diff options
Diffstat (limited to 'drivers/net/usb/usbnet.c')
-rw-r--r-- | drivers/net/usb/usbnet.c | 9 |
1 files changed, 9 insertions, 0 deletions
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 4b8b52ca09d8..febfdceeb9e5 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c | |||
@@ -589,6 +589,14 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) | |||
589 | entry = (struct skb_data *) skb->cb; | 589 | entry = (struct skb_data *) skb->cb; |
590 | urb = entry->urb; | 590 | urb = entry->urb; |
591 | 591 | ||
592 | /* | ||
593 | * Get reference count of the URB to avoid it to be | ||
594 | * freed during usb_unlink_urb, which may trigger | ||
595 | * use-after-free problem inside usb_unlink_urb since | ||
596 | * usb_unlink_urb is always racing with .complete | ||
597 | * handler(include defer_bh). | ||
598 | */ | ||
599 | usb_get_urb(urb); | ||
592 | spin_unlock_irqrestore(&q->lock, flags); | 600 | spin_unlock_irqrestore(&q->lock, flags); |
593 | // during some PM-driven resume scenarios, | 601 | // during some PM-driven resume scenarios, |
594 | // these (async) unlinks complete immediately | 602 | // these (async) unlinks complete immediately |
@@ -597,6 +605,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) | |||
597 | netdev_dbg(dev->net, "unlink urb err, %d\n", retval); | 605 | netdev_dbg(dev->net, "unlink urb err, %d\n", retval); |
598 | else | 606 | else |
599 | count++; | 607 | count++; |
608 | usb_put_urb(urb); | ||
600 | spin_lock_irqsave(&q->lock, flags); | 609 | spin_lock_irqsave(&q->lock, flags); |
601 | } | 610 | } |
602 | spin_unlock_irqrestore (&q->lock, flags); | 611 | spin_unlock_irqrestore (&q->lock, flags); |