]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
usbnet:fix NPE during rx_complete
authorYing Lu <luying1@xiaomi.com>
Wed, 2 Apr 2025 08:58:59 +0000 (16:58 +0800)
committerJakub Kicinski <kuba@kernel.org>
Fri, 4 Apr 2025 14:24:46 +0000 (07:24 -0700)
Missing usbnet_going_away Check in Critical Path.
The usb_submit_urb function lacks a usbnet_going_away
validation, whereas __usbnet_queue_skb includes this check.

This inconsistency creates a race condition where:
A URB request may succeed, but the corresponding SKB data
fails to be queued.

Subsequent processes:
(e.g., rx_complete → defer_bh → __skb_unlink(skb, list))
attempt to access skb->next, triggering a NULL pointer
dereference (Kernel Panic).

Fixes: 04e906839a05 ("usbnet: fix cyclical race on disconnect with work queue")
Cc: stable@vger.kernel.org
Signed-off-by: Ying Lu <luying1@xiaomi.com>
Link: https://patch.msgid.link/4c9ef2efaa07eb7f9a5042b74348a67e5a3a7aea.1743584159.git.luying1@xiaomi.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/net/usb/usbnet.c

index aeab2308b15008185336f717172b090739f4f9d0..724b93aa4f7eb320a66caba7de6e93fd77381128 100644 (file)
@@ -530,7 +530,8 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
            netif_device_present (dev->net) &&
            test_bit(EVENT_DEV_OPEN, &dev->flags) &&
            !test_bit (EVENT_RX_HALT, &dev->flags) &&
-           !test_bit (EVENT_DEV_ASLEEP, &dev->flags)) {
+           !test_bit (EVENT_DEV_ASLEEP, &dev->flags) &&
+           !usbnet_going_away(dev)) {
                switch (retval = usb_submit_urb (urb, GFP_ATOMIC)) {
                case -EPIPE:
                        usbnet_defer_kevent (dev, EVENT_RX_HALT);
@@ -551,8 +552,7 @@ static int rx_submit (struct usbnet *dev, struct urb *urb, gfp_t flags)
                        tasklet_schedule (&dev->bh);
                        break;
                case 0:
-                       if (!usbnet_going_away(dev))
-                               __usbnet_queue_skb(&dev->rxq, skb, rx_start);
+                       __usbnet_queue_skb(&dev->rxq, skb, rx_start);
                }
        } else {
                netif_dbg(dev, ifdown, dev->net, "rx: stopped\n");