From: Thomas Huth <thuth@redhat.com>
To: qemu-devel@nongnu.org, Stefan Hajnoczi <stefanha@redhat.com>
Cc: "Feifan Qian" <bea1e@proton.me>,
"Marc-André Lureau" <marcandre.lureau@redhat.com>
Subject: [PULL 4/7] usbredir: fix use-after-free on buffered bulk packet overflow
Date: Mon, 20 Jul 2026 12:38:30 +0200 [thread overview]
Message-ID: <20260720103833.364506-5-thuth@redhat.com> (raw)
In-Reply-To: <20260720103833.364506-1-thuth@redhat.com>
From: Marc-André Lureau <marcandre.lureau@redhat.com>
When usbredir_buffered_bulk_packet() splits a multi-fragment buffered
bulk packet into max-packet-size chunks, only the final fragment owns
the shared parser allocation (via free_on_destroy). If bufp_alloc()
drops the final fragment due to queue overflow, it frees the backing
buffer while earlier fragments already queued still hold interior
pointers into it. Subsequent guest bulk-IN transfers then read from
freed heap memory.
Fix this by tracking how many fragments were queued during the current
packet. When bufp_alloc() fails, remove all already-queued fragments
from the tail of the endpoint queue before breaking out of the loop.
If the dropped fragment was non-final, free the data buffer explicitly
since no fragment took ownership.
Fixes: CVE-2026-15705
Fixes: b2d1fe67d09d ("usbredir: Add support for buffered bulk input (v2)")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3808
Reported-by: Feifan Qian <bea1e@proton.me>
Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20260714185717.1156157-1-marcandre.lureau@redhat.com>
Signed-off-by: Thomas Huth <thuth@redhat.com>
---
hw/usb/redirect.c | 18 +++++++++++++++++-
1 file changed, 17 insertions(+), 1 deletion(-)
diff --git a/hw/usb/redirect.c b/hw/usb/redirect.c
index bde821e214b..284bcbdb34d 100644
--- a/hw/usb/redirect.c
+++ b/hw/usb/redirect.c
@@ -2138,7 +2138,7 @@ static void usbredir_buffered_bulk_packet(void *priv, uint64_t id,
USBRedirDevice *dev = priv;
uint8_t status, ep = buffered_bulk_packet->endpoint;
void *free_on_destroy;
- int i, len;
+ int i, len, queued = 0;
DPRINTF("buffered-bulk-in status %d ep %02X len %d id %"PRIu64"\n",
buffered_bulk_packet->status, ep, data_len, id);
@@ -2169,8 +2169,24 @@ static void usbredir_buffered_bulk_packet(void *priv, uint64_t id,
/* bufp_alloc also adds the packet to the ep queue */
r = bufp_alloc(dev, data + i, len, status, ep, free_on_destroy);
if (r) {
+ /*
+ * Earlier fragments from this packet are in the queue
+ * with interior pointers into data. If the dropped
+ * fragment was the final one, bufp_alloc already freed
+ * data so those pointers are dangling. Remove them.
+ */
+ while (queued > 0) {
+ struct buf_packet *bufp;
+ bufp = QTAILQ_LAST(&dev->endpoint[EP2I(ep)].bufpq);
+ bufp_free(dev, bufp, ep);
+ queued--;
+ }
+ if (!free_on_destroy) {
+ free(data);
+ }
break;
}
+ queued++;
}
if (dev->endpoint[EP2I(ep)].pending_async_packet) {
--
2.55.0
next prev parent reply other threads:[~2026-07-20 10:39 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-20 10:38 [PULL 0/7] USB-related bug fixes Thomas Huth
2026-07-20 10:38 ` [PULL 1/7] hw/usb/xhci: clamp interval exponent to avoid UB shift in xhci_init_epctx() Thomas Huth
2026-07-20 10:38 ` [PULL 2/7] hw/usb/hcd-xhci-pci: break host link cycle so device_finalize() runs on unplug Thomas Huth
2026-07-20 10:38 ` [PULL 3/7] tests/qtest: add xhci-pci unplug finalize regression test Thomas Huth
2026-07-20 10:38 ` Thomas Huth [this message]
2026-07-20 10:38 ` [PULL 5/7] usbredir: fix infinite loop and SIGFPE with zero max_packet_size Thomas Huth
2026-07-20 10:38 ` [PULL 6/7] hw/usb/hcd-xhci: Fix guest-triggerable assert() in xhci_find_stream() Thomas Huth
2026-07-20 10:38 ` [PULL 7/7] hw/usb/hcd-xhci-sysbus: Fix OOB heap access in xhci_sysbus_intr_raise() Thomas Huth
2026-07-20 17:11 ` [PULL 0/7] USB-related bug fixes Stefan Hajnoczi
2026-07-20 19:08 ` Michael Tokarev
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=20260720103833.364506-5-thuth@redhat.com \
--to=thuth@redhat.com \
--cc=bea1e@proton.me \
--cc=marcandre.lureau@redhat.com \
--cc=qemu-devel@nongnu.org \
--cc=stefanha@redhat.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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.