Commit 0956a8c2 authored by tom.leiming@gmail.com's avatar tom.leiming@gmail.com Committed by David S. Miller

usbnet: increase URB reference count before usb_unlink_urb

Commit 4231d47e(net/usbnet: avoid
recursive locking in usbnet_stop()) fixes the recursive locking
problem by releasing the skb queue lock, but it makes usb_unlink_urb
racing with defer_bh, and the URB to being unlinked may be freed before
or during calling usb_unlink_urb, so use-after-free problem may be
triggerd inside usb_unlink_urb.

The patch fixes the use-after-free problem by increasing URB
reference count with skb queue lock held before calling
usb_unlink_urb, so the URB won't be freed until return from
usb_unlink_urb.

Cc: stable@kernel.org
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: Oliver Neukum <oliver@neukum.org>
Reported-by: default avatarDave Jones <davej@redhat.com>
Signed-off-by: default avatarMing Lei <tom.leiming@gmail.com>
Acked-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1265fd61
...@@ -589,6 +589,14 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) ...@@ -589,6 +589,14 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q)
entry = (struct skb_data *) skb->cb; entry = (struct skb_data *) skb->cb;
urb = entry->urb; 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); spin_unlock_irqrestore(&q->lock, flags);
// during some PM-driven resume scenarios, // during some PM-driven resume scenarios,
// these (async) unlinks complete immediately // these (async) unlinks complete immediately
...@@ -597,6 +605,7 @@ static int unlink_urbs (struct usbnet *dev, struct sk_buff_head *q) ...@@ -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); netdev_dbg(dev->net, "unlink urb err, %d\n", retval);
else else
count++; count++;
usb_put_urb(urb);
spin_lock_irqsave(&q->lock, flags); spin_lock_irqsave(&q->lock, flags);
} }
spin_unlock_irqrestore (&q->lock, flags); spin_unlock_irqrestore (&q->lock, flags);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment