Skip to content

Commit 9e2a5c9

Browse files
committed
modbus: Fix buffer overrun in RTU RX handler
It's possible for uart_buf_ctr to decrement after checking it due to TX interrupts. This can cause the unsigned packet length to overflow when subtracted by 4, which makes memcpy and crc16_ansi overflow the UART buffer. The counter is just loaded into a local variable to prevent further modification. Partially fixes #91088
1 parent 1380739 commit 9e2a5c9

File tree

1 file changed

+6
-5
lines changed

1 file changed

+6
-5
lines changed

subsys/modbus/modbus_serial.c

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -287,10 +287,11 @@ static int modbus_rtu_rx_adu(struct modbus_context *ctx)
287287
uint16_t calc_crc;
288288
uint16_t crc_idx;
289289
uint8_t *data_ptr;
290+
uint16_t buf_ctr = cfg->uart_buf_ctr;
290291

291292
/* Is the message long enough? */
292-
if ((cfg->uart_buf_ctr < MODBUS_RTU_MIN_MSG_SIZE) ||
293-
(cfg->uart_buf_ctr > CONFIG_MODBUS_BUFFER_SIZE)) {
293+
if ((buf_ctr < MODBUS_RTU_MIN_MSG_SIZE) ||
294+
(buf_ctr > CONFIG_MODBUS_BUFFER_SIZE)) {
294295
LOG_WRN("Frame length error");
295296
return -EMSGSIZE;
296297
}
@@ -299,16 +300,16 @@ static int modbus_rtu_rx_adu(struct modbus_context *ctx)
299300
ctx->rx_adu.fc = cfg->uart_buf[1];
300301
data_ptr = &cfg->uart_buf[2];
301302
/* Payload length without node address, function code, and CRC */
302-
ctx->rx_adu.length = cfg->uart_buf_ctr - 4;
303+
ctx->rx_adu.length = buf_ctr - 4;
303304
/* CRC index */
304-
crc_idx = cfg->uart_buf_ctr - sizeof(uint16_t);
305+
crc_idx = buf_ctr - sizeof(uint16_t);
305306

306307
memcpy(ctx->rx_adu.data, data_ptr, ctx->rx_adu.length);
307308

308309
ctx->rx_adu.crc = sys_get_le16(&cfg->uart_buf[crc_idx]);
309310
/* Calculate CRC over address, function code, and payload */
310311
calc_crc = crc16_ansi(&cfg->uart_buf[0],
311-
cfg->uart_buf_ctr - sizeof(ctx->rx_adu.crc));
312+
buf_ctr - sizeof(ctx->rx_adu.crc));
312313

313314
if (ctx->rx_adu.crc != calc_crc) {
314315
LOG_WRN("Calculated CRC does not match received CRC");

0 commit comments

Comments
 (0)