Commit f91b0544fe for qemu.org

commit f91b0544fe1f9fbabf582ccaaecc08877b7e19e1
Author: Thomas Huth <thuth@redhat.com>
Date:   Tue Sep 15 13:22:13 2026 +0200

    hw/usb/hcd-xhci: Set reentrancy guard in timer functions (CVE-2026-17588)

    The xHCI controller processes USB events from timer callbacks
    (xhci_mfwrap_timer and xhci_ep_kick_timer) outside of any MMIO handler
    context. The device's mem_reentrancy_guard is therefore not engaged
    during this processing.

    A malicious guest can exploit this by pointing the event ring base
    address (er_start) at the xHCI doorbell MMIO region. When
    xhci_write_event() performs a DMA write to deliver a transfer
    completion event, the write lands on doorbell register 0. If the
    written value is 0, this triggers xhci_process_commands() reentrantly.
    A CR_DISABLE_SLOT command prepared on the command ring then frees
    endpoint and transfer objects via xhci_disable_ep() / g_free() while
    the outer call stack still holds references to them, causing a
    heap use-after-free.

    Fix this by setting engaged_in_io on the device's mem_reentrancy_guard
    around the processing in these non-MMIO entry points. This mirrors
    the protection that EHCI, DWC2, and UHCI already have via
    qemu_bh_new_guarded(). With the guard active, the memory subsystem's
    automatic reentrancy check (system/memory.c) blocks DMA writes that
    would dispatch into the device's own MMIO handlers.

    CVE: CVE-2026-17588
    Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3926
    Reported-by: XlabAI Team of Tencent Xuanwu Lab <xlabai@tencent.com>,
        Guannan Wang <wgnbuaa@gmail.com>, Zhanpeng Liu <pkugenuine@gmail.com>,
        Jiashuo Liang <761232680@qq.com>, Guancheng Li <lgcpku@gmail.com>
    Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4195
    Reported By: Ken Hsu and Royce Lu of Palo Alto Networks
    Message-ID: <20260915112213.525283-1-thuth@redhat.com>
    Signed-off-by: Thomas Huth <thuth@redhat.com>

diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c
index d342aa2739..12f8ffece0 100644
--- a/hw/usb/hcd-xhci.c
+++ b/hw/usb/hcd-xhci.c
@@ -456,9 +456,15 @@ static void xhci_mfwrap_timer(void *opaque)
 {
     XHCIState *xhci = opaque;
     XHCIEvent wrap = { ER_MFINDEX_WRAP, CC_SUCCESS };
+    MemReentrancyGuard *guard = &xhci->parent.mem_reentrancy_guard;
+
+    assert(!guard->engaged_in_io);
+    guard->engaged_in_io = true;

     xhci_event(xhci, &wrap, 0);
     xhci_mfwrap_update(xhci);
+
+    guard->engaged_in_io = false;
 }

 static void xhci_die(XHCIState *xhci)
@@ -1086,7 +1092,14 @@ static void xhci_set_ep_state(XHCIState *xhci, XHCIEPContext *epctx,
 static void xhci_ep_kick_timer(void *opaque)
 {
     XHCIEPContext *epctx = opaque;
+    MemReentrancyGuard *guard = &epctx->xhci->parent.mem_reentrancy_guard;
+
+    assert(!guard->engaged_in_io);
+    guard->engaged_in_io = true;
+
     xhci_kick_epctx(epctx, 0);
+
+    guard->engaged_in_io = false;
 }

 static XHCIEPContext *xhci_alloc_epctx(XHCIState *xhci,