diff options
author | Alan Stern <stern@rowland.harvard.edu> | 2015-01-30 12:58:26 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <greg@kroah.com> | 2015-01-31 12:05:06 -0500 |
commit | c99197902da284b4b723451c1471c45b18537cde (patch) | |
tree | ff9d749b80d391ccc7b2dcd769c475facdeb9897 /drivers/usb/core | |
parent | cefa9a31a5f0856b81d53030815485fcb1fe8aab (diff) |
USB: fix use-after-free bug in usb_hcd_unlink_urb()
The usb_hcd_unlink_urb() routine in hcd.c contains two possible
use-after-free errors. The dev_dbg() statement at the end of the
routine dereferences urb and urb->dev even though both structures may
have been deallocated.
This patch fixes the problem by storing urb->dev in a local variable
(avoiding the dereference of urb) and moving the dev_dbg() up before
the usb_put_dev() call.
Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
Reported-by: Joe Lawrence <joe.lawrence@stratus.com>
Tested-by: Joe Lawrence <joe.lawrence@stratus.com>
CC: <stable@vger.kernel.org>
Signed-off-by: Greg Kroah-Hartman <greg@kroah.com>
Diffstat (limited to 'drivers/usb/core')
-rw-r--r-- | drivers/usb/core/hcd.c | 16 |
1 files changed, 8 insertions, 8 deletions
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c index 11cee55ae397..45a915ccd71c 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c | |||
@@ -1618,6 +1618,7 @@ static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status) | |||
1618 | int usb_hcd_unlink_urb (struct urb *urb, int status) | 1618 | int usb_hcd_unlink_urb (struct urb *urb, int status) |
1619 | { | 1619 | { |
1620 | struct usb_hcd *hcd; | 1620 | struct usb_hcd *hcd; |
1621 | struct usb_device *udev = urb->dev; | ||
1621 | int retval = -EIDRM; | 1622 | int retval = -EIDRM; |
1622 | unsigned long flags; | 1623 | unsigned long flags; |
1623 | 1624 | ||
@@ -1629,20 +1630,19 @@ int usb_hcd_unlink_urb (struct urb *urb, int status) | |||
1629 | spin_lock_irqsave(&hcd_urb_unlink_lock, flags); | 1630 | spin_lock_irqsave(&hcd_urb_unlink_lock, flags); |
1630 | if (atomic_read(&urb->use_count) > 0) { | 1631 | if (atomic_read(&urb->use_count) > 0) { |
1631 | retval = 0; | 1632 | retval = 0; |
1632 | usb_get_dev(urb->dev); | 1633 | usb_get_dev(udev); |
1633 | } | 1634 | } |
1634 | spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags); | 1635 | spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags); |
1635 | if (retval == 0) { | 1636 | if (retval == 0) { |
1636 | hcd = bus_to_hcd(urb->dev->bus); | 1637 | hcd = bus_to_hcd(urb->dev->bus); |
1637 | retval = unlink1(hcd, urb, status); | 1638 | retval = unlink1(hcd, urb, status); |
1638 | usb_put_dev(urb->dev); | 1639 | if (retval == 0) |
1640 | retval = -EINPROGRESS; | ||
1641 | else if (retval != -EIDRM && retval != -EBUSY) | ||
1642 | dev_dbg(&udev->dev, "hcd_unlink_urb %p fail %d\n", | ||
1643 | urb, retval); | ||
1644 | usb_put_dev(udev); | ||
1639 | } | 1645 | } |
1640 | |||
1641 | if (retval == 0) | ||
1642 | retval = -EINPROGRESS; | ||
1643 | else if (retval != -EIDRM && retval != -EBUSY) | ||
1644 | dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n", | ||
1645 | urb, retval); | ||
1646 | return retval; | 1646 | return retval; |
1647 | } | 1647 | } |
1648 | 1648 | ||