@samitouri / QOSamiQemu / commits / 92abc3c51e

hw/usb/hcd-xhci: Check return value of xhci_xfer_create_sgl() for errors

xhci_xfer_create_sgl() can fail if a guest programmed the XHCI in a weird way. The current code ignores this error, and this triggers an assert() shortly afterwards: hw/usb/core.c:612: usb_packet_copy: Assertion `p->actual_length + bytes <= iov->size' failed. Fix it by handling the error correctly (i.e. return with an error to the caller). While we're at it, change the DPRINTF statements in xhci_xfer_create_sgl() into proper qemu_log_mask() statements, so we have a better way to detect this situation. Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3786 Reported-by: Feifan Qian <bea1e@proton.me> Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Thomas Huth <thuth@redhat.com> Message-ID: <20260724110933.629791-1-thuth@redhat.com>

Thomas Huth committed Jul 24, 2026 at 13:09 UTC 92abc3c51ebb3223a6fdb5bd3414b2943d7653b2
1 file changed +7 -3
hw/usb/hcd-xhci.c
+7 -3
@@ -1464,7 +1464,8 @@ static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer)
1464 switch (TRB_TYPE(*trb)) {
1465 case TR_DATA:
1466 if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) {
1467 - DPRINTF("xhci: data direction mismatch for TR_DATA\n");
1467 + qemu_log_mask(LOG_GUEST_ERROR,
1468 + "xhci: data direction mismatch for TR_DATA\n");
1469 goto err;
1470 }
1471 /* fallthrough */
@@ -1474,7 +1475,8 @@ static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer)
1475 chunk = trb->status & 0x1ffff;
1476 if (trb->control & TRB_TR_IDT) {
1477 if (chunk > 8 || in_xfer) {
1477 - DPRINTF("xhci: invalid immediate data TRB\n");
1478 + qemu_log_mask(LOG_GUEST_ERROR,
1479 + "xhci: invalid immediate data TRB\n");
1480 goto err;
1481 }
1482 qemu_sglist_add(&xfer->sgl, trb->addr, chunk);
@@ -1617,7 +1619,9 @@ static int xhci_setup_packet(XHCITransfer *xfer)
1619 }
1620 }
1621
1620 - xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */
1622 + if (xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN) < 0) { /* Also sets int_req */
1623 + return -1;
1624 + }
1625 usb_packet_setup(&xfer->packet, dir, ep, xfer->streamid,
1626 xfer->trbs[0].addr, false, xfer->int_req);
1627 if (usb_packet_map(&xfer->packet, &xfer->sgl)) {