@samitouri / QOSamiQemu / commits / 9f1b6d013d

libvduse: fix buffer overflow in vduse_queue_read_indirect_desc()

vduse_queue_read_indirect_desc() copies an indirect descriptor table into a buffer in chunks when the table crosses a memory region boundary. The destination is a struct vring_desc pointer but is advanced by a byte count, so each increment moves the pointer by read_len elements instead of read_len bytes, writing beyond the buffer. Use a char pointer for the destination so that the arithmetic advances correctly. While at it, change the source from a struct vring_desc pointer to a void pointer: when the table is split across regions, iova_to_va() can return a pointer into the middle of a descriptor, so casting it to a struct vring_desc pointer is wrong. The pointer is only used as a memcpy() source, so a void pointer is fine. Fixes: CVE-2026-6425 Fixes: a6caeee811 ("libvduse: Add VDUSE (vDPA Device in Userspace) library") Cc: qemu-stable@nongnu.org Reported-by: DARKNAVY <vr@darknavy.com> Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-Id: <20260417132645.121192-3-sgarzare@redhat.com>

Stefano Garzarella committed Apr 17, 2026 at 15:26 UTC 9f1b6d013d42b112680b435af9a9dff331b3fbaf
1 file changed +4 -3
subprojects/libvduse/libvduse.c
+4 -3
@@ -465,8 +465,9 @@ static int
465 vduse_queue_read_indirect_desc(VduseDev *dev, struct vring_desc *desc,
466 uint64_t addr, size_t len)
467 {
468 - struct vring_desc *ori_desc;
468 + char *dst_desc = (char *)desc;
469 uint64_t read_len;
470 + void *ori_desc;
471
472 if (len > (VIRTQUEUE_MAX_SIZE * sizeof(struct vring_desc))) {
473 return -1;
@@ -483,10 +484,10 @@ vduse_queue_read_indirect_desc(VduseDev *dev, struct vring_desc *desc,
484 return -1;
485 }
486
486 - memcpy(desc, ori_desc, read_len);
487 + memcpy(dst_desc, ori_desc, read_len);
488 len -= read_len;
489 addr += read_len;
489 - desc += read_len;
490 + dst_desc += read_len;
491 }
492
493 return 0;