Skip to content

Commit

Permalink
xhci: Fix NULL pointer deref in handle_port_status()
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Sarah Sharp committed Apr 13, 2011
1 parent dfa49c4 commit 386139d
Showing 1 changed file with 11 additions and 0 deletions.
11 changes: 11 additions & 0 deletions drivers/usb/host/xhci-ring.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 386139d

Please sign in to comment.