From 9f1b6d013d42b112680b435af9a9dff331b3fbaf Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Fri, 17 Apr 2026 15:26:45 +0200 Subject: [PATCH] libvduse: fix buffer overflow in vduse_queue_read_indirect_desc() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Signed-off-by: Stefano Garzarella Reviewed-by: Daniel P. Berrangé Reviewed-by: Michael S. Tsirkin Signed-off-by: Michael S. Tsirkin Message-Id: <20260417132645.121192-3-sgarzare@redhat.com> --- subprojects/libvduse/libvduse.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/subprojects/libvduse/libvduse.c b/subprojects/libvduse/libvduse.c index 21ffbb5b8d..df9ca5e56f 100644 --- a/subprojects/libvduse/libvduse.c +++ b/subprojects/libvduse/libvduse.c @@ -465,8 +465,9 @@ static int vduse_queue_read_indirect_desc(VduseDev *dev, struct vring_desc *desc, uint64_t addr, size_t len) { - struct vring_desc *ori_desc; + char *dst_desc = (char *)desc; uint64_t read_len; + void *ori_desc; if (len > (VIRTQUEUE_MAX_SIZE * sizeof(struct vring_desc))) { return -1; @@ -483,10 +484,10 @@ vduse_queue_read_indirect_desc(VduseDev *dev, struct vring_desc *desc, return -1; } - memcpy(desc, ori_desc, read_len); + memcpy(dst_desc, ori_desc, read_len); len -= read_len; addr += read_len; - desc += read_len; + dst_desc += read_len; } return 0;