xhci: Fix NULL pointer deref in handle_port_status()
When we get a port status change event, we need to figure out what type of port it came from: a USB 3.0 port, or a USB 2.0/1.1 port. We can't know which usb_hcd to use until that point, so hcd will be NULL for part of the function. Unfortunately, if any of the sanity checks fail, we'll jump to the cleanup label before hcd is set to a valid pointer, and then we'll attempt to tell the USB core to kick the hcd, which is NULL. Skip kicking the roothub if the sanity checks fail. Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
This commit is contained in:
parent
dfa49c4ad1
commit
386139d7c8
1 changed files with 11 additions and 0 deletions
|
@ -1235,6 +1235,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
u8 major_revision;
|
||||
struct xhci_bus_state *bus_state;
|
||||
u32 __iomem **port_array;
|
||||
bool bogus_port_status = false;
|
||||
|
||||
/* Port status change events always have a successful completion code */
|
||||
if (GET_COMP_CODE(event->generic.field[2]) != COMP_SUCCESS) {
|
||||
|
@ -1247,6 +1248,7 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
max_ports = HCS_MAX_PORTS(xhci->hcs_params1);
|
||||
if ((port_id <= 0) || (port_id > max_ports)) {
|
||||
xhci_warn(xhci, "Invalid port id %d\n", port_id);
|
||||
bogus_port_status = true;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -1258,12 +1260,14 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
xhci_warn(xhci, "Event for port %u not in "
|
||||
"Extended Capabilities, ignoring.\n",
|
||||
port_id);
|
||||
bogus_port_status = true;
|
||||
goto cleanup;
|
||||
}
|
||||
if (major_revision == DUPLICATE_ENTRY) {
|
||||
xhci_warn(xhci, "Event for port %u duplicated in"
|
||||
"Extended Capabilities, ignoring.\n",
|
||||
port_id);
|
||||
bogus_port_status = true;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
|
@ -1335,6 +1339,13 @@ static void handle_port_status(struct xhci_hcd *xhci,
|
|||
/* Update event ring dequeue pointer before dropping the lock */
|
||||
inc_deq(xhci, xhci->event_ring, true);
|
||||
|
||||
/* Don't make the USB core poll the roothub if we got a bad port status
|
||||
* change event. Besides, at that point we can't tell which roothub
|
||||
* (USB 2.0 or USB 3.0) to kick.
|
||||
*/
|
||||
if (bogus_port_status)
|
||||
return;
|
||||
|
||||
spin_unlock(&xhci->lock);
|
||||
/* Pass this up to the core */
|
||||
usb_hcd_poll_rh_status(hcd);
|
||||
|
|
Loading…
Reference in a new issue