-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
RT-Thread Version
master (verified on commit 6a635e32d9f39ea015824927cee492620a05212f)
Hardware Type/Architectures
Any BSP enabling CherryUSB device ADB support
Develop Toolchain
GCC
Describe the bug
Affected Component
| Field | Detail |
|---|---|
| File | components/drivers/usb/cherryusb/class/adb/usbd_adb.c |
| Path | USB Device ADB receive path |
Vulnerability Description
A heap-based buffer overflow exists in the CherryUSB ADB device class receive path.
rx_packet.payload is a fixed-size buffer defined as:
#define MAX_PAYLOAD_V1 (4 * 1024)
#define MAX_PAYLOAD_V2 (256 * 1024)
#define MAX_PAYLOAD MAX_PAYLOAD_V1
struct adb_packet {
USB_MEM_ALIGNX struct adb_msg msg;
USB_MEM_ALIGNX uint8_t payload[USB_ALIGN_UP(MAX_PAYLOAD, CONFIG_USB_ALIGN_SIZE)];
};However, the vulnerable receive path schedules the next bulk OUT read without validating that rx_packet.msg.data_length <= MAX_PAYLOAD:
if (adb_client.common_state == ADB_STATE_READ_MSG) {
if (nbytes != sizeof(struct adb_msg)) {
...
return;
}
if (rx_packet.msg.data_length) {
adb_client.common_state = ADB_STATE_READ_DATA;
usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr,
rx_packet.payload, rx_packet.msg.data_length); // ← no bounds check
}
}Additionally, the code performs an unconditional null-terminator write:
rx_packet.payload[rx_packet.msg.data_length] = '\0';This introduces two distinct issues:
- If
data_length > MAX_PAYLOAD— the host can trigger an out-of-bounds write into the fixed payload buffer. - If
data_length == MAX_PAYLOAD— the null-terminator write is already one byte out of bounds (off-by-one).
Trigger Condition
This path is automatically reachable once the RT-Thread USB device is configured:
case USBD_EVENT_CONFIGURED:
adb_client.common_state = ADB_STATE_READ_MSG;
usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr,
(uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
break;After enumeration and configuration, a malicious USB host can send a crafted ADB message header and trigger the bug without any further local action on the RT-Thread side.
Note: Before scheduling the oversized payload read, the code does not validate
magicordata_crc32. The only check in the first stage is that the received header length equalssizeof(struct adb_msg).
Proof of Concept
A PoC can be implemented with a custom USB host, a libusb-based userspace program, or a USB fuzzing platform.
Expected PoC flow:
- Connect to an RT-Thread target exposing the CherryUSB ADB device class.
- Complete normal USB enumeration until the device enters
USBD_EVENT_CONFIGURED. - Send one bulk OUT transfer containing a 24-byte
adb_msgheader with:- Any valid ADB command value (e.g.
A_OPENorA_WRTE) data_length = MAX_PAYLOAD + 0x100(orMAX_PAYLOADfor the off-by-one case)
- Any valid ADB command value (e.g.
- Send a second bulk OUT transfer containing
data_lengthbytes of payload.
Expected result:
- The device schedules a read into
rx_packet.payloadusing the oversized host-controlled length. - Memory beyond the payload buffer is overwritten.
- Depending on allocator layout and platform, the target may crash, corrupt adjacent state, or behave unpredictably.
Impact Analysis
Upstream
- The vulnerable logic is present in current
master. - The path is automatically reachable in stock upstream once ADB device support is enabled and the device is connected to a USB host.
- This is not a network-remote issue; it requires a malicious directly-connected USB host.
Downstream
- Any downstream RT-Thread product enabling CherryUSB ADB device support is affected if it can be connected to an untrusted USB host.
- Realistic attacker-controlled hosts include hostile PCs, debugging stations, docking stations, or malicious charging/data ports.
- Products that expose ADB over USB for maintenance, shell, file sync, or factory/debug workflows are especially exposed.
Suggested Fix
Validate rx_packet.msg.data_length before calling usbd_ep_start_read():
if (rx_packet.msg.data_length > MAX_PAYLOAD) {
adb_client.common_state = ADB_STATE_READ_MSG;
usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr,
(uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
return;
}Also ensure the null-terminator write is only performed when data_length < MAX_PAYLOAD:
if (rx_packet.msg.data_length < MAX_PAYLOAD) {
rx_packet.payload[rx_packet.msg.data_length] = '\0';
}Please let us know if you intend to request a CVE ID upon confirmation of this vulnerability.
Other additional context
No response