]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
can: ems_usb: validate CPC message lengths
authorPengpeng Hou <pengpeng@iscas.ac.cn>
Mon, 6 Jul 2026 09:27:52 +0000 (17:27 +0800)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Wed, 29 Jul 2026 10:00:18 +0000 (12:00 +0200)
ems_usb_read_bulk_callback() walks CPC messages packed in one USB
receive buffer.

Check that each declared message fits in the URB payload. Also require the
type-specific payload to cover the fields used by the CAN, state, error and
overrun handlers.

Signed-off-by: Pengpeng Hou <pengpeng@iscas.ac.cn>
Link: https://patch.msgid.link/20260706092752.79600-1-pengpeng@iscas.ac.cn
Fixes: 702171adeed3 ("ems_usb: Added support for EMS CPC-USB/ARM7 CAN/USB interface")
Cc: stable@vger.kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/usb/ems_usb.c

index 9b25dda7c18382105d160feedd679b7f74489ce9..24cf8f651f8f166531151bd41555e7b4f3d394af 100644 (file)
@@ -409,6 +409,40 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
                netif_rx(skb);
 }
 
+static bool ems_usb_rx_msg_len_valid(struct ems_cpc_msg *msg)
+{
+       size_t len = msg->length;
+       size_t can_len;
+
+       switch (msg->type) {
+       case CPC_MSG_TYPE_CAN_STATE:
+               return len >= sizeof(msg->msg.can_state);
+
+       case CPC_MSG_TYPE_CAN_FRAME:
+       case CPC_MSG_TYPE_EXT_CAN_FRAME:
+       case CPC_MSG_TYPE_RTR_FRAME:
+       case CPC_MSG_TYPE_EXT_RTR_FRAME:
+               if (len < CPC_CAN_MSG_MIN_SIZE)
+                       return false;
+
+               if (msg->type == CPC_MSG_TYPE_RTR_FRAME ||
+                   msg->type == CPC_MSG_TYPE_EXT_RTR_FRAME)
+                       return true;
+
+               can_len = can_cc_dlc2len(msg->msg.can_msg.length & 0xf);
+               return len >= CPC_CAN_MSG_MIN_SIZE + can_len;
+
+       case CPC_MSG_TYPE_CAN_FRAME_ERROR:
+               return len >= sizeof(msg->msg.error);
+
+       case CPC_MSG_TYPE_OVERRUN:
+               return len >= sizeof(msg->msg.overrun);
+
+       default:
+               return true;
+       }
+}
+
 /*
  * callback for bulk IN urb
  */
@@ -451,6 +485,15 @@ 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_rx_msg_len_valid(msg)) {
+                               netdev_err(netdev, "format error\n");
+                               break;
+                       }
 
                        switch (msg->type) {
                        case CPC_MSG_TYPE_CAN_STATE: