xhci: Limit roothub ports to 15 USB3 & 31 USB2 ports.
authorSarah Sharp <sarah.a.sharp@linux.intel.com>
Tue, 23 Nov 2010 18:42:22 +0000 (10:42 -0800)
committerSarah Sharp <sarah.a.sharp@linux.intel.com>
Mon, 14 Mar 2011 01:23:42 +0000 (18:23 -0700)
The USB core allocates a USB 2.0 roothub descriptor that has room for 31
(USB_MAXCHILDREN) ports' worth of DeviceRemovable and PortPwrCtrlMask
fields.  Limit the number of USB 2.0 roothub ports accordingly.  I don't
expect to run into this limitation ever, but this prevents a buffer
overflow issue in the roothub descriptor filling code.

Similarly, a USB 3.0 hub can only have 15 downstream ports, so limit the
USB 3.0 roothub to 15 USB 3.0 ports.

Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
drivers/usb/host/xhci-mem.c

index 180a2ab..71fd8bd 100644 (file)
@@ -1803,6 +1803,20 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
        }
        xhci_dbg(xhci, "Found %u USB 2.0 ports and %u USB 3.0 ports.\n",
                        xhci->num_usb2_ports, xhci->num_usb3_ports);
+
+       /* Place limits on the number of roothub ports so that the hub
+        * descriptors aren't longer than the USB core will allocate.
+        */
+       if (xhci->num_usb3_ports > 15) {
+               xhci_dbg(xhci, "Limiting USB 3.0 roothub ports to 15.\n");
+               xhci->num_usb3_ports = 15;
+       }
+       if (xhci->num_usb2_ports > USB_MAXCHILDREN) {
+               xhci_dbg(xhci, "Limiting USB 2.0 roothub ports to %u.\n",
+                               USB_MAXCHILDREN);
+               xhci->num_usb2_ports = USB_MAXCHILDREN;
+       }
+
        /*
         * Note we could have all USB 3.0 ports, or all USB 2.0 ports.
         * Not sure how the USB core will handle a hub with no ports...
@@ -1827,6 +1841,8 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
                                        "addr = %p\n", i,
                                        xhci->usb2_ports[port_index]);
                        port_index++;
+                       if (port_index == xhci->num_usb2_ports)
+                               break;
                }
        }
        if (xhci->num_usb3_ports) {
@@ -1845,6 +1861,8 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags)
                                                "addr = %p\n", i,
                                                xhci->usb3_ports[port_index]);
                                port_index++;
+                               if (port_index == xhci->num_usb3_ports)
+                                       break;
                        }
        }
        return 0;