[PATCH] hw/usb/dev-uas: Don't abort if guest provided an undersized buffer for status
Thomas Huth <[email protected]> Thu, 30 Jul 2026 18:39:01 +0200
| Newsgroups | org.nongnu.qemu-trivial,org.nongnu.qemu-devel |
|---|---|
| Message-ID | <[email protected]> |
From: Thomas Huth <[email protected]> QEMU currently aborts if the guest provides an undersized buffer for the status packet (8 bytes): hw/usb/core.c:623: usb_packet_copy: Assertion `p->actual_length + bytes <= iov->size' failed. If we hit this situation, log a guest error and continue by simply only providing the bytes that the guest asked for. (Note: This is e.g. similar to the UAS_PIPE_ID_COMMAND case that also clamps the length with: length = MIN(sizeof(iu), p->iov.size)) Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3900 Reported-by: Feifan Qian <[email protected]> Signed-off-by: Thomas Huth <[email protected]> --- hw/usb/dev-uas.c | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/hw/usb/dev-uas.c b/hw/usb/dev-uas.c index 963c0433b38..be8c3667e83 100644 --- a/hw/usb/dev-uas.c +++ b/hw/usb/dev-uas.c @@ -359,6 +359,7 @@ static void usb_uas_send_status_bh(void *opaque) UASDevice *uas = opaque; UASStatus *st; USBPacket *p; + uint32_t length; while ((st = QTAILQ_FIRST(&uas->results)) != NULL) { if (uas_using_streams(uas)) { @@ -373,7 +374,14 @@ static void usb_uas_send_status_bh(void *opaque) break; } - usb_packet_copy(p, &st->status, st->length); + length = st->length; + if (length > p->iov.size) { + qemu_log_mask(LOG_GUEST_ERROR, + "usb uas: packet (%zd) too small for status (%d)\n", + p->iov.size, length); + length = p->iov.size; + } + usb_packet_copy(p, &st->status, length); QTAILQ_REMOVE(&uas->results, st, next); g_free(st); @@ -875,7 +883,14 @@ static void usb_uas_handle_data(USBDevice *dev, USBPacket *p) break; } } - usb_packet_copy(p, &st->status, st->length); + length = st->length; + if (length > p->iov.size) { + qemu_log_mask(LOG_GUEST_ERROR, + "usb uas: packet (%zd) too small for status (%d)\n", + p->iov.size, length); + length = p->iov.size; + } + usb_packet_copy(p, &st->status, length); QTAILQ_REMOVE(&uas->results, st, next); g_free(st); break; -- 2.55.0