lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20251119120347.70a02fde.michal.pecio@gmail.com>
Date: Wed, 19 Nov 2025 12:03:47 +0100
From: Michal Pecio <michal.pecio@...il.com>
To: Mathias Nyman <mathias.nyman@...el.com>, Greg Kroah-Hartman
 <gregkh@...uxfoundation.org>
Cc: linux-usb@...r.kernel.org, linux-kernel@...r.kernel.org
Subject: [PATCH 2/5] usb: xhci: Find transfer TRB early in handle_tx_event()

As soon as we find the transfer ring to which an event belongs, we can
proceed to locate the exact TRB referenced by the event. This enables
better event handling and diagnostics, even if no TD matches the event.

Also set 'ep_seg' and remove its secondary use as a temporary boolean.

Bail out if event TRB pointer is not NULL and not a transfer TRB on the
endpoint's ring. This indicates that either the HC executes TRBs from a
wrong ring (bad Set TR Dequeue command, Link TRB damaged or ignored by
the HC) or its internal state is corrupted and the event is bogus.

No such event is going to match any TD on td_list and trying to handle
it would generally do nothing. On an isochronous endpoint we might skip
all pending TDs and create more chaos. Just log this error and get out.

Suggested-by: Mathias Nyman <mathias.nyman@...ux.intel.com>
Signed-off-by: Michal Pecio <michal.pecio@...il.com>
---
 drivers/usb/host/xhci-ring.c | 35 +++++++++++++++++++++++++++++++----
 1 file changed, 31 insertions(+), 4 deletions(-)

diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 3d5124912a09..531e2f207b17 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -82,6 +82,27 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
 	return seg->dma + (segment_offset * sizeof(*trb));
 }
 
+/*
+ * Look up a TRB by its DMA address, return NULL if not found on the ring.
+ * Search from start_seg to let callers optimize starting point selection.
+ * Write actual segment containing returned TRB to seg_out, if provided.
+ */
+static union xhci_trb *xhci_dma_to_trb(struct xhci_segment *start_seg, dma_addr_t dma,
+					struct xhci_segment **seg_out)
+{
+	struct xhci_segment *seg;
+
+	xhci_for_each_ring_seg(start_seg, seg) {
+		if (in_range(dma, seg->dma, TRB_SEGMENT_SIZE)) {
+			if (seg_out)
+				*seg_out = seg;
+			return seg->trbs + (dma - seg->dma) / sizeof(seg->trbs[0]);
+		}
+	}
+
+	return NULL;
+}
+
 static bool trb_is_noop(union xhci_trb *trb)
 {
 	return TRB_TYPE_NOOP_LE32(trb->generic.field[3]);
@@ -2672,6 +2693,15 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 	if (!ep_ring)
 		return handle_transferless_tx_event(xhci, ep, trb_comp_code);
 
+	/* get the corresponding transfer TRB pointer */
+	ep_trb = xhci_dma_to_trb(ep_ring->deq_seg, ep_trb_dma, &ep_seg);
+	if (!ep_trb && ep_trb_dma) {
+		xhci_warn(xhci, "Ignoring '%s' event out of ring on slot %d ep %d\n",
+				xhci_trb_comp_code_string(trb_comp_code), slot_id, ep_index);
+		/* XXX: other ring's TDs may be executing on this EP, should we kill it? */
+		return 0;
+	}
+
 	/* Look for common error cases */
 	switch (trb_comp_code) {
 	/* Skip codes that require special handling depending on
@@ -2846,9 +2876,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 				      td_list);
 
 		/* Is this a TRB in the currently executing TD? */
-		ep_seg = trb_in_td(td, ep_trb_dma);
-
-		if (!ep_seg) {
+		if (!trb_in_td(td, ep_trb_dma)) {
 
 			if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
 				/* this event is unlikely to match any TD, don't skip them all */
@@ -2931,7 +2959,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 	if (ring_xrun_event)
 		return 0;
 
-	ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)];
 	trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb, ep_trb_dma);
 
 	/*
-- 
2.48.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ