summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMathias Nyman <mathias.nyman@linux.intel.com>2023-01-16 16:22:12 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-01-24 07:11:49 +0100
commit6fac4b5cecb3928a0a81069aaa815a2edc8dd5a1 (patch)
treea409bf9c3bdceba4d8df964a7aae1e68bb5307bd
parent2d2820d5f375563690c96e60676855205abfb7f5 (diff)
downloadlinux-stable-6fac4b5cecb3928a0a81069aaa815a2edc8dd5a1.tar.gz
linux-stable-6fac4b5cecb3928a0a81069aaa815a2edc8dd5a1.tar.bz2
linux-stable-6fac4b5cecb3928a0a81069aaa815a2edc8dd5a1.zip
xhci: Fix null pointer dereference when host dies
commit a2bc47c43e70cf904b1af49f76d572326c08bca7 upstream. Make sure xhci_free_dev() and xhci_kill_endpoint_urbs() do not race and cause null pointer dereference when host suddenly dies. Usb core may call xhci_free_dev() which frees the xhci->devs[slot_id] virt device at the same time that xhci_kill_endpoint_urbs() tries to loop through all the device's endpoints, checking if there are any cancelled urbs left to give back. hold the xhci spinlock while freeing the virt device Cc: stable@vger.kernel.org Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://lore.kernel.org/r/20230116142216.1141605-4-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/xhci.c5
1 files changed, 5 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 3a1ed63d7334..7deae4e76aa1 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -3830,6 +3830,7 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
struct xhci_hcd *xhci = hcd_to_xhci(hcd);
struct xhci_virt_device *virt_dev;
struct xhci_slot_ctx *slot_ctx;
+ unsigned long flags;
int i, ret;
/*
@@ -3859,7 +3860,11 @@ static void xhci_free_dev(struct usb_hcd *hcd, struct usb_device *udev)
xhci_debugfs_remove_slot(xhci, udev->slot_id);
virt_dev->udev = NULL;
xhci_disable_slot(xhci, udev->slot_id);
+
+ spin_lock_irqsave(&xhci->lock, flags);
xhci_free_virt_device(xhci, udev->slot_id);
+ spin_unlock_irqrestore(&xhci->lock, flags);
+
}
int xhci_disable_slot(struct xhci_hcd *xhci, u32 slot_id)