From: Michal Pecio <michal.pecio@gmail.com>
To: co <co+fd80bc5967eb22c3@bugs.sh>,
"Mathias Nyman" <mathias.nyman@intel.com>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>
Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] usb: xhci: Fix bounce buffer overflow
Date: Wed, 2 Sep 2026 13:24:58 +0200 [thread overview]
Message-ID: <20260902132458.5de2f031.michal.pecio@gmail.com> (raw)
In-Reply-To: <20260828002440.312ec0b6.michal.pecio@gmail.com>
High-speed devices with out of spec 1024 byte bulk endpoints exist and
are allowed by USB core, but xhci-hcd always sets packet size to 512.
The exact nature of these devices isn't documented, commit fb5ee84ea72c
("USB: Accept bulk endpoints with 1024-byte maxpacket") only states
that they "don't work with xHCI host controllers", whatever it means.
But somebody (or a malicious device) can try, and then the driver will
allocate a 512 byte bounce buffer for this endpoint and may write up to
1024 bytes into it if particular scatter-gather URBs are used, because
xhci_align_td() obtains packet size from the descriptor. Fix this.
As a side effect, TRBs will be aligned to the packet size chosen by the
driver on all endpoints of all speeds. Alignment serves the xHC, not
device, so this is fine. Only out of spec devices are affected anyway.
Reported-by: co+fd80bc5967eb22c3@bugs.sh
Link: https://lore.kernel.org/linux-usb/D4tcSGerkYkIV1DmaUo1t8TaR5qQElDLkidn@bugs.sh/
Fixes: f9c589e142d0 ("xhci: TD-fragment, align the unsplittable case with a bounce buffer")
Cc: stable@vger.kernel.org
Signed-off-by: Michal Pecio <michal.pecio@gmail.com>
---
Trivial bug, trivial patch, though only tested for regression with
an in-spec device, testing with the malicious device would be helpful
to confirm that memory corruption is gone as expected.
As for actual devices with 1KB packet size, I found that Cypress FX2
can generate such packets and some HCs receive them, though others
reject the Configure Endpoint command and usb_set_interface() fails.
So we could support that, but this code really should just use the
packet size selected by the driver instead of guessing.
Perhaps the same should apply to other users of endpoint_maxp(), but
those just calculate some TRB fields like TD Size, nothing critical.
drivers/usb/host/xhci-ring.c | 9 +++------
1 file changed, 3 insertions(+), 6 deletions(-)
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b9d005ca5877..fa6684746305 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -3537,15 +3537,13 @@ static u32 xhci_td_remainder(struct xhci_hcd *xhci, int transferred,
static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
- u32 *trb_buff_len, struct xhci_segment *seg)
+ u32 *trb_buff_len, struct xhci_segment *seg, u32 max_pkt)
{
struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
unsigned int unalign;
- unsigned int max_pkt;
u32 new_buff_len;
size_t len;
- max_pkt = xhci_usb_endpoint_maxp(urb->dev, urb->ep);
unalign = (enqd_len + *trb_buff_len) % max_pkt;
/* we got lucky, last normal TRB data on segment is packet aligned */
@@ -3690,9 +3688,8 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (enqd_len + trb_buff_len < full_len) {
field |= TRB_CHAIN;
if (trb_is_link(ring->enqueue + 1)) {
- if (xhci_align_td(xhci, urb, enqd_len,
- &trb_buff_len,
- ring->enq_seg)) {
+ if (xhci_align_td(xhci, urb, enqd_len, &trb_buff_len,
+ ring->enq_seg, ring->bounce_buf_len)) {
send_addr = ring->enq_seg->bounce_dma;
/* TD bounced at least, and last on this seg */
td->bounce_seg = ring->enq_seg;
--
2.48.1
next prev parent reply other threads:[~2026-09-02 11:25 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-27 12:43 [BUG] drivers/usb: out-of-bounds in xhci_queue_bulk_tx() co
2026-08-27 12:50 ` Greg Kroah-Hartman
2026-08-27 17:31 ` Xiang Mei
2026-08-28 2:00 ` CO
2026-08-27 22:47 ` Michal Pecio
2026-09-02 11:24 ` Michal Pecio [this message]
2026-09-02 13:39 ` [PATCH] usb: xhci: Fix bounce buffer overflow Mathias Nyman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260902132458.5de2f031.michal.pecio@gmail.com \
--to=michal.pecio@gmail.com \
--cc=co+fd80bc5967eb22c3@bugs.sh \
--cc=gregkh@linuxfoundation.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-usb@vger.kernel.org \
--cc=mathias.nyman@intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®