Commit 59cb510910 for qemu.org

commit 59cb5109101330fdc4588cbd5a081deeed0cd493
Author: Haotian Jiang <sundayjiang@tencent.com>
Date:   Fri Oct 16 15:04:05 2026 +0200

    usb-host: free request on libusb submit failure

    When libusb_submit_transfer() fails in usb_host_handle_control() or
    usb_host_handle_data(), the USBHostRequest already queued via
    usb_host_req_alloc() is never freed and its r->p pointer is never
    cleared.  The caller (xHCI) may then complete and free the
    XHCITransfer that embeds the USBPacket r->p points to, leaving a
    dangling pointer in s->requests.  A subsequent
    usb_host_abort_xfers() -> usb_host_req_abort() dereferences
    r->p->state on already-freed memory.

    Call usb_host_req_free(r) before returning, matching the existing
    pattern in the #else branch of the BULK_STREAMS case.

    Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3595
    Fixes: 2b2325ff6491 ("use libusb for usb-host")
    Reported-by: Haotian Jiang of Tencent Security (Yunding Lab) <sundayjiang@tencent.com>
    Signed-off-by: Haotian Jiang <sundayjiang@tencent.com>
    Cc: qemu-stable@nongnu.org

diff --git a/hw/usb/host-libusb.c b/hw/usb/host-libusb.c
index cd566b91a3..bddd50903a 100644
--- a/hw/usb/host-libusb.c
+++ b/hw/usb/host-libusb.c
@@ -1526,6 +1526,13 @@ static void usb_host_handle_control(USBDevice *udev, USBPacket *p,
                                  CONTROL_TIMEOUT);
     rc = libusb_submit_transfer(r->xfer);
     if (rc != 0) {
+        /*
+         * Free the request to avoid a dangling r->p pointer.
+         * When libusb_submit_transfer fails the caller (xHCI) may
+         * free the XHCITransfer that holds the USBPacket r->p points
+         * to, so we must remove r from s->requests before returning.
+         */
+        usb_host_req_free(r);
         p->status = USB_RET_NODEV;
         trace_usb_host_req_complete(s->bus_num, s->addr, p,
                                     p->status, p->actual_length);
@@ -1620,6 +1627,13 @@ static void usb_host_handle_data(USBDevice *udev, USBPacket *p)

     rc = libusb_submit_transfer(r->xfer);
     if (rc != 0) {
+        /*
+         * Free the request to avoid a dangling r->p pointer.
+         * When libusb_submit_transfer fails the caller (xHCI) may
+         * free the XHCITransfer that holds the USBPacket r->p points
+         * to, so we must remove r from s->requests before returning.
+         */
+        usb_host_req_free(r);
         p->status = USB_RET_NODEV;
         trace_usb_host_req_complete(s->bus_num, s->addr, p,
                                     p->status, p->actual_length);