The packed-ring indirect descriptor handling in
virtqueue_packed_get_avail_bytes() and virtqueue_packed_pop() accepts
desc.len == 0, so a zero-length indirect descriptor reaches
address_space_cache_init(), triggers its len > 0 assertion, and aborts
QEMU.
Harmless except if the driver is in guest userspace, then it's a DoS
attack on the guest.
Check and reject desc.len == 0 - also matches the split-ring behaviour.
Fixes: CVE-2026-63324
Fixes: 86044b24e8 ("virtio: basic packed virtqueue support")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3754
Cc: Jason Wang <jasowangio@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
hw/virtio/virtio.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 7c19080db5..2d33622daf 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -1475,7 +1475,7 @@ static void virtqueue_packed_get_avail_bytes(VirtQueue *vq,
}
if (desc.flags & VRING_DESC_F_INDIRECT) {
- if (desc.len % sizeof(VRingPackedDesc)) {
+ if (!desc.len || (desc.len % sizeof(VRingPackedDesc))) {
virtio_error(vdev, "Invalid size for indirect buffer table");
goto err;
}
@@ -1927,7 +1927,7 @@ static void *virtqueue_packed_pop(VirtQueue *vq, size_t sz)
vring_packed_desc_read(vdev, &desc, desc_cache, i, true);
id = desc.id;
if (desc.flags & VRING_DESC_F_INDIRECT) {
- if (desc.len % sizeof(VRingPackedDesc)) {
+ if (!desc.len || (desc.len % sizeof(VRingPackedDesc))) {
virtio_error(vdev, "Invalid size for indirect buffer table");
goto done;
}
--
MST