Out-of-bounds access was triggered on a Thinkpad Yoga during suspend or by rmmod'ing the xhci-pci module, sometimes leading to a general protection fault. This is a defensive symptom fix; the error proper must occur somewhere else, eg. when the udev with its portnum is left lingering around even after the xhci struct has its num_usb2_ports reduced to zero, or maybe when the udev is assigned to the wrong xhci. Anyway, this keeps nasty crashes from happening in hard to debug situations (during suspend, not even kdump could provide an error message). Signed-off-by: Christian M. Amsüss <chrysn@xxxxxxxx> --- On Mon, Dec 14, 2015 at 07:42:54PM +0100, chrysn wrote: > [1.] One line summary of the problem: > > general_protection when rmmod'ing xhci-pci Some other observations around the issue: * rmmod'ing/modprobing xhci-pci is just a more convenient way of reproducing the issue; the problematic code section is being passed through on suspends as well (I placed debug messages there and observed them during suspend), I just seem never to have managed to get a kdump of such a situation / was always stuck with a black screen and dead device. The issue is more easily reproducible when the device is under any kind of load; a plain rmmod/modprobe loop with some sleep inbetween often does not trigger the issue, because while the out-of-bounds access still occurs, the addresses involved haven't changed, and there are still sufficiently valid pointers around for no general protection error to occur. Restarting a postgresql server in an endless loop in another terminal speeds up testing. * This a symptom fix; I probably won't look deeper on my own, but would be happy to provide more details or test patches on the machine this occurs on. drivers/usb/host/xhci.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index d51ee0c..3c1f1f3 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -4171,6 +4171,12 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd, port_array = xhci->usb2_ports; port_num = udev->portnum - 1; + if (port_num >= xhci->num_usb2_ports) { + dev_warn(&udev->dev, "%s: udev portnum exceeds num_usb2_ports, pretending there is no power management.\n", + __func__); + spin_unlock_irqrestore(&xhci->lock, flags); + return 0; + } pm_addr = port_array[port_num] + PORTPMSC; pm_val = readl(pm_addr); hlpm_addr = port_array[port_num] + PORTHLPMC; -- 2.8.0.rc3
Attachment:
signature.asc
Description: PGP signature