summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorJack Pham <jackp@codeaurora.org>2017-06-01 17:57:14 -0700
committerJack Pham <jackp@codeaurora.org>2017-06-02 09:59:15 -0700
commita4253a4598b6632a2e49f17fac5ed10abf43aae2 (patch)
treeb27ee134fc2bf0df7ad5e2b1d97908340cac3766 /drivers/usb
parent28bf2d8b6bd153bb3a27ec871115d76f6a94b97e (diff)
usb: xhci: Avoid accessing dangling virt_dev in xhci_stop_device
In xhci_stop_device() the virt_dev pointer is assigned from the device slot prior to acquiring xhci->lock and disabling IRQs. This is an opportunity for a TRB_DISABLE_SLOT command to have completed (e.g. in case the device was disconnected, or the port was disabled) which would have called xhci_free_virt_device() and freed the slot's pointer in IRQ context. Then after the lock is acquired virt_dev may now be pointing to freed memory and results in a panic. Avoid this by moving the assignment virt_dev = xhci->devs[slot_id]; and NULL pointer check to after the lock is taken to ensure that we don't race against xhci IRQ handler. Change-Id: I4ac23fbfd3def0ad93967316b62c0c0cd19ca33f Signed-off-by: Jack Pham <jackp@codeaurora.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/host/xhci-hub.c11
1 files changed, 7 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index d885033d3322..6c414f252291 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -376,10 +376,6 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
int i;
ret = 0;
- virt_dev = xhci->devs[slot_id];
- if (!virt_dev)
- return -ENODEV;
-
cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
if (!cmd) {
xhci_dbg(xhci, "Couldn't allocate command structure.\n");
@@ -387,6 +383,13 @@ static int xhci_stop_device(struct xhci_hcd *xhci, int slot_id, int suspend)
}
spin_lock_irqsave(&xhci->lock, flags);
+ virt_dev = xhci->devs[slot_id];
+ if (!virt_dev) {
+ spin_unlock_irqrestore(&xhci->lock, flags);
+ xhci_free_command(xhci, cmd);
+ return -ENODEV;
+ }
+
for (i = LAST_EP_INDEX; i > 0; i--) {
if (virt_dev->eps[i].ring && virt_dev->eps[i].ring->dequeue) {
struct xhci_command *command;