diff options
author | Mathias Nyman <mathias.nyman@linux.intel.com> | 2017-07-20 14:48:26 +0300 |
---|---|---|
committer | Ben Hutchings <ben@decadent.org.uk> | 2017-11-11 16:33:02 +0300 |
commit | 96bfb7d0843a57f033c8d91a306ef4270d798e85 (patch) | |
tree | baa668ef573678931e3b477c71f2912a882088ca /drivers/usb | |
parent | 4053c6292e6991e9241f221ce5b4a0e771f7118d (diff) | |
download | linux-96bfb7d0843a57f033c8d91a306ef4270d798e85.tar.xz |
xhci: Fix NULL pointer dereference when cleaning up streams for removed host
commit 4b895868bb2da60a386a17cde3bf9ecbc70c79f4 upstream.
This off by one in stream_id indexing caused NULL pointer dereference and
soft lockup on machines with USB attached SCSI devices connected to a
hotpluggable xhci controller.
The code that cleans up pending URBs for dead hosts tried to dereference
a stream ring at the invalid stream_id 0.
ep->stream_info->stream_rings[0] doesn't point to a ring.
Start looping stream_id from 1 like in all the other places in the driver,
and check that the ring exists before trying to kill URBs on it.
Reported-by: rocko r <rockorequin@gmail.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Ben Hutchings <ben@decadent.org.uk>
Diffstat (limited to 'drivers/usb')
-rw-r--r-- | drivers/usb/host/xhci-ring.c | 11 |
1 files changed, 7 insertions, 4 deletions
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 97a3955650c9..e69c7df4b9a9 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -821,13 +821,16 @@ static void xhci_kill_endpoint_urbs(struct xhci_hcd *xhci, (ep->ep_state & EP_GETTING_NO_STREAMS)) { int stream_id; - for (stream_id = 0; stream_id < ep->stream_info->num_streams; + for (stream_id = 1; stream_id < ep->stream_info->num_streams; stream_id++) { + ring = ep->stream_info->stream_rings[stream_id]; + if (!ring) + continue; + xhci_dbg_trace(xhci, trace_xhci_dbg_cancel_urb, "Killing URBs for slot ID %u, ep index %u, stream %u", - slot_id, ep_index, stream_id + 1); - xhci_kill_ring_urbs(xhci, - ep->stream_info->stream_rings[stream_id]); + slot_id, ep_index, stream_id); + xhci_kill_ring_urbs(xhci, ring); } } else { ring = ep->ring; |