[PATCH] can: ems_usb: validate received CAN message payloads
From: Guangshuo Li
Date: Wed Jul 08 2026 - 09:03:47 EST
ems_usb_read_bulk_callback() validates that the fixed CPC message header
fits in the received USB buffer before dispatching the message to a
handler.
That is not enough for messages with payloads. The CAN frame handler
reads the CAN id, DLC and data bytes from the variable payload area. A
malformed device can place a CPC message header at the end of the
received buffer so that the fixed header check succeeds, but the CAN
payload read by ems_usb_rx_can_msg() extends past the actual USB data.
The post-dispatch length check is too late because the handler has
already read the payload by then. Also, the number of CAN data bytes read
by ems_usb_rx_can_msg() is derived from the CAN DLC field, so it must be
validated against the received CPC payload length as well.
Validate the complete CPC payload before dispatching the message, and
make sure CAN frame messages contain the bytes required by their DLC.
Fixes: 702171adeed3 ("ems_usb: Added support for EMS CPC-USB/ARM7 CAN/USB interface")
Signed-off-by: Guangshuo Li <lgs201920130244@xxxxxxxxx>
---
drivers/net/can/usb/ems_usb.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 9b25dda7c183..f72e36fdf788 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -409,6 +409,28 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
netif_rx(skb);
}
+static bool ems_usb_msg_valid(struct ems_cpc_msg *msg)
+{
+ u8 can_len;
+
+ switch (msg->type) {
+ case CPC_MSG_TYPE_CAN_FRAME:
+ case CPC_MSG_TYPE_EXT_CAN_FRAME:
+ if (msg->length < CPC_CAN_MSG_MIN_SIZE)
+ return false;
+
+ can_len = can_cc_dlc2len(msg->msg.can_msg.length & 0xf);
+ return msg->length >= CPC_CAN_MSG_MIN_SIZE + can_len;
+
+ case CPC_MSG_TYPE_RTR_FRAME:
+ case CPC_MSG_TYPE_EXT_RTR_FRAME:
+ return msg->length >= CPC_CAN_MSG_MIN_SIZE;
+
+ default:
+ return true;
+ }
+}
+
/*
* callback for bulk IN urb
*/
@@ -452,6 +474,16 @@ static void ems_usb_read_bulk_callback(struct urb *urb)
msg = (struct ems_cpc_msg *)&ibuf[start];
+ if (msg->length > urb->actual_length - start -
+ CPC_MSG_HEADER_LEN) {
+ netdev_err(netdev, "format error\n");
+ break;
+ }
+ if (!ems_usb_msg_valid(msg)) {
+ netdev_err(netdev, "format error\n");
+ break;
+ }
+
switch (msg->type) {
case CPC_MSG_TYPE_CAN_STATE:
/* Process CAN state changes */
--
2.43.0