| Titolo | RT-Thread v5.0.2 Out-of-bounds Write |
|---|
| Descrizione | I have already reported this vulnerability in the project's GitHub issue tracker for review by the maintainers. The report is provided below.
# SWM341 CAN receive path trusts raw DLC and writes past fixed receive buffers
## Describe the bug
The SWM341 CAN receive path copies the raw hardware DLC value into fixed 8-byte CAN receive buffers without clamping it to the classic CAN payload size.
The external input boundary is the CAN controller receive frame. When a frame arrives from the CAN bus, the controller exposes attacker-controlled frame metadata and payload through `CANx->FRAME.INFO` and `CANx->FRAME.DATA[]`. The low 4 bits of `CANx->FRAME.INFO` are used as the DLC. That external DLC value flows directly into a loop bound and causes an out-of-bounds write when it is greater than 8.
The concrete data flow is:
```text
external CAN frame
-> CAN controller RX register CANx->FRAME.INFO[DLC]
-> CAN_Receive(): msg->size
-> loop bound for msg->data[i]
-> out-of-bounds write when i == 8 and msg->size > 8
-> swm_can_recvmsg(): pmsg->len
-> loop bound for pmsg->data[i]
-> out-of-bounds write when i == 8 and pmsg->len > 8
```
The RT-Thread CAN message type used when `RT_CAN_USING_CANFD` is not enabled stores only 8 payload bytes:
```text
components/drivers/include/drivers/dev_can.h:510
components/drivers/include/drivers/dev_can.h:526
```
However, the SWM341 low-level receive routine extracts a 4-bit DLC value from the CAN frame information register:
```c
#define CAN_INFO_DLC_Msk (0x0F << CAN_INFO_DLC_Pos)
/* External input: DLC bits from the received CAN frame. */
msg->size = (CANx->FRAME.INFO & CAN_INFO_DLC_Msk) >> CAN_INFO_DLC_Pos;
```
and then uses that value directly as a byte count:
```c
/*
* Overflow trigger:
* msg->data has valid indexes [0..7].
* If the external DLC is 9..15, the iteration with i == 8 writes
* msg->data[8], which is past the end of CAN_RXMessage.data.
*/
for(i = 0; i < msg->size; i++)
{
/* CANx->FRAME.DATA[] is the external CAN payload register. */
msg->data[i] = CANx->FRAME.DATA[i+2];
}
```
`CAN_RXMessage.data` is only 8 bytes:
```c
typedef struct {
uint32_t id;
uint8_t format;
uint8_t remote;
uint8_t size;
uint8_t data[8];
} CAN_RXMessage;
```
The higher-level SWM341 RT-Thread driver then copies the same unchecked length into `struct rt_can_msg.data[8]`:
```c
CAN_RXMessage CAN_RXMsg;
CAN_Receive(can_dev->can_cfg->CANx, &CAN_RXMsg);
/* CAN_RXMsg.size is derived from the external CAN DLC. */
pmsg->len = CAN_RXMsg.size;
/*
* Second overflow point:
* pmsg points to RT-Thread's struct rt_can_msg.
* pmsg->data also has valid indexes [0..7].
* If pmsg->len is still 9..15, i == 8 writes pmsg->data[8].
*/
for(i = 0; i < pmsg->len; i++)
{
pmsg->data[i] = CAN_RXMsg.data[i];
}
```
The interrupt path reaches this driver callback through the generic RT-Thread CAN ISR:
```c
/* Stack object inside rt_hw_can_isr(). */
struct rt_can_msg tmpmsg;
/* swm_can_recvmsg() receives &tmpmsg as pmsg. */
ch = can->ops->recvmsg(can, &tmpmsg, no);
...
rt_memcpy(&listmsg->data, &tmpmsg, sizeof(struct rt_can_msg));
```
So a received classic CAN frame whose raw DLC code is 9..15 can corrupt stack memory in the ISR receive path before the message is copied into the RT-Thread RX FIFO.
Locations:
```text
bsp/synwit/libraries/SWM341_CSL/CMSIS/DeviceSupport/SWM341.h:2268
bsp/synwit/libraries/SWM341_CSL/CMSIS/DeviceSupport/SWM341.h:2269
bsp/synwit/libraries/SWM341_CSL/SWM341_StdPeriph_Driver/SWM341_can.h:85
bsp/synwit/libraries/SWM341_CSL/SWM341_StdPeriph_Driver/SWM341_can.h:89
bsp/synwit/libraries/SWM341_CSL/SWM341_StdPeriph_Driver/SWM341_can.h:90
bsp/synwit/libraries/SWM341_CSL/SWM341_StdPeriph_Driver/SWM341_can.c:240
bsp/synwit/libraries/SWM341_CSL/SWM341_StdPeriph_Driver/SWM341_can.c:246
bsp/synwit/libraries/SWM341_CSL/SWM341_StdPeriph_Driver/SWM341_can.c:248
bsp/synwit/libraries/SWM341_drivers/drv_can.c:413
bsp/synwit/libraries/SWM341_drivers/drv_can.c:416
bsp/synwit/libraries/SWM341_drivers/drv_can.c:438
bsp/synwit/libraries/SWM341_drivers/drv_can.c:440
bsp/synwit/libraries/SWM341_drivers/drv_can.c:442
bsp/synwit/libraries/SWM341_drivers/drv_can.c:453
bsp/synwit/libraries/SWM341_drivers/drv_can.c:466
components/drivers/can/dev_can.c:982
components/drivers/can/dev_can.c:998
components/drivers/can/dev_can.c:1039
components/drivers/include/drivers/dev_can.h:526
```
## Steps to reproduce
I have not reproduced this on physical SWM341 hardware yet. I verified the source-level bug with a standalone reduced check that preserves the relevant register decode and fixed-buffer copy semantics.
The source-level trigger is:
```text
CANx->FRAME.INFO DLC bits = 9..15
RT_CAN_USING_CANFD = not enabled
BSP_USING_CAN = enabled
BSP_USING_CAN0 or CAN1 = enabled
```
Reduced check:
```c
#include <stdint.h>
typedef struct {
uint32_t INFO;
uint8_t DATA[16];
} CAN_Frame;
typedef struct {
CAN_Frame FRAME;
} CAN_TypeDef;
typedef struct {
uint32_t id;
uint8_t format;
uint8_t remote;
uint8_t size;
uint8_t data[8];
} CAN_RXMessage;
#define CAN_INFO_DLC_Pos 0
#define CAN_INFO_DLC_Msk (0x0F << CAN_INFO_DLC_Pos)
void CAN_Receive(CAN_TypeDef *CANx, CAN_RXMessage *msg)
{
uint32_t i;
/* External input: raw DLC from the received CAN frame. */
msg->size = (CANx->FRAME.INFO & CAN_INFO_DLC_Msk) >> CAN_INFO_DLC_Pos;
for (i = 0; i < msg->size; i++) {
/* OOB when can.FRAME.INFO makes msg->size > 8 and i reaches 8. */
msg->data[i] = CANx->FRAME.DATA[i + 2];
}
}
int main(void)
{
CAN_TypeDef can = {0};
CAN_RXMessage msg = {0};
can.FRAME.INFO = 15; /* external DLC value 15 */
CAN_Receive(&can, &msg);
return 0;
}
```
Compile it with AddressSanitizer, for example:
```text
clang -x c -fsanitize=address -O0 -g repro.c -o repro && ./repro
```
Changing the receive path to clamp or reject DLC values above 8 avoids the ASan report.
## Relevant log output
AddressSanitizer reports a stack buffer overflow on the write into `CAN_RXMessage.data`:
```text
ERROR: AddressSanitizer: stack-buffer-overflow
WRITE of size 1
#0 CAN_Receive ... repro.c
#1 main ... repro.c
This frame has 2 object(s):
[..] 'can'
[..] 'msg' <== Memory access overflows this variable
SUMMARY: AddressSanitizer: stack-buffer-overflow in CAN_Receive
```
## Impact
Potential memory corruption from an externally supplied CAN frame on SWM341 boards when the CAN driver is enabled.
The attacker-controlled value is the raw DLC field observed by the CAN controller. If the controller reports DLC values 9..15 to software, the driver first writes beyond the local `CAN_RXMessage.data[8]` buffer and then may also copy beyond `struct rt_can_msg.data[8]` in the RT-Thread receive callback.
This is especially relevant for RTOS deployments because CAN traffic often crosses trust boundaries, and the vulnerable path executes from the interrupt-driven receive flow.
## Environment
```text
Initial RT-Thread commit checked: c39e92f4c1
Checked tree description: v5.0.2-2360-gc39e92f4c1-dirty
Affected driver: bsp/synwit/libraries/SWM341_drivers/drv_can.c
Affected low-level CAN code: bsp/synwit/libraries/SWM341_CSL/SWM341_StdPeriph_Driver/SWM341_can.c
Affected board family: Synwit SWM341
Target hardware: not tested on board yet
Verification: host-side AddressSanitizer semantic check
```
The board configuration exposes this driver when CAN is enabled:
```text
bsp/synwit/swm341-mini/board/Kconfig:115 menuconfig BSP_USING_CAN
bsp/synwit/swm341-mini/board/Kconfig:120 config BSP_USING_CAN0
bsp/synwit/swm341-mini/board/Kconfig:123 config BSP_USING_CAN1
```
The currently checked default `.config` has this board's CAN options disabled:
```text
bsp/synwit/swm341-mini/.config:247 # CONFIG_RT_USING_CAN is not set
bsp/synwit/swm341-mini/.config:1415 # CONFIG_BSP_USING_CAN is not set
```
## Additional context
A fix should validate the DLC before it is used as a copy length. For classic CAN, the code should either reject/drop frames whose raw DLC code is above 8 or clamp the payload length to 8 before copying:
```c
msg->size = (CANx->FRAME.INFO & CAN_INFO_DLC_Msk) >> CAN_INFO_DLC_Pos;
if (msg->size > 8) {
msg->size = 8;
}
```
The same invariant should be preserved in `swm_can_recvmsg()` before writing `pmsg->len` and before copying into `pmsg->data`. |
|---|
| Fonte | ⚠️ https://github.com/RT-Thread/rt-thread/issues/11425 |
|---|
| Utente | Zephyr Saxon (UID 80853) |
|---|
| Sottomissione | 01/06/2026 08:41 (1 mese fa) |
|---|
| Moderazione | 03/07/2026 15:51 (1 month later) |
|---|
| Stato | Accettato |
|---|
| Voce VulDB | 376114 [RT-Thread fino a 5.0.2 SWM341 CAN SWM341.h CAN_Receive buffer overflow] |
|---|
| Punti | 20 |
|---|