usbnet: don't clear urb->dev in tx_complete
[firefly-linux-kernel-4.4.55.git] / drivers / net / usb / usbnet.c
index 4b8b52ca09d866001bb9302d42103e5266fdee53..62f8b5cfbb56c3057f49309d2ad4fbd3d611a309 100644 (file)
@@ -589,6 +589,14 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
                entry = (struct skb_data *) skb->cb;
                urb = entry->urb;
 
+               /*
+                * Get reference count of the URB to avoid it to be
+                * freed during usb_unlink_urb, which may trigger
+                * use-after-free problem inside usb_unlink_urb since
+                * usb_unlink_urb is always racing with .complete
+                * handler(include defer_bh).
+                */
+               usb_get_urb(urb);
                spin_unlock_irqrestore(&q->lock, flags);
                // during some PM-driven resume scenarios,
                // these (async) unlinks complete immediately
@@ -597,6 +605,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
                        netdev_dbg(dev->net, "unlink urb err, %d\n", retval);
                else
                        count++;
+               usb_put_urb(urb);
                spin_lock_irqsave(&q->lock, flags);
        }
        spin_unlock_irqrestore (&q->lock, flags);
@@ -1028,7 +1037,6 @@ static void tx_complete (struct urb *urb)
        }
 
        usb_autopm_put_interface_async(dev->intf);
-       urb->dev = NULL;
        entry->state = tx_done;
        defer_bh(dev, skb, &dev->txq);
 }