]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
can: peak_usb: add bounds check for USB channel index
authorJames Gao <jamesgao5@outlook.com>
Wed, 20 May 2026 05:40:03 +0000 (13:40 +0800)
committerMarc Kleine-Budde <mkl@pengutronix.de>
Wed, 29 Jul 2026 09:58:25 +0000 (11:58 +0200)
The channel control index ctrl_idx is derived from rx->len which comes
directly from a device USB payload. The mask 0x0f allows values 0-15, but
the array size of usb_if->dev[] is only 2. Values 2-15 cause heap
out-of-bounds read, eventually causing kernel panic in the IRQ context.

Add bounds checking for ctrl_idx before the array access in both
pcan_usb_pro_handle_canmsg() and pcan_usb_pro_handle_error().

Fixes: d8a199355f8f ("can: usb: PEAK-System Technik PCAN-USB Pro specific part")
Signed-off-by: James Gao <jamesgao5@outlook.com>
Reviewed-by: Vincent Mailhol <mailhol@kernel.org>
Link: https://patch.msgid.link/TYWPR01MB8559DBAAAA6A7F410400329CF0012@TYWPR01MB8559.jpnprd01.prod.outlook.com
Cc: stable@kernel.org
Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
drivers/net/can/usb/peak_usb/pcan_usb_pro.c

index aefcded8e12a8fb3cce0c6547c7116ed3fdc68e8..b6be8c19e537f1031c8deec497809266aa9fc62b 100644 (file)
@@ -534,12 +534,18 @@ static int pcan_usb_pro_handle_canmsg(struct pcan_usb_pro_interface *usb_if,
                                      struct pcan_usb_pro_rxmsg *rx)
 {
        const unsigned int ctrl_idx = (rx->len >> 4) & 0x0f;
-       struct peak_usb_device *dev = usb_if->dev[ctrl_idx];
-       struct net_device *netdev = dev->netdev;
+       struct peak_usb_device *dev;
+       struct net_device *netdev;
        struct can_frame *can_frame;
        struct sk_buff *skb;
        struct skb_shared_hwtstamps *hwts;
 
+       if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
+               return -EINVAL;
+
+       dev = usb_if->dev[ctrl_idx];
+       netdev = dev->netdev;
+
        skb = alloc_can_skb(netdev, &can_frame);
        if (!skb)
                return -ENOMEM;
@@ -573,14 +579,20 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
 {
        const u16 raw_status = le16_to_cpu(er->status);
        const unsigned int ctrl_idx = (er->channel >> 4) & 0x0f;
-       struct peak_usb_device *dev = usb_if->dev[ctrl_idx];
-       struct net_device *netdev = dev->netdev;
+       struct peak_usb_device *dev;
+       struct net_device *netdev;
        struct can_frame *can_frame;
        enum can_state new_state = CAN_STATE_ERROR_ACTIVE;
        u8 err_mask = 0;
        struct sk_buff *skb;
        struct skb_shared_hwtstamps *hwts;
 
+       if (ctrl_idx >= ARRAY_SIZE(usb_if->dev))
+               return -EINVAL;
+
+       dev = usb_if->dev[ctrl_idx];
+       netdev = dev->netdev;
+
        /* nothing should be sent while in BUS_OFF state */
        if (dev->can.state == CAN_STATE_BUS_OFF)
                return 0;