From: Thomas Huth <[email protected]> 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 <[email protected]> Reviewed-by: Peter Maydell <[email protected]> Signed-off-by: Thomas Huth <[email protected]> Message-ID: <[email protected]> --- hw/usb/hcd-xhci.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hw/usb/hcd-xhci.c b/hw/usb/hcd-xhci.c index 569386b8cf1..d342aa2739e 100644 --- a/hw/usb/hcd-xhci.c +++ b/hw/usb/hcd-xhci.c @@ -1464,7 +1464,8 @@ static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer) switch (TRB_TYPE(*trb)) { case TR_DATA: if ((!(trb->control & TRB_TR_DIR)) != (!in_xfer)) { - DPRINTF("xhci: data direction mismatch for TR_DATA\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "xhci: data direction mismatch for TR_DATA\n"); goto err; } /* fallthrough */ @@ -1474,7 +1475,8 @@ static int xhci_xfer_create_sgl(XHCITransfer *xfer, int in_xfer) chunk = trb->status & 0x1ffff; if (trb->control & TRB_TR_IDT) { if (chunk > 8 || in_xfer) { - DPRINTF("xhci: invalid immediate data TRB\n"); + qemu_log_mask(LOG_GUEST_ERROR, + "xhci: invalid immediate data TRB\n"); goto err; } qemu_sglist_add(&xfer->sgl, trb->addr, chunk); @@ -1617,7 +1619,9 @@ static int xhci_setup_packet(XHCITransfer *xfer) } } - xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN); /* Also sets int_req */ + if (xhci_xfer_create_sgl(xfer, dir == USB_TOKEN_IN) < 0) { /* Also sets int_req */ + return -1; + } usb_packet_setup(&xfer->packet, dir, ep, xfer->streamid, xfer->trbs[0].addr, false, xfer->int_req); if (usb_packet_map(&xfer->packet, &xfer->sgl)) { -- 2.55.0
