diff options
author | Joe Lawrence <joe.lawrence@stratus.com> | 2016-02-03 20:51:12 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-02-05 04:00:10 +0300 |
commit | 89140fdaf11aec81e93d5590a993720f2ef0d26e (patch) | |
tree | c7abad88a88cfe4fe2d599eff868a59e18f16f17 /drivers/usb/host/xhci-ext-caps.h | |
parent | 207b08b9426dfaa63fcfea4156be0acb5b46ee38 (diff) | |
download | linux-89140fdaf11aec81e93d5590a993720f2ef0d26e.tar.xz |
xhci: harden xhci_find_next_ext_cap against device removal
xhci_find_next_ext_cap doesn't check for PCI hotplug removal and may use
the PCI master abort bit pattern (~0) to calculate a new PCI address
offset to read/write. The has lead to reproducable crashes when testing
surprise removal during device initialization on a Stratus platform, at
least after commit d5ddcdf4d672 ("xhci: rework xhci extended capability
list parsing functions").
The crash is repeatable on a Stratus platform when injecting hardware
faults to induce xHCI host controller hotplug during driver
initialization. If a PCI read in xhci_find_next_ext_cap returns the
master abort pattern, quirk_usb_handoff_xhci may start using a bogus
ext_cap_offset to start searching more bogus PCI addresses.
Signed-off-by: Joe Lawrence <joe.lawrence@stratus.com>
Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/host/xhci-ext-caps.h')
-rw-r--r-- | drivers/usb/host/xhci-ext-caps.h | 4 |
1 files changed, 4 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h index 04ce6b156b35..e0244fb3903d 100644 --- a/drivers/usb/host/xhci-ext-caps.h +++ b/drivers/usb/host/xhci-ext-caps.h @@ -112,12 +112,16 @@ static inline int xhci_find_next_ext_cap(void __iomem *base, u32 start, int id) offset = start; if (!start || start == XHCI_HCC_PARAMS_OFFSET) { val = readl(base + XHCI_HCC_PARAMS_OFFSET); + if (val == ~0) + return 0; offset = XHCI_HCC_EXT_CAPS(val) << 2; if (!offset) return 0; }; do { val = readl(base + offset); + if (val == ~0) + return 0; if (XHCI_EXT_CAPS_ID(val) == id && offset != start) return offset; |