summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter Marko <peter.marko@siemens.com>2025-03-06 19:35:51 +0100
committerArmin Kuster <akuster808@gmail.com>2025-03-07 19:40:47 -0500
commit73e6789fdfdd31a8b512aedb59dfe9cfd5b40342 (patch)
treef0088c38b72ce61f34e0a5251635900d287f0c65
parent454cc113175e42d803fe09d5a6c495c369b5a68a (diff)
downloadmeta-openembedded-73e6789fdfdd31a8b512aedb59dfe9cfd5b40342.tar.gz
libmodbus: patch CVE-2024-10918
Pick commit mentioning the bug and two follow-up commits mentioning the first commit as well as commit to adapt tests for these. Tested by running the test-suite. Signed-off-by: Peter Marko <peter.marko@siemens.com> Signed-off-by: Armin Kuster <akuster808@gmail.com>
-rw-r--r--meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-01.patch177
-rw-r--r--meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-02.patch121
-rw-r--r--meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-03.patch84
-rw-r--r--meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-04.patch239
-rw-r--r--meta-oe/recipes-extended/libmodbus/libmodbus_3.1.10.bb8
5 files changed, 628 insertions, 1 deletions
diff --git a/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-01.patch b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-01.patch
new file mode 100644
index 0000000000..f50bee68e8
--- /dev/null
+++ b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-01.patch
@@ -0,0 +1,177 @@
1From df79a02feb253c0a9a009bcdbb21e47581315111 Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?St=C3=A9phane=20Raimbault?= <stephane.raimbault@gmail.com>
3Date: Fri, 18 Oct 2024 10:47:14 +0200
4Subject: [PATCH] Check length passed to modbus_reply (write_bit)
5
6The modbus_reply function is designed to receive arguments
7from modbus_receive. This patch avoid a wrong use of memcpy if
8the user chooses to inject a bad length argument.
9
10Thank you Nozomi Networks Labs Advisory for the report.
11
12CVE: CVE-2024-10918
13Upstream-Status: Backport [https://github.com/stephane/libmodbus/commit/df79a02feb253c0a9a009bcdbb21e47581315111]
14Signed-off-by: Peter Marko <peter.marko@siemens.com>
15---
16 src/modbus.c | 54 +++++++++++++++++++++++++---------------
17 tests/unit-test-client.c | 9 +++++--
18 tests/unit-test-server.c | 16 +++++++++---
19 tests/unit-test.h.in | 1 +
20 4 files changed, 55 insertions(+), 25 deletions(-)
21
22diff --git a/src/modbus.c b/src/modbus.c
23index 5a9b867..33086ec 100644
24--- a/src/modbus.c
25+++ b/src/modbus.c
26@@ -897,24 +897,37 @@ int modbus_reply(modbus_t *ctx,
27 FALSE,
28 "Illegal data address 0x%0X in write_bit\n",
29 address);
30+ break;
31+ }
32+
33+ /* This check is only done here to ensure using memcpy is safe. */
34+ rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req);
35+ if (rsp_length != req_length) {
36+ /* Bad use of modbus_reply */
37+ rsp_length = response_exception(ctx,
38+ &sft,
39+ MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
40+ rsp,
41+ FALSE,
42+ "Invalid request length (%d)\n",
43+ req_length);
44+ break;
45+ }
46+
47+ int data = (req[offset + 3] << 8) + req[offset + 4];
48+ if (data == 0xFF00 || data == 0x0) {
49+ mb_mapping->tab_bits[mapping_address] = data ? ON : OFF;
50+ memcpy(rsp, req, rsp_length);
51 } else {
52- int data = (req[offset + 3] << 8) + req[offset + 4];
53-
54- if (data == 0xFF00 || data == 0x0) {
55- mb_mapping->tab_bits[mapping_address] = data ? ON : OFF;
56- memcpy(rsp, req, req_length);
57- rsp_length = req_length;
58- } else {
59- rsp_length = response_exception(
60- ctx,
61- &sft,
62- MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
63- rsp,
64- FALSE,
65- "Illegal data value 0x%0X in write_bit request at address %0X\n",
66- data,
67- address);
68- }
69+ rsp_length = response_exception(
70+ ctx,
71+ &sft,
72+ MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
73+ rsp,
74+ FALSE,
75+ "Illegal data value 0x%0X in write_bit request at address %0X\n",
76+ data,
77+ address);
78 }
79 } break;
80 case MODBUS_FC_WRITE_SINGLE_REGISTER: {
81@@ -1127,8 +1140,8 @@ int modbus_reply(modbus_t *ctx,
82 break;
83 }
84
85- /* Suppress any responses in RTU when the request was a broadcast, excepted when quirk
86- * is enabled. */
87+ /* Suppress any responses in RTU when the request was a broadcast, excepted when
88+ * quirk is enabled. */
89 if (ctx->backend->backend_type == _MODBUS_BACKEND_TYPE_RTU &&
90 slave == MODBUS_BROADCAST_ADDRESS &&
91 !(ctx->quirks & MODBUS_QUIRK_REPLY_TO_BROADCAST)) {
92@@ -1821,7 +1834,8 @@ int modbus_set_byte_timeout(modbus_t *ctx, uint32_t to_sec, uint32_t to_usec)
93 return 0;
94 }
95
96-/* Get the timeout interval used by the server to wait for an indication from a client */
97+/* Get the timeout interval used by the server to wait for an indication from a client
98+ */
99 int modbus_get_indication_timeout(modbus_t *ctx, uint32_t *to_sec, uint32_t *to_usec)
100 {
101 if (ctx == NULL) {
102diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c
103index a441766..50859f8 100644
104--- a/tests/unit-test-client.c
105+++ b/tests/unit-test-client.c
106@@ -400,11 +400,11 @@ int main(int argc, char *argv[])
107 ASSERT_TRUE(rc == -1 && errno == EMBXILADD, "");
108
109 rc = modbus_write_bits(ctx, 0, 1, tab_rp_bits);
110- printf("* modbus_write_coils (0): ");
111+ printf("* modbus_write_bits (0): ");
112 ASSERT_TRUE(rc == -1 && errno == EMBXILADD, "");
113
114 rc = modbus_write_bits(ctx, UT_BITS_ADDRESS + UT_BITS_NB, UT_BITS_NB, tab_rp_bits);
115- printf("* modbus_write_coils (max): ");
116+ printf("* modbus_write_bits (max): ");
117 ASSERT_TRUE(rc == -1 && errno == EMBXILADD, "");
118
119 rc = modbus_write_register(ctx, 0, tab_rp_registers[0]);
120@@ -500,6 +500,11 @@ int main(int argc, char *argv[])
121 rc = modbus_set_slave(ctx, old_slave);
122 ASSERT_TRUE(rc == 0, "Uanble to restore slave value")
123
124+ /** BAD USE OF REPLY FUNCTION **/
125+ rc = modbus_write_bit(ctx, UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH, ON);
126+ printf("* modbus_write_bit (triggers invalid reply): ");
127+ ASSERT_TRUE(rc == -1 && errno == EMBXILVAL, "");
128+
129 /** SLAVE REPLY **/
130
131 printf("\nTEST SLAVE REPLY:\n");
132diff --git a/tests/unit-test-server.c b/tests/unit-test-server.c
133index 561d64d..8e28124 100644
134--- a/tests/unit-test-server.c
135+++ b/tests/unit-test-server.c
136@@ -150,9 +150,8 @@ int main(int argc, char *argv[])
137 break;
138 }
139
140- /* Special server behavior to test client */
141- if (query[header_length] == 0x03) {
142- /* Read holding registers */
143+ /** Special server behavior to test client **/
144+ if (query[header_length] == MODBUS_FC_READ_HOLDING_REGISTERS) {
145
146 if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 3) ==
147 UT_REGISTERS_NB_SPECIAL) {
148@@ -204,6 +203,17 @@ int main(int argc, char *argv[])
149 }
150 continue;
151 }
152+
153+ } else if (query[header_length] == MODBUS_FC_WRITE_SINGLE_COIL) {
154+ if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
155+ UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH) {
156+ // The valid length is lengths of header + checkum + FC + address + value
157+ // (max 12)
158+ rc = 34;
159+ printf("Special modbus_write_bit detected. Inject a wrong rc value (%d) "
160+ "in modbus_reply\n",
161+ rc);
162+ }
163 }
164
165 rc = modbus_reply(ctx, query, rc, mb_mapping);
166diff --git a/tests/unit-test.h.in b/tests/unit-test.h.in
167index 5e379bb..21d09e3 100644
168--- a/tests/unit-test.h.in
169+++ b/tests/unit-test.h.in
170@@ -30,6 +30,7 @@
171 const uint16_t UT_BITS_ADDRESS = 0x130;
172 const uint16_t UT_BITS_NB = 0x25;
173 const uint8_t UT_BITS_TAB[] = { 0xCD, 0x6B, 0xB2, 0x0E, 0x1B };
174+const uint16_t UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH = UT_BITS_ADDRESS + 2;
175
176 const uint16_t UT_INPUT_BITS_ADDRESS = 0x1C4;
177 const uint16_t UT_INPUT_BITS_NB = 0x16;
diff --git a/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-02.patch b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-02.patch
new file mode 100644
index 0000000000..16b9ba72c5
--- /dev/null
+++ b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-02.patch
@@ -0,0 +1,121 @@
1From d8a971e04d52be16bf405b51d934a30b8aa3f2c3 Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?St=C3=A9phane=20Raimbault?= <stephane.raimbault@gmail.com>
3Date: Sun, 20 Oct 2024 18:02:22 +0200
4Subject: [PATCH] Check length passed to modbus_reply (write_register)
5
6Related to df79a02feb253c.
7
8CVE: CVE-2024-10918
9Upstream-Status: Backport [https://github.com/stephane/libmodbus/commit/d8a971e04d52be16bf405b51d934a30b8aa3f2c3]
10Signed-off-by: Peter Marko <peter.marko@siemens.com>
11---
12 src/modbus.c | 38 ++++++++++++++++++++++++++------------
13 tests/unit-test-client.c | 6 +++++-
14 tests/unit-test-server.c | 13 +++++++++++--
15 3 files changed, 42 insertions(+), 15 deletions(-)
16
17diff --git a/src/modbus.c b/src/modbus.c
18index 33086ec..fe192a7 100644
19--- a/src/modbus.c
20+++ b/src/modbus.c
21@@ -904,13 +904,14 @@ int modbus_reply(modbus_t *ctx,
22 rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req);
23 if (rsp_length != req_length) {
24 /* Bad use of modbus_reply */
25- rsp_length = response_exception(ctx,
26- &sft,
27- MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
28- rsp,
29- FALSE,
30- "Invalid request length (%d)\n",
31- req_length);
32+ rsp_length =
33+ response_exception(ctx,
34+ &sft,
35+ MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
36+ rsp,
37+ FALSE,
38+ "Invalid request length used in modbus_reply (%d)\n",
39+ req_length);
40 break;
41 }
42
43@@ -942,13 +943,26 @@ int modbus_reply(modbus_t *ctx,
44 FALSE,
45 "Illegal data address 0x%0X in write_register\n",
46 address);
47- } else {
48- int data = (req[offset + 3] << 8) + req[offset + 4];
49+ break;
50+ }
51
52- mb_mapping->tab_registers[mapping_address] = data;
53- memcpy(rsp, req, req_length);
54- rsp_length = req_length;
55+ rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req);
56+ if (rsp_length != req_length) {
57+ /* Bad use of modbus_reply */
58+ rsp_length =
59+ response_exception(ctx,
60+ &sft,
61+ MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
62+ rsp,
63+ FALSE,
64+ "Invalid request length used in modbus_reply (%d)\n",
65+ req_length);
66+ break;
67 }
68+ int data = (req[offset + 3] << 8) + req[offset + 4];
69+
70+ mb_mapping->tab_registers[mapping_address] = data;
71+ memcpy(rsp, req, rsp_length);
72 } break;
73 case MODBUS_FC_WRITE_MULTIPLE_COILS: {
74 int nb = (req[offset + 3] << 8) + req[offset + 4];
75diff --git a/tests/unit-test-client.c b/tests/unit-test-client.c
76index 50859f8..84d5840 100644
77--- a/tests/unit-test-client.c
78+++ b/tests/unit-test-client.c
79@@ -498,13 +498,17 @@ int main(int argc, char *argv[])
80
81 modbus_disable_quirks(ctx, MODBUS_QUIRK_MAX_SLAVE);
82 rc = modbus_set_slave(ctx, old_slave);
83- ASSERT_TRUE(rc == 0, "Uanble to restore slave value")
84+ ASSERT_TRUE(rc == 0, "Unable to restore slave value")
85
86 /** BAD USE OF REPLY FUNCTION **/
87 rc = modbus_write_bit(ctx, UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH, ON);
88 printf("* modbus_write_bit (triggers invalid reply): ");
89 ASSERT_TRUE(rc == -1 && errno == EMBXILVAL, "");
90
91+ rc = modbus_write_register(ctx, UT_REGISTERS_ADDRESS_SPECIAL, 0x42);
92+ printf("* modbus_write_register (triggers invalid reply): ");
93+ ASSERT_TRUE(rc == -1 && errno == EMBXILVAL, "");
94+
95 /** SLAVE REPLY **/
96
97 printf("\nTEST SLAVE REPLY:\n");
98diff --git a/tests/unit-test-server.c b/tests/unit-test-server.c
99index 8e28124..fc7ceb3 100644
100--- a/tests/unit-test-server.c
101+++ b/tests/unit-test-server.c
102@@ -210,8 +210,17 @@ int main(int argc, char *argv[])
103 // The valid length is lengths of header + checkum + FC + address + value
104 // (max 12)
105 rc = 34;
106- printf("Special modbus_write_bit detected. Inject a wrong rc value (%d) "
107- "in modbus_reply\n",
108+ printf(
109+ "Special modbus_write_bit detected. Inject a wrong length value (%d) "
110+ "in modbus_reply\n",
111+ rc);
112+ }
113+ } else if (query[header_length] == MODBUS_FC_WRITE_SINGLE_REGISTER) {
114+ if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
115+ UT_REGISTERS_ADDRESS_SPECIAL) {
116+ rc = 45;
117+ printf("Special modbus_write_register detected. Inject a wrong length "
118+ "value (%d) in modbus_reply\n",
119 rc);
120 }
121 }
diff --git a/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-03.patch b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-03.patch
new file mode 100644
index 0000000000..6ae9305b33
--- /dev/null
+++ b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-03.patch
@@ -0,0 +1,84 @@
1From 7ea85f1b41f7066849f4bde7c0a3549b1e087bbf Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?St=C3=A9phane=20Raimbault?= <stephane.raimbault@gmail.com>
3Date: Sun, 20 Oct 2024 18:23:26 +0200
4Subject: [PATCH] Small cleanups of unit test server
5
6CVE: CVE-2024-10918
7Upstream-Status: Backport [https://github.com/stephane/libmodbus/commit/7ea85f1b41f7066849f4bde7c0a3549b1e087bbf]
8Signed-off-by: Peter Marko <peter.marko@siemens.com>
9---
10 tests/unit-test-server.c | 29 ++++++++++++-----------------
11 1 file changed, 12 insertions(+), 17 deletions(-)
12
13diff --git a/tests/unit-test-server.c b/tests/unit-test-server.c
14index fc7ceb3..bb25ba4 100644
15--- a/tests/unit-test-server.c
16+++ b/tests/unit-test-server.c
17@@ -150,21 +150,21 @@ int main(int argc, char *argv[])
18 break;
19 }
20
21+ uint8_t function = query[header_length];
22+ uint16_t address = MODBUS_GET_INT16_FROM_INT8(query, header_length + 1);
23+
24 /** Special server behavior to test client **/
25- if (query[header_length] == MODBUS_FC_READ_HOLDING_REGISTERS) {
26-
27+ if (function == MODBUS_FC_READ_HOLDING_REGISTERS) {
28 if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 3) ==
29 UT_REGISTERS_NB_SPECIAL) {
30 printf("Set an incorrect number of values\n");
31 MODBUS_SET_INT16_TO_INT8(
32 query, header_length + 3, UT_REGISTERS_NB_SPECIAL - 1);
33- } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
34- UT_REGISTERS_ADDRESS_SPECIAL) {
35+ } else if (address == UT_REGISTERS_ADDRESS_SPECIAL) {
36 printf("Reply to this special register address by an exception\n");
37 modbus_reply_exception(ctx, query, MODBUS_EXCEPTION_SLAVE_OR_SERVER_BUSY);
38 continue;
39- } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
40- UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE) {
41+ } else if (address == UT_REGISTERS_ADDRESS_INVALID_TID_OR_SLAVE) {
42 const int RAW_REQ_LENGTH = 5;
43 uint8_t raw_req[] = {(use_backend == RTU) ? INVALID_SERVER_ID : 0xFF,
44 0x03,
45@@ -175,12 +175,10 @@ int main(int argc, char *argv[])
46 printf("Reply with an invalid TID or slave\n");
47 modbus_send_raw_request(ctx, raw_req, RAW_REQ_LENGTH * sizeof(uint8_t));
48 continue;
49- } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
50- UT_REGISTERS_ADDRESS_SLEEP_500_MS) {
51+ } else if (address == UT_REGISTERS_ADDRESS_SLEEP_500_MS) {
52 printf("Sleep 0.5 s before replying\n");
53 usleep(500000);
54- } else if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
55- UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS) {
56+ } else if (address == UT_REGISTERS_ADDRESS_BYTE_SLEEP_5_MS) {
57 /* Test low level only available in TCP mode */
58 /* Catch the reply and send reply byte a byte */
59 uint8_t req[] = "\x00\x1C\x00\x00\x00\x05\xFF\x03\x02\x00\x00";
60@@ -203,10 +201,8 @@ int main(int argc, char *argv[])
61 }
62 continue;
63 }
64-
65- } else if (query[header_length] == MODBUS_FC_WRITE_SINGLE_COIL) {
66- if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
67- UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH) {
68+ } else if (function == MODBUS_FC_WRITE_SINGLE_COIL) {
69+ if (address == UT_BITS_ADDRESS_INVALID_REQUEST_LENGTH) {
70 // The valid length is lengths of header + checkum + FC + address + value
71 // (max 12)
72 rc = 34;
73@@ -215,9 +211,8 @@ int main(int argc, char *argv[])
74 "in modbus_reply\n",
75 rc);
76 }
77- } else if (query[header_length] == MODBUS_FC_WRITE_SINGLE_REGISTER) {
78- if (MODBUS_GET_INT16_FROM_INT8(query, header_length + 1) ==
79- UT_REGISTERS_ADDRESS_SPECIAL) {
80+ } else if (function == MODBUS_FC_WRITE_SINGLE_REGISTER) {
81+ if (address == UT_REGISTERS_ADDRESS_SPECIAL) {
82 rc = 45;
83 printf("Special modbus_write_register detected. Inject a wrong length "
84 "value (%d) in modbus_reply\n",
diff --git a/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-04.patch b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-04.patch
new file mode 100644
index 0000000000..4538054193
--- /dev/null
+++ b/meta-oe/recipes-extended/libmodbus/libmodbus/CVE-2024-10918-04.patch
@@ -0,0 +1,239 @@
1From 81bf713cf029bfa5b5da87b945c1e8817b4398f9 Mon Sep 17 00:00:00 2001
2From: =?UTF-8?q?St=C3=A9phane=20Raimbault?= <stephane.raimbault@gmail.com>
3Date: Mon, 21 Oct 2024 17:32:39 +0200
4Subject: [PATCH] Fix request length check in modbus_reply in RTU
5
6- rename internal *_prepare_response_tid to *_get_response_tid
7- change signature, don't need req length anymore
8- remove misleading modification of req_length
9- check of req length before use in memcpy for mask write register
10
11Related to df79a02feb253c0a9a009bcdbb21e47581315111
12
13CVE: CVE-2024-10918
14Upstream-Status: Backport [https://github.com/stephane/libmodbus/commit/81bf713cf029bfa5b5da87b945c1e8817b4398f9]
15Signed-off-by: Peter Marko <peter.marko@siemens.com>
16---
17 src/modbus-private.h | 2 +-
18 src/modbus-rtu.c | 5 ++--
19 src/modbus-tcp.c | 6 ++--
20 src/modbus.c | 71 ++++++++++++++++++++++++++++----------------
21 4 files changed, 52 insertions(+), 32 deletions(-)
22
23diff --git a/src/modbus-private.h b/src/modbus-private.h
24index 6cd3424..ea83187 100644
25--- a/src/modbus-private.h
26+++ b/src/modbus-private.h
27@@ -75,7 +75,7 @@ typedef struct _modbus_backend {
28 int (*build_request_basis)(
29 modbus_t *ctx, int function, int addr, int nb, uint8_t *req);
30 int (*build_response_basis)(sft_t *sft, uint8_t *rsp);
31- int (*prepare_response_tid)(const uint8_t *req, int *req_length);
32+ int (*get_response_tid)(const uint8_t *req);
33 int (*send_msg_pre)(uint8_t *req, int req_length);
34 ssize_t (*send)(modbus_t *ctx, const uint8_t *req, int req_length);
35 int (*receive)(modbus_t *ctx, uint8_t *req);
36diff --git a/src/modbus-rtu.c b/src/modbus-rtu.c
37index b774923..8b5ee08 100644
38--- a/src/modbus-rtu.c
39+++ b/src/modbus-rtu.c
40@@ -129,9 +129,8 @@ static uint16_t crc16(uint8_t *buffer, uint16_t buffer_length)
41 return (crc_hi << 8 | crc_lo);
42 }
43
44-static int _modbus_rtu_prepare_response_tid(const uint8_t *req, int *req_length)
45+static int _modbus_rtu_get_response_tid(const uint8_t *req)
46 {
47- (*req_length) -= _MODBUS_RTU_CHECKSUM_LENGTH;
48 /* No TID */
49 return 0;
50 }
51@@ -1187,7 +1186,7 @@ const modbus_backend_t _modbus_rtu_backend = {
52 _modbus_set_slave,
53 _modbus_rtu_build_request_basis,
54 _modbus_rtu_build_response_basis,
55- _modbus_rtu_prepare_response_tid,
56+ _modbus_rtu_get_response_tid,
57 _modbus_rtu_send_msg_pre,
58 _modbus_rtu_send,
59 _modbus_rtu_receive,
60diff --git a/src/modbus-tcp.c b/src/modbus-tcp.c
61index 733a4a9..60ac6b4 100644
62--- a/src/modbus-tcp.c
63+++ b/src/modbus-tcp.c
64@@ -151,7 +151,7 @@ static int _modbus_tcp_build_response_basis(sft_t *sft, uint8_t *rsp)
65 return _MODBUS_TCP_PRESET_RSP_LENGTH;
66 }
67
68-static int _modbus_tcp_prepare_response_tid(const uint8_t *req, int *req_length)
69+static int _modbus_tcp_get_response_tid(const uint8_t *req)
70 {
71 return (req[0] << 8) + req[1];
72 }
73@@ -812,7 +812,7 @@ const modbus_backend_t _modbus_tcp_backend = {
74 _modbus_set_slave,
75 _modbus_tcp_build_request_basis,
76 _modbus_tcp_build_response_basis,
77- _modbus_tcp_prepare_response_tid,
78+ _modbus_tcp_get_response_tid,
79 _modbus_tcp_send_msg_pre,
80 _modbus_tcp_send,
81 _modbus_tcp_receive,
82@@ -835,7 +835,7 @@ const modbus_backend_t _modbus_tcp_pi_backend = {
83 _modbus_set_slave,
84 _modbus_tcp_build_request_basis,
85 _modbus_tcp_build_response_basis,
86- _modbus_tcp_prepare_response_tid,
87+ _modbus_tcp_get_response_tid,
88 _modbus_tcp_send_msg_pre,
89 _modbus_tcp_send,
90 _modbus_tcp_receive,
91diff --git a/src/modbus.c b/src/modbus.c
92index fe192a7..e3737bb 100644
93--- a/src/modbus.c
94+++ b/src/modbus.c
95@@ -125,7 +125,7 @@ int modbus_flush(modbus_t *ctx)
96 return rc;
97 }
98
99-/* Computes the length of the expected response */
100+/* Computes the length of the expected response including checksum */
101 static unsigned int compute_response_length_from_request(modbus_t *ctx, uint8_t *req)
102 {
103 int length;
104@@ -386,8 +386,7 @@ int _modbus_receive_msg(modbus_t *ctx, uint8_t *msg, msg_type_t msg_type)
105 length_to_read = ctx->backend->header_length + 1;
106
107 if (msg_type == MSG_INDICATION) {
108- /* Wait for a message, we don't know when the message will be
109- * received */
110+ /* Wait for a message, we don't know when the message will be received */
111 if (ctx->indication_timeout.tv_sec == 0 && ctx->indication_timeout.tv_usec == 0) {
112 /* By default, the indication timeout isn't set */
113 p_tv = NULL;
114@@ -799,7 +798,7 @@ int modbus_reply(modbus_t *ctx,
115
116 sft.slave = slave;
117 sft.function = function;
118- sft.t_id = ctx->backend->prepare_response_tid(req, &req_length);
119+ sft.t_id = ctx->backend->get_response_tid(req);
120
121 /* Data are flushed on illegal number of values errors. */
122 switch (function) {
123@@ -895,7 +894,7 @@ int modbus_reply(modbus_t *ctx,
124 MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS,
125 rsp,
126 FALSE,
127- "Illegal data address 0x%0X in write_bit\n",
128+ "Illegal data address 0x%0X in write bit\n",
129 address);
130 break;
131 }
132@@ -904,20 +903,26 @@ int modbus_reply(modbus_t *ctx,
133 rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req);
134 if (rsp_length != req_length) {
135 /* Bad use of modbus_reply */
136- rsp_length =
137- response_exception(ctx,
138- &sft,
139- MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
140- rsp,
141- FALSE,
142- "Invalid request length used in modbus_reply (%d)\n",
143- req_length);
144+ rsp_length = response_exception(
145+ ctx,
146+ &sft,
147+ MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
148+ rsp,
149+ FALSE,
150+ "Invalid request length in modbus_reply to write bit (%d)\n",
151+ req_length);
152 break;
153 }
154
155+ /* Don't copy the CRC, if any, it will be computed later (even if identical to the
156+ * request) */
157+ rsp_length -= ctx->backend->checksum_length;
158+
159 int data = (req[offset + 3] << 8) + req[offset + 4];
160 if (data == 0xFF00 || data == 0x0) {
161+ /* Apply the change to mapping */
162 mb_mapping->tab_bits[mapping_address] = data ? ON : OFF;
163+ /* Prepare response */
164 memcpy(rsp, req, rsp_length);
165 } else {
166 rsp_length = response_exception(
167@@ -949,19 +954,21 @@ int modbus_reply(modbus_t *ctx,
168 rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req);
169 if (rsp_length != req_length) {
170 /* Bad use of modbus_reply */
171- rsp_length =
172- response_exception(ctx,
173- &sft,
174- MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
175- rsp,
176- FALSE,
177- "Invalid request length used in modbus_reply (%d)\n",
178- req_length);
179+ rsp_length = response_exception(
180+ ctx,
181+ &sft,
182+ MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
183+ rsp,
184+ FALSE,
185+ "Invalid request length in modbus_reply to write register (%d)\n",
186+ req_length);
187 break;
188 }
189 int data = (req[offset + 3] << 8) + req[offset + 4];
190
191 mb_mapping->tab_registers[mapping_address] = data;
192+
193+ rsp_length -= ctx->backend->checksum_length;
194 memcpy(rsp, req, rsp_length);
195 } break;
196 case MODBUS_FC_WRITE_MULTIPLE_COILS: {
197@@ -1082,8 +1089,23 @@ int modbus_reply(modbus_t *ctx,
198
199 data = (data & and) | (or &(~and));
200 mb_mapping->tab_registers[mapping_address] = data;
201- memcpy(rsp, req, req_length);
202- rsp_length = req_length;
203+
204+ rsp_length = compute_response_length_from_request(ctx, (uint8_t *) req);
205+ if (rsp_length != req_length) {
206+ /* Bad use of modbus_reply */
207+ rsp_length = response_exception(ctx,
208+ &sft,
209+ MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE,
210+ rsp,
211+ FALSE,
212+ "Invalid request length in modbus_reply "
213+ "to mask write register (%d)\n",
214+ req_length);
215+ break;
216+ }
217+
218+ rsp_length -= ctx->backend->checksum_length;
219+ memcpy(rsp, req, rsp_length);
220 }
221 } break;
222 case MODBUS_FC_WRITE_AND_READ_REGISTERS: {
223@@ -1171,7 +1193,6 @@ int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, unsigned int excep
224 int function;
225 uint8_t rsp[MAX_MESSAGE_LENGTH];
226 int rsp_length;
227- int dummy_length = 99;
228 sft_t sft;
229
230 if (ctx == NULL) {
231@@ -1185,7 +1206,7 @@ int modbus_reply_exception(modbus_t *ctx, const uint8_t *req, unsigned int excep
232
233 sft.slave = slave;
234 sft.function = function + 0x80;
235- sft.t_id = ctx->backend->prepare_response_tid(req, &dummy_length);
236+ sft.t_id = ctx->backend->get_response_tid(req);
237 rsp_length = ctx->backend->build_response_basis(&sft, rsp);
238
239 /* Positive exception code */
diff --git a/meta-oe/recipes-extended/libmodbus/libmodbus_3.1.10.bb b/meta-oe/recipes-extended/libmodbus/libmodbus_3.1.10.bb
index 9e17f91669..c8e1c3a3e2 100644
--- a/meta-oe/recipes-extended/libmodbus/libmodbus_3.1.10.bb
+++ b/meta-oe/recipes-extended/libmodbus/libmodbus_3.1.10.bb
@@ -6,7 +6,13 @@ SECTION = "libs"
6LICENSE = "LGPL-2.1-or-later" 6LICENSE = "LGPL-2.1-or-later"
7LIC_FILES_CHKSUM = "file://COPYING.LESSER;md5=4fbd65380cdd255951079008b364516c" 7LIC_FILES_CHKSUM = "file://COPYING.LESSER;md5=4fbd65380cdd255951079008b364516c"
8 8
9SRC_URI = "git://github.com/stephane/libmodbus;branch=master;protocol=https" 9SRC_URI = " \
10 git://github.com/stephane/libmodbus;branch=master;protocol=https \
11 file://CVE-2024-10918-01.patch \
12 file://CVE-2024-10918-02.patch \
13 file://CVE-2024-10918-03.patch \
14 file://CVE-2024-10918-04.patch \
15"
10SRCREV = "2cbafa3113e276c3697d297f68e88d112b53174d" 16SRCREV = "2cbafa3113e276c3697d297f68e88d112b53174d"
11 17
12S = "${WORKDIR}/git" 18S = "${WORKDIR}/git"