@samitouri / QOSamiQemu / commits / 85805ee887

libvhost-user: fix buffer overflow in virtqueue_read_indirect_desc()

virtqueue_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, vu_gpa_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: 293084a719 ("libvhost-user: Support across-memory-boundary access") 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-2-sgarzare@redhat.com>

Stefano Garzarella committed Apr 17, 2026 at 15:26 UTC 85805ee887be4adddb1f1a34f526968adc95e582
1 file changed +4 -3
subprojects/libvhost-user/libvhost-user.c
+4 -3
@@ -2391,8 +2391,9 @@ static int
2391 virtqueue_read_indirect_desc(VuDev *dev, struct vring_desc *desc,
2392 uint64_t addr, size_t len)
2393 {
2394 - struct vring_desc *ori_desc;
2394 + char *dst_desc = (char *)desc;
2395 uint64_t read_len;
2396 + void *ori_desc;
2397
2398 if (len > (VIRTQUEUE_MAX_SIZE * sizeof(struct vring_desc))) {
2399 return -1;
@@ -2409,10 +2410,10 @@ virtqueue_read_indirect_desc(VuDev *dev, struct vring_desc *desc,
2410 return -1;
2411 }
2412
2412 - memcpy(desc, ori_desc, read_len);
2413 + memcpy(dst_desc, ori_desc, read_len);
2414 len -= read_len;
2415 addr += read_len;
2415 - desc += read_len;
2416 + dst_desc += read_len;
2417 }
2418
2419 return 0;