From: "Denis V. Lunev" <den@openvz.org>
To: andrey.drobyshev@virtuozzo.com
Cc: svt-core@virtuozzo.com, den@openvz.org
Subject: [PATCH hci-8.1 3/3] hw/usb/hcd-xhci: More reentrancy guard fixes for the XHCI code #VSTOR-151666
Date: Mon, 26 Oct 2026 12:46:45 +0100 [thread overview]
Message-ID: <20261026114645.187003-4-den@openvz.org> (raw)
In-Reply-To: <20261026114645.187003-1-den@openvz.org>
From: Thomas Huth <thuth@redhat.com>
The XHCI controller's USB port and bus callbacks -- xhci_complete(),
xhci_wakeup_endpoint(), xhci_attach(), xhci_detach(), and
xhci_wakeup() -- can be invoked from outside any MMIO handler context.
The device's mem_reentrancy_guard is therefore not engaged during
this processing.
A malicious guest can exploit this gap via MSI-X self-targeting: it
programs the MSI-X vector's message address to point at the XHCI
doorbell register array (both reside in the same BAR0 MemoryRegion).
When any of these callbacks posts an event via xhci_event() ->
xhci_intr_raise(), the resulting msix_notify() -> pci_msi_trigger()
issues an address_space_stl_le() that writes doorbell 0, triggering
xhci_process_commands() reentrantly. A CR_DISABLE_SLOT command
planted on the command ring then frees XHCITransfer/XHCIEPContext
objects that the outer call stack still references, causing a
heap use-after-free.
Fix this by setting engaged_in_io on the device's mem_reentrancy_guard
around the processing in all five callbacks. The guard is set
conditionally (only when not already engaged) because these callbacks
may also be reached from within a guarded MMIO context.
xhci_child_detach() is intentionally left unguarded: it only calls
xhci_detach_slot() which passes report=0 to xhci_ep_nuke_xfers(),
suppressing event generation, so it never reaches xhci_event().
Note: This is similar to the fixes done for CVE-2026-17588, see
f91b0544fe ("Set reentrancy guard in timer functions").
CVE: CVE-2026-111819
Message-ID: <20261020114031.687929-1-thuth@redhat.com>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4625
Reported-by: Ken Hsu, Royce Lu, and Bo Qu of Palo Alto Networks
Buglink: https://gitlab.com/qemu-project/qemu/-/work_items/4642
Reported-by: Nikhil Agrawal <nikhil.agrawal@mettlelabs.ai>
Signed-off-by: Thomas Huth <thuth@redhat.com>
(cherry picked from commit cfa70f3a82f581ad758586ecf408fe7f3602850f)
---
hw/usb/hcd-xhci.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index 80d2687fb19..8017ddcebd0 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -3243,49 +3243,73 @@ static const MemoryRegionOps xhci_doorbell_ops = {
.endianness = DEVICE_LITTLE_ENDIAN,
};
+static bool xhci_engage_reentrancy_guard(XHCIState *xhci)
+{
+ bool prev_engaged = xhci->parent.mem_reentrancy_guard.engaged_in_io;
+
+ xhci->parent.mem_reentrancy_guard.engaged_in_io = true;
+ return prev_engaged;
+}
+
+static void xhci_restore_reentrancy_guard(XHCIState *xhci, bool engaged)
+{
+ xhci->parent.mem_reentrancy_guard.engaged_in_io = engaged;
+}
+
static void xhci_attach(USBPort *usbport)
{
XHCIState *xhci = usbport->opaque;
XHCIPort *port = xhci_lookup_port(xhci, usbport);
+ bool prev_engaged = xhci_engage_reentrancy_guard(xhci);
xhci_port_update(port, 0);
+ xhci_restore_reentrancy_guard(xhci, prev_engaged);
}
static void xhci_detach(USBPort *usbport)
{
XHCIState *xhci = usbport->opaque;
XHCIPort *port = xhci_lookup_port(xhci, usbport);
+ bool prev_engaged = xhci_engage_reentrancy_guard(xhci);
xhci_detach_slot(xhci, usbport);
xhci_port_update(port, 1);
+ xhci_restore_reentrancy_guard(xhci, prev_engaged);
}
static void xhci_wakeup(USBPort *usbport)
{
XHCIState *xhci = usbport->opaque;
XHCIPort *port = xhci_lookup_port(xhci, usbport);
+ bool prev_engaged;
assert(port);
if (get_field(port->portsc, PORTSC_PLS) != PLS_U3) {
return;
}
+ prev_engaged = xhci_engage_reentrancy_guard(xhci);
set_field(&port->portsc, PLS_RESUME, PORTSC_PLS);
xhci_port_notify(port, PORTSC_PLC);
+ xhci_restore_reentrancy_guard(xhci, prev_engaged);
}
static void xhci_complete(USBPort *port, USBPacket *packet)
{
XHCITransfer *xfer = container_of(packet, XHCITransfer, packet);
+ XHCIState *xhci = xfer->epctx->xhci;
+ bool prev_engaged;
if (packet->status == USB_RET_REMOVE_FROM_QUEUE) {
xhci_ep_nuke_one_xfer(xfer, 0);
return;
}
+ prev_engaged = xhci_engage_reentrancy_guard(xhci);
xhci_try_complete_packet(xfer);
xhci_kick_epctx(xfer->epctx, xfer->streamid);
if (xfer->complete) {
xhci_ep_free_xfer(xfer);
}
+ xhci_restore_reentrancy_guard(xhci, prev_engaged);
}
static void xhci_child_detach(USBPort *uport, USBDevice *child)
@@ -3337,6 +3361,7 @@ static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
{
XHCIState *xhci = container_of(bus, XHCIState, bus);
int slotid;
+ bool prev_engaged;
DPRINTF("%s\n", __func__);
slotid = ep->dev->addr;
@@ -3345,7 +3370,9 @@ static void xhci_wakeup_endpoint(USBBus *bus, USBEndpoint *ep,
DPRINTF("%s: oops, no slot for dev %d\n", __func__, ep->dev->addr);
return;
}
+ prev_engaged = xhci_engage_reentrancy_guard(xhci);
xhci_kick_ep(xhci, slotid, xhci_find_epid(ep), stream);
+ xhci_restore_reentrancy_guard(xhci, prev_engaged);
}
static USBBusOps xhci_bus_ops = {
--
2.53.0
next prev parent reply other threads:[~2026-10-26 11:47 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-26 11:46 [PATCH hci-8.1 0/3] hw/usb/hcd-xhci: fix guest-triggerable use-after-free (CVE-2026-17588, CVE-2026-111819) #VSTOR-151666 Denis V. Lunev
2026-10-26 11:46 ` [PATCH hci-8.1 1/3] hw/usb/hcd-xhci: Set reentrancy guard in timer functions (CVE-2026-17588) #VSTOR-151666 Denis V. Lunev
2026-10-26 11:51 ` no-reply
2026-10-26 11:46 ` [PATCH hci-8.1 2/3] hw/usb/hcd-xhci: Limit DMA transfers to plain memory #VSTOR-151666 Denis V. Lunev
2026-10-26 11:50 ` no-reply
2026-10-26 11:46 ` Denis V. Lunev [this message]
2026-10-26 11:53 ` [PATCH hci-8.1 3/3] hw/usb/hcd-xhci: More reentrancy guard fixes for the XHCI code #VSTOR-151666 no-reply
2026-10-26 16:13 ` [PATCH hci-8.1 0/3] hw/usb/hcd-xhci: fix guest-triggerable use-after-free (CVE-2026-17588, CVE-2026-111819) #VSTOR-151666 Andrey Drobyshev
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=20261026114645.187003-4-den@openvz.org \
--to=den@openvz.org \
--cc=andrey.drobyshev@virtuozzo.com \
--cc=svt-core@virtuozzo.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.