Skip to contentSkip to conversation

xhci: Restrict USB4 tunnel detection for USB3 devices to Intel hosts

PATCH In review Marc Zyngier 3 participants 3 messages Feb 27, 2025 – Feb 28, 2025

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 xhci: Restrict USB4 tunnel detection for USB3 devices to Intel hosts

When adding support for USB3-over-USB4 tunnelling detection, a check for an Intel-specific capability was added. This capability, which goes by ID 206, is used without any check that we are actually dealing with an Intel host.

As it turns out, the Cadence XHCI controller *also* exposes an extended capability numbered 206 (for unknown purposes), but of course doesn't have the Intel-specific registers that the tunnelling code is trying to access. Fun follows.

The core of the problems is that the tunnelling code blindly uses vendor-specific capabilities without any check (the Intel-provided documentation I have at hand indicates that 192-255 are indeed vendor-specific).

Restrict the detection code to Intel HW for real, preventing any further explosion on my (non-Intel) HW.

Cc Mathias Nyman <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Fixes 948ce83fbb7df ("xhci: Add USB4 tunnel detection for USB3 devices on Intel hosts")
---
 drivers/usb/host/xhci-hub.c | 8 ++++++++
 1 file changed, 8 insertions(+)
drivers/usb/host/xhci-hub.c +8 -0
index 9693464c05204..69c278b64084b 100644
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/unaligned.h>
 #include <linux/bitfield.h>
+#include <linux/pci.h>
 
 #include "xhci.h"
 #include "xhci-trace.h"
@@ -770,9 +771,16 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
 enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
 						struct xhci_port *port)
 {
+	struct usb_hcd *hcd;
 	void __iomem *base;
 	u32 offset;
 
+	/* Don't try and probe this capability for non-Intel hosts */
+	hcd = xhci_to_hcd(xhci);
+	if (!dev_is_pci(hcd->self.controller) ||
+	    to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL)
+		return USB_LINK_UNKNOWN;
+
 	base = &xhci->cap_regs->hc_capbase;
 	offset = xhci_find_next_ext_cap(base, 0, XHCI_EXT_CAPS_INTEL_SPR_SHADOW);
 
Signature · 1 line
2.39.2
#1 lore raw
Quoted 42 lines · Marc Zyngier

When adding support for USB3-over-USB4 tunnelling detection, a check for an Intel-specific capability was added. This capability, which goes by ID 206, is used without any check that we are actually dealing with an Intel host.

As it turns out, the Cadence XHCI controller *also* exposes an extended capability numbered 206 (for unknown purposes), but of course doesn't have the Intel-specific registers that the tunnelling code is trying to access. Fun follows.

The core of the problems is that the tunnelling code blindly uses vendor-specific capabilities without any check (the Intel-provided documentation I have at hand indicates that 192-255 are indeed vendor-specific).

Restrict the detection code to Intel HW for real, preventing any further explosion on my (non-Intel) HW.

Cc Mathias Nyman <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Fixes 948ce83fbb7df ("xhci: Add USB4 tunnel detection for USB3 devices on Intel hosts")
---
 drivers/usb/host/xhci-hub.c | 8 ++++++++
 1 file changed, 8 insertions(+)
drivers/usb/host/xhci-hub.c +1 -0
index 9693464c05204..69c278b64084b 100644
@@ -12,6 +12,7 @@
 #include <linux/slab.h>
 #include <linux/unaligned.h>
 #include <linux/bitfield.h>
+#include <linux/pci.h>
 
 #include "xhci.h"
 #include "xhci-trace.h"
@@ -770,9 +771,16 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
 enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
 						struct xhci_port *port)

drivers/usb/host/xhci-hub.c static int xhci_exit_test_mode(struct xhci_hcd *xhci) · line 782

Quoted 10 lines
drivers/usb/host/xhci-hub.c +6 -0
 {
+	struct usb_hcd *hcd;
 	void __iomem *base;
 	u32 offset;
 
+	/* Don't try and probe this capability for non-Intel hosts */
+	hcd = xhci_to_hcd(xhci);
+	if (!dev_is_pci(hcd->self.controller) ||
+	    to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL)
+		return USB_LINK_UNKNOWN;

Ugh, nice catch.

Mathias, want me to just take this directly for now and not wait for you to resend it?

thanks,

greg k-h

Acked-by
#2 lore raw
Quoted 56 lines · Greg Kroah-Hartman
Quoted 42 lines · Marc Zyngier

When adding support for USB3-over-USB4 tunnelling detection, a check for an Intel-specific capability was added. This capability, which goes by ID 206, is used without any check that we are actually dealing with an Intel host.

As it turns out, the Cadence XHCI controller *also* exposes an extended capability numbered 206 (for unknown purposes), but of course doesn't have the Intel-specific registers that the tunnelling code is trying to access. Fun follows.

The core of the problems is that the tunnelling code blindly uses vendor-specific capabilities without any check (the Intel-provided documentation I have at hand indicates that 192-255 are indeed vendor-specific).

Restrict the detection code to Intel HW for real, preventing any further explosion on my (non-Intel) HW.

Cc Mathias Nyman <[email protected]>
Cc Greg Kroah-Hartman <[email protected]>
Fixes 948ce83fbb7df ("xhci: Add USB4 tunnel detection for USB3 devices on Intel hosts")
---
  drivers/usb/host/xhci-hub.c | 8 ++++++++
  1 file changed, 8 insertions(+)
drivers/usb/host/xhci-hub.c +1 -0
index 9693464c05204..69c278b64084b 100644
@@ -12,6 +12,7 @@
  #include <linux/slab.h>
  #include <linux/unaligned.h>
  #include <linux/bitfield.h>
+#include <linux/pci.h>
 
  #include "xhci.h"
  #include "xhci-trace.h"
@@ -770,9 +771,16 @@ static int xhci_exit_test_mode(struct xhci_hcd *xhci)
  enum usb_link_tunnel_mode xhci_port_is_tunneled(struct xhci_hcd *xhci,
  						struct xhci_port *port)

drivers/usb/host/xhci-hub.c static int xhci_exit_test_mode(struct xhci_hcd *xhci) · line 782

Quoted 10 lines
drivers/usb/host/xhci-hub.c +6 -0
  {
+	struct usb_hcd *hcd;
  	void __iomem *base;
  	u32 offset;
 
+	/* Don't try and probe this capability for non-Intel hosts */
+	hcd = xhci_to_hcd(xhci);
+	if (!dev_is_pci(hcd->self.controller) ||
+	    to_pci_dev(hcd->self.controller)->vendor != PCI_VENDOR_ID_INTEL)
+		return USB_LINK_UNKNOWN;

Ugh, nice catch.

Quoted 2 lines

Mathias, want me to just take this directly for now and not wait for you to resend it?

Yes, please, take it directly

Thanks
Mathias