* [PULL 01/30] virtio: use masked features with set_features_ex
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 02/30] virtio-net: fix OOB read in RSC receive path Michael S. Tsirkin
` (29 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Jason Wang, Yuri Benditovich, Paolo Abeni
virtio_set_features_nocheck() calls set_features_ex
with guest-supplied feature bits, without masking the value
with host features (unlike set_features which gets the
correct val & host_features).
This does not matter if the driver matches spec, but drivers
can be malicious or buggy and set bit outside the host mask.
Devices don't expect this, so unsupported guest feature bits getting set
can break the host. In virtio-net, this can enable RSC without vnet
header support and cause out-of-bounds reads from short packets.
Pass the masked features to set_features_ex, consistent with set_features.
Fixes: CVE-2026-63321
Fixes: 64a6a336f4 ("virtio: add support for negotiating extended features")
Cc: Jason Wang <jasowangio@gmail.com>
Cc: Yuri Benditovich <ybendito@redhat.com>
Cc: Paolo Abeni <pabeni@redhat.com>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3623
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <dfd27c9b26e442a2076f6ddc9bb3d38363d9b2da.1784891251.git.mst@redhat.com>
---
hw/virtio/virtio.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index f4d86a3655..7c19080db5 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -3320,7 +3320,7 @@ static int virtio_set_features_nocheck(VirtIODevice *vdev, const uint64_t *val)
virtio_features_and(tmp, val, vdev->host_features_ex);
if (k->set_features_ex) {
- k->set_features_ex(vdev, val);
+ k->set_features_ex(vdev, tmp);
} else if (k->set_features) {
bad = bad || virtio_features_use_ex(tmp);
k->set_features(vdev, tmp[0]);
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 02/30] virtio-net: fix OOB read in RSC receive path
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 01/30] virtio: use masked features with set_features_ex Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 03/30] virtio-net: fix short frame OOB read in receive_filter() Michael S. Tsirkin
` (28 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Jason Wang, Yuri Benditovich, Wei Xu
The RSC receive path parses incoming frames at guest_hdr_len byte
offsets, but the backend buffer contains only host_hdr_len bytes of vnet
header. If the lengths differ, RSC would read at the wrong offset and
cause an OOB read.
This is no longer possible after the previous patch, but the assumption
seem fragile. Along the defense in depth lines, let's validate. To
ensure we are not breaking any valid setups by mistake, warn and fall
back to the normal receive path when host_hdr_len != guest_hdr_len.
Fixes: CVE-2026-63321
Fixes: 2974e916df ("virtio-net: support RSC v4/v6 tcp traffic for Windows HCK")
Cc: Jason Wang <jasowangio@gmail.com>
Cc: Yuri Benditovich <ybendito@redhat.com>
Cc: Wei Xu <wexu@redhat.com>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3623
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <f261dcd535edc890f8636d8ae5ac1007bc32b8b4.1784891251.git.mst@redhat.com>
---
hw/net/virtio-net.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index f0e3beb290..2761644dfd 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -2674,6 +2674,13 @@ static ssize_t virtio_net_receive(NetClientState *nc, const uint8_t *buf,
{
VirtIONet *n = qemu_get_nic_opaque(nc);
if ((n->rsc4_enabled || n->rsc6_enabled)) {
+ /* this never happens with existing backends, but just in case. */
+ if (n->host_hdr_len != n->guest_hdr_len) {
+ warn_report_once("virtio-net: host_hdr_len %zu != guest_hdr_len %zu, "
+ "skipping RSC",
+ n->host_hdr_len, n->guest_hdr_len);
+ return virtio_net_do_receive(nc, buf, size);
+ }
return virtio_net_rsc_receive(nc, buf, size);
} else {
return virtio_net_do_receive(nc, buf, size);
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 03/30] virtio-net: fix short frame OOB read in receive_filter()
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 01/30] virtio: use masked features with set_features_ex Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 02/30] virtio-net: fix OOB read in RSC receive path Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 04/30] libvhost-user: protect against OOB writes in vu_set_inflight_fd Michael S. Tsirkin
` (27 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Jason Wang, Alex Williamson
Within virtio-net, receive_filter() reads Ethernet header fields without
any length checks.
But virtio-net sets do_not_pad in NetClientState, so backends such as
socket forward frames at the size supplied by the peer without padding
to the Ethernet minimum. A short frame thus causes an out-of-bounds
read.
Add size checks in receive_filter() and drop the truncated frames.
Fixes: CVE-2026-63320
Fixes: 3831ab2094 ("qemu:virtio-net: Enable filtering based on MAC, promisc, broadcast and allmulti (Alex Williamson)")
Cc: Jason Wang <jasowangio@gmail.com>
Cc: Alex Williamson <alex@shazbot.org>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3626
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <ee5c77b96ab66b2dd518f146def8727216a5c495.1784895727.git.mst@redhat.com>
---
hw/net/virtio-net.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 2761644dfd..7e0c984ec6 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -1744,10 +1744,21 @@ static int receive_filter(VirtIONet *n, const uint8_t *buf, int size)
if (n->promisc)
return 1;
+ if (size < n->host_hdr_len + 14) {
+ /* Truncated ethernet packet */
+ return 0;
+ }
+
ptr += n->host_hdr_len;
if (!memcmp(&ptr[12], vlan, sizeof(vlan))) {
- int vid = lduw_be_p(ptr + 14) & 0xfff;
+ int vid;
+
+ /* Truncated vlan packet */
+ if (size < n->host_hdr_len + 16) {
+ return 0;
+ }
+ vid = lduw_be_p(ptr + 14) & 0xfff;
if (!(n->vlans[vid >> 5] & (1U << (vid & 0x1f))))
return 0;
}
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 04/30] libvhost-user: protect against OOB writes in vu_set_inflight_fd
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (2 preceding siblings ...)
2026-07-26 21:29 ` [PULL 03/30] virtio-net: fix short frame OOB read in receive_filter() Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 05/30] libvhost-user: protect against OOB vring queue access Michael S. Tsirkin
` (26 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Stefano Garzarella
vu_set_inflight_fd() trusts the num_queues value from the
VHOST_USER_SET_INFLIGHT_FD message without checking it against
dev->max_queues, so an oversized value causes out-of-bounds writes to
dev->vq.
Front end is generally trusted so not a security problem, but OOB isn't
a nice way to handle frontend bugs. Let's harden this a bit:
check num_queues and panic if it's invalid.
Fixes: 5f9ff1eff3 ("libvhost-user: Support tracking inflight I/O in shared memory")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3740
Cc: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <23b3f12388c1035f208550df9de9944c22d8d534.1784899127.git.mst@redhat.com>
---
subprojects/libvhost-user/libvhost-user.c | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c
index 2c35bddd6f..8208265588 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -1998,6 +1998,8 @@ vu_get_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
if (vmsg->size != sizeof(vmsg->payload.inflight)) {
vu_panic(dev, "Invalid get_inflight_fd message:%d", vmsg->size);
+ vmsg_close_fds(vmsg);
+ vmsg->fd_num = 0;
vmsg->payload.inflight.mmap_size = 0;
return true;
}
@@ -2005,6 +2007,15 @@ vu_get_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
num_queues = vmsg->payload.inflight.num_queues;
queue_size = vmsg->payload.inflight.queue_size;
+ if (num_queues > dev->max_queues) {
+ vu_panic(dev, "Invalid get_inflight_fd num_queues: %"PRId16,
+ num_queues);
+ vmsg_close_fds(vmsg);
+ vmsg->fd_num = 0;
+ vmsg->payload.inflight.mmap_size = 0;
+ return true;
+ }
+
DPRINT("set_inflight_fd num_queues: %"PRId16"\n", num_queues);
DPRINT("set_inflight_fd queue_size: %"PRId16"\n", queue_size);
@@ -2052,6 +2063,7 @@ vu_set_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
vmsg->size != sizeof(vmsg->payload.inflight)) {
vu_panic(dev, "Invalid set_inflight_fd message size:%d fds:%d",
vmsg->size, vmsg->fd_num);
+ vmsg_close_fds(vmsg);
return false;
}
@@ -2061,6 +2073,13 @@ vu_set_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
num_queues = vmsg->payload.inflight.num_queues;
queue_size = vmsg->payload.inflight.queue_size;
+ if (num_queues > dev->max_queues) {
+ vu_panic(dev, "Invalid set_inflight_fd num_queues: %"PRId16,
+ num_queues);
+ close(fd);
+ return false;
+ }
+
DPRINT("set_inflight_fd mmap_size: %"PRId64"\n", mmap_size);
DPRINT("set_inflight_fd mmap_offset: %"PRId64"\n", mmap_offset);
DPRINT("set_inflight_fd num_queues: %"PRId16"\n", num_queues);
@@ -2071,6 +2090,7 @@ vu_set_inflight_fd(VuDev *dev, VhostUserMsg *vmsg)
if (rc == MAP_FAILED) {
vu_panic(dev, "set_inflight_fd mmap error: %s", strerror(errno));
+ close(fd);
return false;
}
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 05/30] libvhost-user: protect against OOB vring queue access
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (3 preceding siblings ...)
2026-07-26 21:29 ` [PULL 04/30] libvhost-user: protect against OOB writes in vu_set_inflight_fd Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 06/30] hw/virtio: reject zero-length packed indirect descriptor table Michael S. Tsirkin
` (25 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Stefano Garzarella
SET_VRING_NUM, SET_VRING_ADDR, SET_VRING_BASE, and GET_VRING_BASE
handlers all use the queue index from the message to access dev->vq[]
without checking that it is below dev->max_queues, so a malformed
message causes an out-of-bounds heap access.
Frontend is trusted so not a security problem, but
an OOB access is not a nice way to handle errors.
Check, and panic.
Fixes: 7b2e5c65f4 ("contrib: add libvhost-user")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3741
Cc: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <dbba777b25f86587c8d131891a2b4b2be97e5c5b.1784899069.git.mst@redhat.com>
---
subprojects/libvhost-user/libvhost-user.c | 28 ++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c
index 8208265588..42a5e2f1f5 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -1200,6 +1200,12 @@ vu_set_vring_num_exec(VuDev *dev, VhostUserMsg *vmsg)
DPRINT("State.index: %u\n", index);
DPRINT("State.num: %u\n", num);
+
+ if (index >= dev->max_queues) {
+ vu_panic(dev, "Invalid vring_num index: %u", index);
+ return false;
+ }
+
dev->vq[index].vring.num = num;
return false;
@@ -1210,7 +1216,7 @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg)
{
struct vhost_vring_addr addr = vmsg->payload.addr, *vra = &addr;
unsigned int index = vra->index;
- VuVirtq *vq = &dev->vq[index];
+ VuVirtq *vq;
DPRINT("vhost_vring_addr:\n");
DPRINT(" index: %d\n", vra->index);
@@ -1220,6 +1226,12 @@ vu_set_vring_addr_exec(VuDev *dev, VhostUserMsg *vmsg)
DPRINT(" avail_user_addr: 0x%016" PRIx64 "\n", (uint64_t)vra->avail_user_addr);
DPRINT(" log_guest_addr: 0x%016" PRIx64 "\n", (uint64_t)vra->log_guest_addr);
+ if (index >= dev->max_queues) {
+ vu_panic(dev, "Invalid vring_addr index: %u", index);
+ return false;
+ }
+
+ vq = &dev->vq[index];
vq->vra = *vra;
vq->vring.flags = vra->flags;
vq->vring.log_guest_addr = vra->log_guest_addr;
@@ -1256,6 +1268,12 @@ vu_set_vring_base_exec(VuDev *dev, VhostUserMsg *vmsg)
DPRINT("State.index: %u\n", index);
DPRINT("State.num: %u\n", num);
+
+ if (index >= dev->max_queues) {
+ vu_panic(dev, "Invalid vring_base index: %u", index);
+ return false;
+ }
+
dev->vq[index].shadow_avail_idx = dev->vq[index].last_avail_idx = num;
return false;
@@ -1267,6 +1285,14 @@ vu_get_vring_base_exec(VuDev *dev, VhostUserMsg *vmsg)
unsigned int index = vmsg->payload.state.index;
DPRINT("State.index: %u\n", index);
+
+ if (index >= dev->max_queues) {
+ vu_panic(dev, "Invalid vring_base index: %u", index);
+ vmsg->payload.state.num = 0;
+ vmsg->size = sizeof(vmsg->payload.state);
+ return true;
+ }
+
vmsg->payload.state.num = dev->vq[index].last_avail_idx;
vmsg->size = sizeof(vmsg->payload.state);
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 06/30] hw/virtio: reject zero-length packed indirect descriptor table
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (4 preceding siblings ...)
2026-07-26 21:29 ` [PULL 05/30] libvhost-user: protect against OOB vring queue access Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 07/30] vhost: do not crash on ring map failure Michael S. Tsirkin
` (24 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Laurent Vivier, jasowangio, qemu-stable
From: Laurent Vivier <lvivier@redhat.com>
The split-ring path already rejects a zero-length indirect descriptor
table since commit 7423192912af ("virtio: add checks for the size of
the indirect table"). The packed-ring path is missing the same check,
allowing a guest to trigger an assertion in address_space_cache_init()
with a packed indirect descriptor that has len=0.
Add the same !desc.len check to the packed-ring indirect validation
in both virtqueue_packed_get_avail_bytes() and virtqueue_packed_pop().
Fixes: 86044b24e865 ("virtio: basic packed virtqueue support")
Cc: jasowangio@gmail.com
Cc: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3984
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260715115040.2186274-1-lvivier@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
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 07/30] vhost: do not crash on ring map failure
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (5 preceding siblings ...)
2026-07-26 21:29 ` [PULL 06/30] hw/virtio: reject zero-length packed indirect descriptor table Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 08/30] virtio-scsi: fix SCSIRequest leak on a bad request Michael S. Tsirkin
` (23 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Stefano Garzarella, Dr. David Alan Gilbert
When vhost_commit() rebuilds the memory region table after a flatview
change, it revalidates cached host virtual addresses for active vring
parts. If a mapping is stale, QEMU abort().
This is not a security problem - only the priviledged guest
can control make it invalid - but not nice e.g. for driver debugging.
Let's call virtio_error() instead, marking the device as broken.
Fixes: 0ca1fd2d68 ("vhost: Simplify ring verification checks")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3783
Cc: Stefano Garzarella <sgarzare@redhat.com>
Cc: Dr. David Alan Gilbert <dave@treblig.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <71961a7dc157f552303aeea8c99a75c5e1ce904e.1784898432.git.mst@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dave@treblig.org>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
hw/virtio/vhost.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index af41841b52..371dca17dd 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -755,8 +755,9 @@ static void vhost_commit(MemoryListener *listener)
(void *)(uintptr_t)dev->mem->regions[i].userspace_addr,
dev->mem->regions[i].guest_phys_addr,
dev->mem->regions[i].memory_size)) {
- error_report("Verify ring failure on region %d", i);
- abort();
+ virtio_error(dev->vdev,
+ "Verify ring failure on region %d", i);
+ goto out;
}
}
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 08/30] virtio-scsi: fix SCSIRequest leak on a bad request
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (6 preceding siblings ...)
2026-07-26 21:29 ` [PULL 07/30] vhost: do not crash on ring map failure Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 09/30] virtio-mmio: fix QUEUE_NUM_MAX Michael S. Tsirkin
` (22 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Paolo Bonzini, Fam Zheng, Greg Kurz
When virtio_scsi_handle_cmd_vq() cleans up prepared requests after a
malformed element in the same batch, it drops only one reference even
though virtio_scsi_handle_cmd_req_prepare() leaves each unsubmitted
SCSIRequest with two references. This leaks the request and allows
repeated bad batches to cause unbounded host memory growth.
Add a second scsi_req_unref() and clear hba_private first.
Fixes: CVE-2026-61476
Fixes: 661e32fb3c ("virtio-scsi: convert virtio_scsi_bad_req() to use virtio_error()")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3875
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Fam Zheng <fam@euphon.net>
Cc: Greg Kurz <groug@kaod.org>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <5092cd4716e08d29731bfe85eea82a732b837ff4.1784895264.git.mst@redhat.com>
---
include/hw/scsi/scsi.h | 1 +
hw/scsi/scsi-bus.c | 7 +++++++
hw/scsi/virtio-scsi.c | 2 ++
3 files changed, 10 insertions(+)
diff --git a/include/hw/scsi/scsi.h b/include/hw/scsi/scsi.h
index 5f83e58d1d..c60c6e8810 100644
--- a/include/hw/scsi/scsi.h
+++ b/include/hw/scsi/scsi.h
@@ -221,6 +221,7 @@ SCSIRequest *scsi_req_new(SCSIDevice *d, uint32_t tag, uint32_t lun,
int32_t scsi_req_enqueue(SCSIRequest *req);
SCSIRequest *scsi_req_ref(SCSIRequest *req);
void scsi_req_unref(SCSIRequest *req);
+void scsi_req_unref_detach_hba(SCSIRequest *req);
int scsi_bus_parse_cdb(SCSIDevice *dev, SCSICommand *cmd, uint8_t *buf,
size_t buf_len, void *hba_private);
diff --git a/hw/scsi/scsi-bus.c b/hw/scsi/scsi-bus.c
index dccb2f25b2..deb43d5560 100644
--- a/hw/scsi/scsi-bus.c
+++ b/hw/scsi/scsi-bus.c
@@ -1513,6 +1513,13 @@ void scsi_req_unref(SCSIRequest *req)
}
}
+void scsi_req_unref_detach_hba(SCSIRequest *req)
+{
+ /* Unref when the HBA frees hba_private separately (e.g. virtio_scsi_free_req) */
+ req->hba_private = NULL;
+ scsi_req_unref(req);
+}
+
/* Tell the device that we finished processing this chunk of I/O. It
will start the next chunk or complete the command. */
void scsi_req_continue(SCSIRequest *req)
diff --git a/hw/scsi/virtio-scsi.c b/hw/scsi/virtio-scsi.c
index 6c73768011..bf64d1231a 100644
--- a/hw/scsi/virtio-scsi.c
+++ b/hw/scsi/virtio-scsi.c
@@ -931,7 +931,9 @@ static void virtio_scsi_handle_cmd_vq(VirtIOSCSI *s, VirtQueue *vq)
req = QTAILQ_FIRST(&reqs);
QTAILQ_REMOVE(&reqs, req, next);
defer_call_end();
+ /* Drop both the ref from _prepare and the initial ref */
scsi_req_unref(req->sreq);
+ scsi_req_unref_detach_hba(req->sreq);
virtqueue_detach_element(req->vq, &req->elem, 0);
virtio_scsi_free_req(req);
}
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 09/30] virtio-mmio: fix QUEUE_NUM_MAX
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (7 preceding siblings ...)
2026-07-26 21:29 ` [PULL 08/30] virtio-scsi: fix SCSIRequest leak on a bad request Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 10/30] virtio: fix queue size validation against allocated maximum Michael S. Tsirkin
` (21 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Yonggang Luo, Philippe Mathieu-Daudé,
Zhao Liu
virtio-mmio reports VIRTQUEUE_MAX_SIZE (1024) as QUEUE_NUM_MAX for every
queue, regardless of the size the device passes to virtio_add_queue().
This works by accident because QEMU mostly does not care about the ring
size - the guest is the one allocating memory here. But this changes
with in-order vqs where qemu is the one allocating resources.
Now, specifying a larger vq than allocated causes an OOB memory access.
To fix:
- for new machine types, report the actual max queue size to guest
- for old machine types, use a compat property to allocate 1k sized
queues
Fixes: 525d82e323 ("virtio: fix queue size validation against allocated maximum")
Fixes: CVE-2026-50626
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3882
Cc: Peter Maydell <peter.maydell@linaro.org>
Message-ID: <8715acbb9516e67e2a776cda6f9edf105343f788.1784930765.git.mst@redhat.com>
Acked-by: Yonggang Luo <luoyonggang@gmail.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
include/hw/virtio/virtio-bus.h | 1 +
include/hw/virtio/virtio-mmio.h | 1 +
hw/core/machine.c | 1 +
hw/virtio/virtio-mmio.c | 7 +++----
hw/virtio/virtio.c | 11 +++++++++++
5 files changed, 17 insertions(+), 4 deletions(-)
diff --git a/include/hw/virtio/virtio-bus.h b/include/hw/virtio/virtio-bus.h
index 1a2d396156..f80fd71424 100644
--- a/include/hw/virtio/virtio-bus.h
+++ b/include/hw/virtio/virtio-bus.h
@@ -30,6 +30,7 @@
#include "qom/object.h"
#define TYPE_VIRTIO_BUS "virtio-bus"
+#define VIRTIO_QUEUE_SIZE_OVERRIDE "x-override-queue-size"
typedef struct VirtioBusClass VirtioBusClass;
typedef struct VirtioBusState VirtioBusState;
DECLARE_OBJ_CHECKERS(VirtioBusState, VirtioBusClass,
diff --git a/include/hw/virtio/virtio-mmio.h b/include/hw/virtio/virtio-mmio.h
index 1644d09810..0a9069868c 100644
--- a/include/hw/virtio/virtio-mmio.h
+++ b/include/hw/virtio/virtio-mmio.h
@@ -69,6 +69,7 @@ struct VirtIOMMIOProxy {
/* Fields only used for non-legacy (v2) devices */
uint32_t guest_features[2];
VirtIOMMIOQueue vqs[VIRTIO_QUEUE_MAX];
+ uint16_t override_queue_size;
};
#endif
diff --git a/hw/core/machine.c b/hw/core/machine.c
index 805148678d..73b4d82b4a 100644
--- a/hw/core/machine.c
+++ b/hw/core/machine.c
@@ -41,6 +41,7 @@
#include "hw/arm/smmuv3.h"
GlobalProperty hw_compat_11_0[] = {
+ { "virtio-mmio", VIRTIO_QUEUE_SIZE_OVERRIDE, "1024" },
{ "chardev-vc", "encoding", "cp437" },
{ "tpm-crb", "cap-chunk", "off" },
{ "tpm-crb", "x-allow-chunk-migration", "off" },
diff --git a/hw/virtio/virtio-mmio.c b/hw/virtio/virtio-mmio.c
index 58c6d46aab..55ceaeef5f 100644
--- a/hw/virtio/virtio-mmio.c
+++ b/hw/virtio/virtio-mmio.c
@@ -172,10 +172,7 @@ static uint64_t virtio_mmio_read(void *opaque, hwaddr offset, unsigned size)
>> (32 * proxy->host_features_sel);
}
case VIRTIO_MMIO_QUEUE_NUM_MAX:
- if (!virtio_queue_get_num(vdev, vdev->queue_sel)) {
- return 0;
- }
- return VIRTQUEUE_MAX_SIZE;
+ return virtio_queue_get_max_num(vdev, vdev->queue_sel);
case VIRTIO_MMIO_QUEUE_PFN:
if (!proxy->legacy) {
qemu_log_mask(LOG_GUEST_ERROR,
@@ -738,6 +735,8 @@ static const Property virtio_mmio_properties[] = {
DEFINE_PROP_BOOL("force-legacy", VirtIOMMIOProxy, legacy, true),
DEFINE_PROP_BIT("ioeventfd", VirtIOMMIOProxy, flags,
VIRTIO_IOMMIO_FLAG_USE_IOEVENTFD_BIT, true),
+ DEFINE_PROP_UINT16(VIRTIO_QUEUE_SIZE_OVERRIDE, VirtIOMMIOProxy,
+ override_queue_size, 0),
};
static void virtio_mmio_realizefn(DeviceState *d, Error **errp)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 2d33622daf..cdc8ba76f1 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2568,6 +2568,17 @@ VirtQueue *virtio_add_queue(VirtIODevice *vdev, int queue_size,
if (i == VIRTIO_QUEUE_MAX || queue_size > VIRTQUEUE_MAX_SIZE)
abort();
+ BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
+ if (qbus && qbus->parent &&
+ object_property_find(OBJECT(qbus->parent), VIRTIO_QUEUE_SIZE_OVERRIDE)) {
+ int override = object_property_get_int(OBJECT(qbus->parent),
+ VIRTIO_QUEUE_SIZE_OVERRIDE,
+ &error_abort);
+ if (override) {
+ queue_size = override;
+ }
+ }
+
vdev->vq[i].vring.num = queue_size;
vdev->vq[i].vring.num_default = queue_size;
vdev->vq[i].vring.align = VIRTIO_PCI_VRING_ALIGN;
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 10/30] virtio: fix queue size validation against allocated maximum
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (8 preceding siblings ...)
2026-07-26 21:29 ` [PULL 09/30] virtio-mmio: fix QUEUE_NUM_MAX Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 11/30] virtio: stop migrating num_default, validate vring.num on load Michael S. Tsirkin
` (20 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell
virtio_add_queue() allocates used_elems for num_default entries, but
virtio_queue_set_num() accepts larger guest-supplied queue sizes up to
VIRTQUEUE_MAX_SIZE. With VIRTIO_F_IN_ORDER, this lets the guest drive
used_elems accesses past the allocation and cause out-of-bounds reads
and writes.
Reject queue sizes larger than num_default in virtio_queue_set_num()
and mark the device broken.
Fixes: e63c0ba1bc ("virtio: Add support for guest setting of queue size")
Fixes: CVE-2026-50626
Cc: Peter Maydell <peter.maydell@linaro.org>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3882
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3921
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3923
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3613
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <eb7cc3672a20db392f577edbece2300aa6754dd3.1784898967.git.mst@redhat.com>
---
hw/virtio/virtio.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index cdc8ba76f1..4a6430c31c 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2418,6 +2418,11 @@ void virtio_queue_set_num(VirtIODevice *vdev, int n, int num)
num < 0) {
return;
}
+ if (num > vdev->vq[n].vring.num_default) {
+ virtio_error(vdev, "virtio: queue %d size %d exceeds max size %u",
+ n, num, vdev->vq[n].vring.num_default);
+ return;
+ }
vdev->vq[n].vring.num = num;
}
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 11/30] virtio: stop migrating num_default, validate vring.num on load
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (9 preceding siblings ...)
2026-07-26 21:29 ` [PULL 10/30] virtio: fix queue size validation against allocated maximum Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 12/30] virtio: fail early on bad config_len in migration Michael S. Tsirkin
` (19 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Cornelia Huck
num_default tracks the allocation size of used_elems, set by
virtio_add_queue(). Migrating it via the ringsize subsection is
wrong: a migration stream (malicious or simply from a different
configuration) can inflate num_default so that
virtio_queue_set_num() accepts oversized values, leading to OOB
access on the used_elems array.
It is not even migrated consistently: a configuration with a
smaller num_default could thinkably migrate and work but in the
common case of num == num_default the value is not actually sent.
Stop migrating num_default: make virtio_ringsize_needed() return
false so the subsection is never sent, and use VMSTATE_UNUSED to
consume the field from old streams without applying it. The
destination keeps its local num_default from virtio_add_queue(),
which matches the actual allocation.
Also validate vring.num against num_default when loading the core
virtio state, rejecting streams that supply a queue size larger
than the locally allocated maximum.
Fixes: 46c5d0823d ("virtio: ring sizes vs. reset")
Fixes: 50e5ae4dc3 ("migration/virtio: Remove simple .get/.put use")
Cc: Cornelia Huck <cohuck@redhat.com>
Cc: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <3e6a7c403f93acc37af6a6332fdc65049ae218fb.1784894327.git.mst@redhat.com>
---
hw/virtio/virtio.c | 16 +++++++---------
1 file changed, 7 insertions(+), 9 deletions(-)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 4a6430c31c..2766217ddd 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -2805,14 +2805,6 @@ static bool virtio_packed_virtqueue_needed(void *opaque)
static bool virtio_ringsize_needed(void *opaque)
{
- VirtIODevice *vdev = opaque;
- int i;
-
- for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
- if (vdev->vq[i].vring.num != vdev->vq[i].vring.num_default) {
- return true;
- }
- }
return false;
}
@@ -2901,7 +2893,7 @@ static const VMStateDescription vmstate_ringsize = {
.version_id = 1,
.minimum_version_id = 1,
.fields = (const VMStateField[]) {
- VMSTATE_UINT32(vring.num_default, struct VirtQueue),
+ VMSTATE_UNUSED(sizeof(uint32_t)),
VMSTATE_END_OF_LIST()
}
};
@@ -3581,6 +3573,12 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
for (i = 0; i < num; i++) {
vdev->vq[i].vring.num = qemu_get_be32(f);
+ if (vdev->vq[i].vring.num > vdev->vq[i].vring.num_default) {
+ error_report("VQ %d vring.num %u exceeds allocated max %u",
+ i, vdev->vq[i].vring.num,
+ vdev->vq[i].vring.num_default);
+ return -1;
+ }
if (k->has_variable_vring_alignment) {
vdev->vq[i].vring.align = qemu_get_be32(f);
}
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 12/30] virtio: fail early on bad config_len in migration
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (10 preceding siblings ...)
2026-07-26 21:29 ` [PULL 11/30] virtio: stop migrating num_default, validate vring.num on load Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 13/30] vhost-user: assert nregions within limit Michael S. Tsirkin
` (18 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Dr. David Alan Gilbert
virtio_load() attempts to load config_len bytes from the migration
stream. If that's huge (e.g. 4g) this will uselessly spin
beyond the end of the stream for seconds. Not nice.
Check qemu_file_get_error() and bail out early, instead.
Also note that config_len is int32_t but is coerced to unsigned when
used. Switch it to uint32_t to make this clearer.
Fixes: 2f5732e964 ("Allow mismatched virtio config-len")
Cc: Dr. David Alan Gilbert <dave@treblig.org>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3891
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <cfbefa358af5885eb386637216552bfeba5e7bbc.1784898922.git.mst@redhat.com>
Reviewed-by: Dr. David Alan Gilbert <dave@treblig.org>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
hw/virtio/virtio.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
index 2766217ddd..979c4065b7 100644
--- a/hw/virtio/virtio.c
+++ b/hw/virtio/virtio.c
@@ -3505,7 +3505,7 @@ int coroutine_mixed_fn
virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
{
int i, ret;
- int32_t config_len;
+ uint32_t config_len;
uint32_t num;
uint32_t features;
BusState *qbus = qdev_get_parent_bus(DEVICE(vdev));
@@ -3553,6 +3553,9 @@ virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
qemu_get_buffer(f, vdev->config, MIN(config_len, vdev->config_len));
while (config_len > vdev->config_len) {
+ if (qemu_file_get_error(f)) {
+ return -1;
+ }
qemu_get_byte(f);
config_len--;
}
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 13/30] vhost-user: assert nregions within limit
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (11 preceding siblings ...)
2026-07-26 21:29 ` [PULL 12/30] virtio: fail early on bad config_len in migration Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 14/30] virtio-pmem: wait for flush requests on unrealize Michael S. Tsirkin
` (17 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Stefano Garzarella, Raphael Norwitz
scrub_shadow_regions() and vhost_user_add_remove_regions() use
fixed-size stack arrays sized to VHOST_USER_MAX_RAM_SLOTS and index them
with dev->mem->nregions.
nregions is calculated to never overrun these, but let's add an assert
to make sure we don't get a stack overflow if there's a bug.
Fixes: f1aeb14b08 ("Transmit vhost-user memory regions individually")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3910
Cc: Stefano Garzarella <sgarzare@redhat.com>
Cc: Raphael Norwitz <raphael.norwitz@nutanix.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <48fb8411f67e525872fb19618a886e52b670ab7f.1784896199.git.mst@redhat.com>
---
hw/virtio/vhost-user.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/hw/virtio/vhost-user.c b/hw/virtio/vhost-user.c
index 517cc4ca71..2881cec72d 100644
--- a/hw/virtio/vhost-user.c
+++ b/hw/virtio/vhost-user.c
@@ -946,6 +946,9 @@ static int vhost_user_add_remove_regions(struct vhost_dev *dev,
msg->hdr.size = sizeof(msg->payload.mem_reg);
+ /* Ensure nregions fits the fixed-size arrays used below. */
+ assert(dev->mem->nregions <= VHOST_USER_MAX_RAM_SLOTS);
+
/* Find the regions which need to be removed or added. */
scrub_shadow_regions(dev, add_reg, &nr_add_reg, rem_reg, &nr_rem_reg,
shadow_pcb, track_ramblocks);
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 14/30] virtio-pmem: wait for flush requests on unrealize
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (12 preceding siblings ...)
2026-07-26 21:29 ` [PULL 13/30] vhost-user: assert nregions within limit Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 15/30] libvhost-user: validate last_batch_head in vu_check_queue_inflights Michael S. Tsirkin
` (16 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, David Hildenbrand, Pankaj Gupta
virtio_pmem_flush submits fsync requests to the thread pool and stores a
VirtIOPMEM pointer in each request. If device is deleted e.g. by
hot-unplug, once these complete, done_cb can run after
virtio_pmem_unrealize frees the device, causing a use-after-free.
Track in-flight requests and wait in virtio_pmem_unrealize until
their completions finish before tearing the device down.
Fixes: CVE-2026-63323
Fixes: 5f503cd9f3 ("virtio-pmem: add virtio device")
Cc: David Hildenbrand <david@kernel.org>
Cc: Pankaj Gupta <pagupta@redhat.com>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3938
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <417b6685f37ce818c660ca3c84945992f5c30dcf.1784894206.git.mst@redhat.com>
---
include/hw/virtio/virtio-pmem.h | 1 +
hw/virtio/virtio-pmem.c | 17 +++++++++++++++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/include/hw/virtio/virtio-pmem.h b/include/hw/virtio/virtio-pmem.h
index 9cce600d0b..bb959d10cf 100644
--- a/include/hw/virtio/virtio-pmem.h
+++ b/include/hw/virtio/virtio-pmem.h
@@ -32,6 +32,7 @@ struct VirtIOPMEM {
VirtQueue *rq_vq;
uint64_t start;
HostMemoryBackend *memdev;
+ unsigned int inflight;
};
struct VirtIOPMEMClass {
diff --git a/hw/virtio/virtio-pmem.c b/hw/virtio/virtio-pmem.c
index c3b3299c9c..6f7271c140 100644
--- a/hw/virtio/virtio-pmem.c
+++ b/hw/virtio/virtio-pmem.c
@@ -23,6 +23,7 @@
#include "standard-headers/linux/virtio_pmem.h"
#include "system/hostmem.h"
#include "block/thread-pool.h"
+#include "qemu/aio-wait.h"
#include "trace.h"
typedef struct VirtIODeviceRequest {
@@ -54,14 +55,20 @@ static int worker_cb(void *opaque)
static void done_cb(void *opaque, int ret)
{
VirtIODeviceRequest *req_data = opaque;
+ VirtIOPMEM *pmem = req_data->pmem;
int len = iov_from_buf(req_data->elem.in_sg, req_data->elem.in_num, 0,
&req_data->resp, sizeof(struct virtio_pmem_resp));
/* Callbacks are serialized, so no need to use atomic ops. */
- virtqueue_push(req_data->pmem->rq_vq, &req_data->elem, len);
- virtio_notify((VirtIODevice *)req_data->pmem, req_data->pmem->rq_vq);
+ virtqueue_push(pmem->rq_vq, &req_data->elem, len);
+ virtio_notify((VirtIODevice *)pmem, pmem->rq_vq);
trace_virtio_pmem_response();
g_free(req_data);
+
+ pmem->inflight--;
+ if (!pmem->inflight) {
+ aio_wait_kick();
+ }
}
static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq)
@@ -85,6 +92,7 @@ static void virtio_pmem_flush(VirtIODevice *vdev, VirtQueue *vq)
req_data->fd = memory_region_get_fd(&backend->mr);
req_data->pmem = pmem;
req_data->vdev = vdev;
+ pmem->inflight++;
thread_pool_submit_aio(worker_cb, req_data, done_cb, req_data);
}
@@ -122,6 +130,7 @@ static void virtio_pmem_realize(DeviceState *dev, Error **errp)
host_memory_backend_set_mapped(pmem->memdev, true);
virtio_init(vdev, VIRTIO_ID_PMEM, sizeof(struct virtio_pmem_config));
pmem->rq_vq = virtio_add_queue(vdev, 128, virtio_pmem_flush);
+ pmem->inflight = 1;
}
static void virtio_pmem_unrealize(DeviceState *dev)
@@ -129,6 +138,10 @@ static void virtio_pmem_unrealize(DeviceState *dev)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIOPMEM *pmem = VIRTIO_PMEM(dev);
+ /* Release the device's own reference and wait for in-flight flushes */
+ pmem->inflight--;
+ AIO_WAIT_WHILE(NULL, pmem->inflight > 0);
+
host_memory_backend_set_mapped(pmem->memdev, false);
virtio_delete_queue(pmem->rq_vq);
virtio_cleanup(vdev);
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 15/30] libvhost-user: validate last_batch_head in vu_check_queue_inflights
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (13 preceding siblings ...)
2026-07-26 21:29 ` [PULL 14/30] virtio-pmem: wait for flush requests on unrealize Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 16/30] libvhost-user: fix heap overflow " Michael S. Tsirkin
` (15 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Xie Yongji, Stefano Garzarella
vu_check_queue_inflights uses last_batch_head from the frontend-controlled
inflight shared memory as an index into desc[] without bounds checking.
A malicious or buggy frontend can set last_batch_head >= desc_num,
causing an out-of-bounds write.
Validate last_batch_head before using it.
Note: the value is not guest-accessible so not a security vulnerability.
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3974
Fixes: 5f9ff1eff3 ("libvhost-user: Support tracking inflight I/O in shared memory")
Cc: Xie Yongji <xieyongji@bytedance.com>
Cc: Stefano Garzarella <sgarzare@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <8133770c75c9907578dd551f4d468140a0a75cd2.1784892981.git.mst@redhat.com>
---
subprojects/libvhost-user/libvhost-user.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c
index 42a5e2f1f5..c1c13dbc90 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -1379,6 +1379,12 @@ vu_check_queue_inflights(VuDev *dev, VuVirtq *vq)
vq->counter = 0;
if (unlikely(vq->inflight->used_idx != vq->used_idx)) {
+ if (vq->inflight->last_batch_head >= vq->inflight->desc_num) {
+ vu_panic(dev, "vu_check_queue_inflights: last_batch_head %u "
+ "out of range (desc_num %u)",
+ vq->inflight->last_batch_head, vq->inflight->desc_num);
+ return -1;
+ }
vq->inflight->desc[vq->inflight->last_batch_head].inflight = 0;
barrier();
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 16/30] libvhost-user: fix heap overflow in vu_check_queue_inflights
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (14 preceding siblings ...)
2026-07-26 21:29 ` [PULL 15/30] libvhost-user: validate last_batch_head in vu_check_queue_inflights Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64 Michael S. Tsirkin
` (14 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Xie Yongji, Stefano Garzarella
vu_check_queue_inflights counts inflight descriptors using inflight == 1
but copies entries using inflight != 0. If the inflight field contains
an unexpected non-0/1 value, the function copies more entries than it
allocates and overflows the heap buffer.
Stop the copy pass once resubmit_num reaches the counted inuse value.
Note: the value is not guest-accessible so not a security vulnerability.
Fixes: CVE-2026-63110
Fixes: 5f9ff1eff3 ("libvhost-user: Support tracking inflight I/O in shared memory")
Cc: Xie Yongji <xieyongji@bytedance.com>
Cc: Stefano Garzarella <sgarzare@redhat.com>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3974
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-Id: <e2315efc526c0ee918485df4be69e2b26e8b7a73.1784892981.git.mst@redhat.com>
---
subprojects/libvhost-user/libvhost-user.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/subprojects/libvhost-user/libvhost-user.c b/subprojects/libvhost-user/libvhost-user.c
index c1c13dbc90..a74d814bb4 100644
--- a/subprojects/libvhost-user/libvhost-user.c
+++ b/subprojects/libvhost-user/libvhost-user.c
@@ -1408,6 +1408,13 @@ vu_check_queue_inflights(VuDev *dev, VuVirtq *vq)
for (i = 0; i < vq->inflight->desc_num; i++) {
if (vq->inflight->desc[i].inflight) {
+ /*
+ * We earlier counted exactly vq->inuse in flight -
+ * what is going on?
+ */
+ if (vq->resubmit_num >= vq->inuse) {
+ return -1;
+ }
vq->resubmit_list[vq->resubmit_num].index = i;
vq->resubmit_list[vq->resubmit_num].counter =
vq->inflight->desc[i].counter;
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (15 preceding siblings ...)
2026-07-26 21:29 ` [PULL 16/30] libvhost-user: fix heap overflow " Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-27 0:31 ` Peter Xu
2026-07-26 21:29 ` [PULL 18/30] libvduse: validate vq size Michael S. Tsirkin
` (13 subsequent siblings)
30 siblings, 1 reply; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Alexandr Moshkov, Peter Xu, Fabiano Rosas
vhost user currently saves the inflight buffer to the migration stream
using VMSTATE_VBUFFER_UINT64. The size is controlled by the vhost-user
backend.
But the implementation of that is broken if size is >2G: it stores the
buffer size in a uint64_t field, but vmstate_size() always reads the
size field as int32_t regardless of the macro used. This, in turn,
causes negative or truncated lengths on load, leading to undersized
allocations and down the road out-of-bounds buffer access.
There's no practical reason to support such large sizes, so it's enough
to validate: read the field as uint64_t when VMS_VBUFFER_UINT64 is set,
reject negative or oversized values, and propagate errors to
vmstate_load_vmsd().
Note: the large value is coming from the backend, not guest, so this
shouldn't be considered a security issue. The CVE was assigned before
the qemu security policy was updated to exclude this class of bugs.
Fixes: CVE-2026-6426
Fixes: f6fdd8b2bd ("vmstate: introduce VMSTATE_VBUFFER_UINT64")
Cc: Alexandr Moshkov <dtalexundeer@yandex-team.ru>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3675
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <801b1501ee10241f7ac49a10570d548352b36347.1784890517.git.mst@redhat.com>
---
include/migration/vmstate.h | 5 ++++-
migration/vmstate.c | 31 ++++++++++++++++++++++++++++---
2 files changed, 32 insertions(+), 4 deletions(-)
diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
index 1b7f295417..e7095cd977 100644
--- a/include/migration/vmstate.h
+++ b/include/migration/vmstate.h
@@ -168,6 +168,9 @@ enum VMStateFlags {
*/
VMS_ARRAY_OF_POINTER_AUTO_ALLOC = 0x10000,
+ /* Use a uint64_t size field for VMS_VBUFFER instead of int32_t. */
+ VMS_VBUFFER_UINT64 = 0x40000,
+
/* Marker for end of list */
VMS_END = 0x20000,
};
@@ -788,7 +791,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
.field_exists = (_test), \
.size_offset = vmstate_offset_value(_state, _field_size, uint64_t),\
.info = &vmstate_info_buffer, \
- .flags = VMS_VBUFFER | VMS_POINTER, \
+ .flags = VMS_VBUFFER | VMS_VBUFFER_UINT64 | VMS_POINTER, \
.offset = offsetof(_state, _field), \
}
diff --git a/migration/vmstate.c b/migration/vmstate.c
index 50ebe37845..d7f03a9f5b 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -103,10 +103,24 @@ static int vmstate_size(void *opaque, const VMStateField *field)
int size;
if (field->flags & VMS_VBUFFER) {
- size = *(int32_t *)(opaque + field->size_offset);
- if (field->flags & VMS_MULTIPLY) {
- size *= field->size;
+ uint64_t usize64;
+
+ if (field->flags & VMS_VBUFFER_UINT64) {
+ usize64 = *(uint64_t *)(opaque + field->size_offset);
+ } else {
+ int32_t ssize32 = *(int32_t *)(opaque + field->size_offset);
+ if (ssize32 < 0) {
+ return -1;
+ }
+ usize64 = ssize32;
}
+ if (field->flags & VMS_MULTIPLY) {
+ usize64 *= field->size;
+ }
+ if (usize64 > INT_MAX) {
+ return -1;
+ }
+ size = usize64;
} else if (field->flags & VMS_ARRAY_OF_POINTER) {
/*
* For an array of pointer, the each element is always size of a
@@ -337,6 +351,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
void *first_elem = opaque + field->offset;
int i, n_elems = vmstate_n_elems(opaque, field);
int size = vmstate_size(opaque, field);
+ if (size < 0) {
+ error_setg(errp, "VMState field '%s': invalid size",
+ field->name);
+ return false;
+ }
vmstate_handle_alloc(first_elem, field, opaque);
if (field->flags & VMS_POINTER) {
@@ -661,6 +680,12 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd,
bool use_dynamic_array =
field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
+ if (size < 0) {
+ error_setg(errp, "VMState field '%s': invalid size",
+ field->name);
+ ok = false;
+ goto out;
+ }
trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems);
if (field->flags & VMS_POINTER) {
first_elem = *(void **)first_elem;
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
2026-07-26 21:29 ` [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64 Michael S. Tsirkin
@ 2026-07-27 0:31 ` Peter Xu
2026-07-27 8:53 ` Michael S. Tsirkin
0 siblings, 1 reply; 41+ messages in thread
From: Peter Xu @ 2026-07-27 0:31 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: QEMU Developers, Peter Maydell, Alexandr Moshkov, Fabiano Rosas
[-- Attachment #1: Type: text/plain, Size: 5311 bytes --]
This patch is migration only change and hasn't been reviewed. Give us a
few days to review it?
Can't do it now because it is on cellphone and I just bathed my son.
Please hold off merging.
Thanks.
On Sun, Jul 26, 2026, 5:29 p.m. Michael S. Tsirkin <mst@redhat.com> wrote:
> vhost user currently saves the inflight buffer to the migration stream
> using VMSTATE_VBUFFER_UINT64. The size is controlled by the vhost-user
> backend.
>
> But the implementation of that is broken if size is >2G: it stores the
> buffer size in a uint64_t field, but vmstate_size() always reads the
> size field as int32_t regardless of the macro used. This, in turn,
> causes negative or truncated lengths on load, leading to undersized
> allocations and down the road out-of-bounds buffer access.
>
> There's no practical reason to support such large sizes, so it's enough
> to validate: read the field as uint64_t when VMS_VBUFFER_UINT64 is set,
> reject negative or oversized values, and propagate errors to
> vmstate_load_vmsd().
>
> Note: the large value is coming from the backend, not guest, so this
> shouldn't be considered a security issue. The CVE was assigned before
> the qemu security policy was updated to exclude this class of bugs.
>
> Fixes: CVE-2026-6426
> Fixes: f6fdd8b2bd ("vmstate: introduce VMSTATE_VBUFFER_UINT64")
> Cc: Alexandr Moshkov <dtalexundeer@yandex-team.ru>
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3675
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> Message-ID: <
> 801b1501ee10241f7ac49a10570d548352b36347.1784890517.git.mst@redhat.com>
> ---
> include/migration/vmstate.h | 5 ++++-
> migration/vmstate.c | 31 ++++++++++++++++++++++++++++---
> 2 files changed, 32 insertions(+), 4 deletions(-)
>
> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> index 1b7f295417..e7095cd977 100644
> --- a/include/migration/vmstate.h
> +++ b/include/migration/vmstate.h
> @@ -168,6 +168,9 @@ enum VMStateFlags {
> */
> VMS_ARRAY_OF_POINTER_AUTO_ALLOC = 0x10000,
>
> + /* Use a uint64_t size field for VMS_VBUFFER instead of int32_t. */
> + VMS_VBUFFER_UINT64 = 0x40000,
> +
> /* Marker for end of list */
> VMS_END = 0x20000,
> };
> @@ -788,7 +791,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
> .field_exists = (_test), \
> .size_offset = vmstate_offset_value(_state, _field_size, uint64_t),\
> .info = &vmstate_info_buffer, \
> - .flags = VMS_VBUFFER | VMS_POINTER, \
> + .flags = VMS_VBUFFER | VMS_VBUFFER_UINT64 | VMS_POINTER, \
> .offset = offsetof(_state, _field), \
> }
>
> diff --git a/migration/vmstate.c b/migration/vmstate.c
> index 50ebe37845..d7f03a9f5b 100644
> --- a/migration/vmstate.c
> +++ b/migration/vmstate.c
> @@ -103,10 +103,24 @@ static int vmstate_size(void *opaque, const
> VMStateField *field)
> int size;
>
> if (field->flags & VMS_VBUFFER) {
> - size = *(int32_t *)(opaque + field->size_offset);
> - if (field->flags & VMS_MULTIPLY) {
> - size *= field->size;
> + uint64_t usize64;
> +
> + if (field->flags & VMS_VBUFFER_UINT64) {
> + usize64 = *(uint64_t *)(opaque + field->size_offset);
> + } else {
> + int32_t ssize32 = *(int32_t *)(opaque + field->size_offset);
> + if (ssize32 < 0) {
> + return -1;
> + }
> + usize64 = ssize32;
> }
> + if (field->flags & VMS_MULTIPLY) {
> + usize64 *= field->size;
> + }
> + if (usize64 > INT_MAX) {
> + return -1;
> + }
> + size = usize64;
> } else if (field->flags & VMS_ARRAY_OF_POINTER) {
> /*
> * For an array of pointer, the each element is always size of a
> @@ -337,6 +351,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const
> VMStateDescription *vmsd,
> void *first_elem = opaque + field->offset;
> int i, n_elems = vmstate_n_elems(opaque, field);
> int size = vmstate_size(opaque, field);
> + if (size < 0) {
> + error_setg(errp, "VMState field '%s': invalid size",
> + field->name);
> + return false;
> + }
>
> vmstate_handle_alloc(first_elem, field, opaque);
> if (field->flags & VMS_POINTER) {
> @@ -661,6 +680,12 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const
> VMStateDescription *vmsd,
> bool use_dynamic_array =
> field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
>
> + if (size < 0) {
> + error_setg(errp, "VMState field '%s': invalid size",
> + field->name);
> + ok = false;
> + goto out;
> + }
> trace_vmstate_save_state_loop(vmsd->name, field->name,
> n_elems);
> if (field->flags & VMS_POINTER) {
> first_elem = *(void **)first_elem;
> --
> MST
>
>
[-- Attachment #2: Type: text/html, Size: 6917 bytes --]
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
2026-07-27 0:31 ` Peter Xu
@ 2026-07-27 8:53 ` Michael S. Tsirkin
2026-07-27 12:49 ` Peter Xu
0 siblings, 1 reply; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-27 8:53 UTC (permalink / raw)
To: Peter Xu; +Cc: QEMU Developers, Peter Maydell, Alexandr Moshkov, Fabiano Rosas
On Sun, Jul 26, 2026 at 08:31:57PM -0400, Peter Xu wrote:
> This patch is migration only change and hasn't been reviewed. Give us a few
> days to review it?
> Can't do it now because it is on cellphone and I just bathed my son.
>
> Please hold off merging.
>
> Thanks.
OK. I'll drop this and you will merge it through the migration tree
as appropriate?
> On Sun, Jul 26, 2026, 5:29 p.m. Michael S. Tsirkin <mst@redhat.com> wrote:
>
> vhost user currently saves the inflight buffer to the migration stream
> using VMSTATE_VBUFFER_UINT64. The size is controlled by the vhost-user
> backend.
>
> But the implementation of that is broken if size is >2G: it stores the
> buffer size in a uint64_t field, but vmstate_size() always reads the
> size field as int32_t regardless of the macro used. This, in turn,
> causes negative or truncated lengths on load, leading to undersized
> allocations and down the road out-of-bounds buffer access.
>
> There's no practical reason to support such large sizes, so it's enough
> to validate: read the field as uint64_t when VMS_VBUFFER_UINT64 is set,
> reject negative or oversized values, and propagate errors to
> vmstate_load_vmsd().
>
> Note: the large value is coming from the backend, not guest, so this
> shouldn't be considered a security issue. The CVE was assigned before
> the qemu security policy was updated to exclude this class of bugs.
>
> Fixes: CVE-2026-6426
> Fixes: f6fdd8b2bd ("vmstate: introduce VMSTATE_VBUFFER_UINT64")
> Cc: Alexandr Moshkov <dtalexundeer@yandex-team.ru>
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3675
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> Message-ID: <
> 801b1501ee10241f7ac49a10570d548352b36347.1784890517.git.mst@redhat.com>
> ---
> include/migration/vmstate.h | 5 ++++-
> migration/vmstate.c | 31 ++++++++++++++++++++++++++++---
> 2 files changed, 32 insertions(+), 4 deletions(-)
>
> diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> index 1b7f295417..e7095cd977 100644
> --- a/include/migration/vmstate.h
> +++ b/include/migration/vmstate.h
> @@ -168,6 +168,9 @@ enum VMStateFlags {
> */
> VMS_ARRAY_OF_POINTER_AUTO_ALLOC = 0x10000,
>
> + /* Use a uint64_t size field for VMS_VBUFFER instead of int32_t. */
> + VMS_VBUFFER_UINT64 = 0x40000,
> +
> /* Marker for end of list */
> VMS_END = 0x20000,
> };
> @@ -788,7 +791,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
> .field_exists = (_test), \
> .size_offset = vmstate_offset_value(_state, _field_size, uint64_t),\
> .info = &vmstate_info_buffer, \
> - .flags = VMS_VBUFFER | VMS_POINTER, \
> + .flags = VMS_VBUFFER | VMS_VBUFFER_UINT64 | VMS_POINTER, \
> .offset = offsetof(_state, _field), \
> }
>
> diff --git a/migration/vmstate.c b/migration/vmstate.c
> index 50ebe37845..d7f03a9f5b 100644
> --- a/migration/vmstate.c
> +++ b/migration/vmstate.c
> @@ -103,10 +103,24 @@ static int vmstate_size(void *opaque, const
> VMStateField *field)
> int size;
>
> if (field->flags & VMS_VBUFFER) {
> - size = *(int32_t *)(opaque + field->size_offset);
> - if (field->flags & VMS_MULTIPLY) {
> - size *= field->size;
> + uint64_t usize64;
> +
> + if (field->flags & VMS_VBUFFER_UINT64) {
> + usize64 = *(uint64_t *)(opaque + field->size_offset);
> + } else {
> + int32_t ssize32 = *(int32_t *)(opaque + field->size_offset);
> + if (ssize32 < 0) {
> + return -1;
> + }
> + usize64 = ssize32;
> }
> + if (field->flags & VMS_MULTIPLY) {
> + usize64 *= field->size;
> + }
> + if (usize64 > INT_MAX) {
> + return -1;
> + }
> + size = usize64;
> } else if (field->flags & VMS_ARRAY_OF_POINTER) {
> /*
> * For an array of pointer, the each element is always size of a
> @@ -337,6 +351,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const
> VMStateDescription *vmsd,
> void *first_elem = opaque + field->offset;
> int i, n_elems = vmstate_n_elems(opaque, field);
> int size = vmstate_size(opaque, field);
> + if (size < 0) {
> + error_setg(errp, "VMState field '%s': invalid size",
> + field->name);
> + return false;
> + }
>
> vmstate_handle_alloc(first_elem, field, opaque);
> if (field->flags & VMS_POINTER) {
> @@ -661,6 +680,12 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const
> VMStateDescription *vmsd,
> bool use_dynamic_array =
> field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
>
> + if (size < 0) {
> + error_setg(errp, "VMState field '%s': invalid size",
> + field->name);
> + ok = false;
> + goto out;
> + }
> trace_vmstate_save_state_loop(vmsd->name, field->name,
> n_elems);
> if (field->flags & VMS_POINTER) {
> first_elem = *(void **)first_elem;
> --
> MST
>
>
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
2026-07-27 8:53 ` Michael S. Tsirkin
@ 2026-07-27 12:49 ` Peter Xu
2026-07-27 13:17 ` Michael S. Tsirkin
2026-07-27 19:06 ` Michael S. Tsirkin
0 siblings, 2 replies; 41+ messages in thread
From: Peter Xu @ 2026-07-27 12:49 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: QEMU Developers, Peter Maydell, Alexandr Moshkov, Fabiano Rosas
On Mon, Jul 27, 2026 at 04:53:15AM -0400, Michael S. Tsirkin wrote:
> On Sun, Jul 26, 2026 at 08:31:57PM -0400, Peter Xu wrote:
> > This patch is migration only change and hasn't been reviewed. Give us a few
> > days to review it?
> > Can't do it now because it is on cellphone and I just bathed my son.
> >
> > Please hold off merging.
> >
> > Thanks.
>
> OK. I'll drop this and you will merge it through the migration tree
> as appropriate?
Let's drop it first so it won't block this pull. I can definitely pick it
up when ready, but I want to discuss on how to fix first. Which tree to
pick it up isn't a huge matter to me, but the review.
We found a bunch of randomly introduced VMSTATE flags in the past, I used
to remove some, at least my plan is in the future each time we introduce a
new one (by request from other modules) we better justify it before landing
too easily, in case it needs a revert again.
This vhost regression started 11.0 so IIUC we don't need to rush in 11.1.
I just noticed I read that patch and didn't notice this, my bad to not have
noticed..
For this one specifically..
>
> > On Sun, Jul 26, 2026, 5:29 p.m. Michael S. Tsirkin <mst@redhat.com> wrote:
> >
> > vhost user currently saves the inflight buffer to the migration stream
> > using VMSTATE_VBUFFER_UINT64. The size is controlled by the vhost-user
> > backend.
> >
> > But the implementation of that is broken if size is >2G: it stores the
> > buffer size in a uint64_t field, but vmstate_size() always reads the
> > size field as int32_t regardless of the macro used. This, in turn,
> > causes negative or truncated lengths on load, leading to undersized
> > allocations and down the road out-of-bounds buffer access.
> >
> > There's no practical reason to support such large sizes, so it's enough
If there's no real demand to use 2G or more, I suggest we change size to
int32_t instead on the user, and revert f6fdd8b2 VMSTATE_VBUFFER_UINT64().
Fabiano and I were looking at rest 20+ possible security related bugs in
the past 1-2 weeks, I've some patches to be posted for 11.2 too when we
went through all of them. One relevant patch I haven't sent but will do
soon:
https://gitlab.com/peterx/qemu/-/commit/afd2cb25defdf78a4ab5279cc16634884792c57a
We encountered quite a few of possible over-allocation on destionation side
by manipulating on-wire length field like this one, I believe Fabiano is
looking at how to further limit that from 2G if ever possible per-user.
I'm not sure if that idea will fly, but I think anything bigger than 2G
definitely is not suggested for now when it's only for a type match not
real demand..
I believe VMSTATE_VBUFFER_UINT32 is problematic on its own too, I'll see
how to fix that. That one is slightly easier, worst case is we bail out
for 2G (hence ignore bit 31, which shouldn't be used in reality for legit
users), but I'll think about it.
Thanks,
> > to validate: read the field as uint64_t when VMS_VBUFFER_UINT64 is set,
> > reject negative or oversized values, and propagate errors to
> > vmstate_load_vmsd().
> >
> > Note: the large value is coming from the backend, not guest, so this
> > shouldn't be considered a security issue. The CVE was assigned before
> > the qemu security policy was updated to exclude this class of bugs.
> >
> > Fixes: CVE-2026-6426
> > Fixes: f6fdd8b2bd ("vmstate: introduce VMSTATE_VBUFFER_UINT64")
> > Cc: Alexandr Moshkov <dtalexundeer@yandex-team.ru>
> > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3675
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > Message-ID: <
> > 801b1501ee10241f7ac49a10570d548352b36347.1784890517.git.mst@redhat.com>
> > ---
> > include/migration/vmstate.h | 5 ++++-
> > migration/vmstate.c | 31 ++++++++++++++++++++++++++++---
> > 2 files changed, 32 insertions(+), 4 deletions(-)
> >
> > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > index 1b7f295417..e7095cd977 100644
> > --- a/include/migration/vmstate.h
> > +++ b/include/migration/vmstate.h
> > @@ -168,6 +168,9 @@ enum VMStateFlags {
> > */
> > VMS_ARRAY_OF_POINTER_AUTO_ALLOC = 0x10000,
> >
> > + /* Use a uint64_t size field for VMS_VBUFFER instead of int32_t. */
> > + VMS_VBUFFER_UINT64 = 0x40000,
> > +
> > /* Marker for end of list */
> > VMS_END = 0x20000,
> > };
> > @@ -788,7 +791,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
> > .field_exists = (_test), \
> > .size_offset = vmstate_offset_value(_state, _field_size, uint64_t),\
> > .info = &vmstate_info_buffer, \
> > - .flags = VMS_VBUFFER | VMS_POINTER, \
> > + .flags = VMS_VBUFFER | VMS_VBUFFER_UINT64 | VMS_POINTER, \
> > .offset = offsetof(_state, _field), \
> > }
> >
> > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > index 50ebe37845..d7f03a9f5b 100644
> > --- a/migration/vmstate.c
> > +++ b/migration/vmstate.c
> > @@ -103,10 +103,24 @@ static int vmstate_size(void *opaque, const
> > VMStateField *field)
> > int size;
> >
> > if (field->flags & VMS_VBUFFER) {
> > - size = *(int32_t *)(opaque + field->size_offset);
> > - if (field->flags & VMS_MULTIPLY) {
> > - size *= field->size;
> > + uint64_t usize64;
> > +
> > + if (field->flags & VMS_VBUFFER_UINT64) {
> > + usize64 = *(uint64_t *)(opaque + field->size_offset);
> > + } else {
> > + int32_t ssize32 = *(int32_t *)(opaque + field->size_offset);
> > + if (ssize32 < 0) {
> > + return -1;
> > + }
> > + usize64 = ssize32;
> > }
> > + if (field->flags & VMS_MULTIPLY) {
> > + usize64 *= field->size;
> > + }
> > + if (usize64 > INT_MAX) {
> > + return -1;
> > + }
> > + size = usize64;
> > } else if (field->flags & VMS_ARRAY_OF_POINTER) {
> > /*
> > * For an array of pointer, the each element is always size of a
> > @@ -337,6 +351,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const
> > VMStateDescription *vmsd,
> > void *first_elem = opaque + field->offset;
> > int i, n_elems = vmstate_n_elems(opaque, field);
> > int size = vmstate_size(opaque, field);
> > + if (size < 0) {
> > + error_setg(errp, "VMState field '%s': invalid size",
> > + field->name);
> > + return false;
> > + }
> >
> > vmstate_handle_alloc(first_elem, field, opaque);
> > if (field->flags & VMS_POINTER) {
> > @@ -661,6 +680,12 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const
> > VMStateDescription *vmsd,
> > bool use_dynamic_array =
> > field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
> >
> > + if (size < 0) {
> > + error_setg(errp, "VMState field '%s': invalid size",
> > + field->name);
> > + ok = false;
> > + goto out;
> > + }
> > trace_vmstate_save_state_loop(vmsd->name, field->name,
> > n_elems);
> > if (field->flags & VMS_POINTER) {
> > first_elem = *(void **)first_elem;
> > --
> > MST
> >
> >
>
--
Peter Xu
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
2026-07-27 12:49 ` Peter Xu
@ 2026-07-27 13:17 ` Michael S. Tsirkin
2026-07-27 14:12 ` Peter Xu
2026-07-27 19:06 ` Michael S. Tsirkin
1 sibling, 1 reply; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-27 13:17 UTC (permalink / raw)
To: Peter Xu; +Cc: QEMU Developers, Peter Maydell, Alexandr Moshkov, Fabiano Rosas
On Mon, Jul 27, 2026 at 08:49:44AM -0400, Peter Xu wrote:
> On Mon, Jul 27, 2026 at 04:53:15AM -0400, Michael S. Tsirkin wrote:
> > On Sun, Jul 26, 2026 at 08:31:57PM -0400, Peter Xu wrote:
> > > This patch is migration only change and hasn't been reviewed. Give us a few
> > > days to review it?
> > > Can't do it now because it is on cellphone and I just bathed my son.
> > >
> > > Please hold off merging.
> > >
> > > Thanks.
> >
> > OK. I'll drop this and you will merge it through the migration tree
> > as appropriate?
>
> Let's drop it first so it won't block this pull. I can definitely pick it
> up when ready, but I want to discuss on how to fix first. Which tree to
> pick it up isn't a huge matter to me, but the review.
Done.
Pls include:
Reported-by: Seungjung Kim <seungjung0711@gmail.com>
when you are merging this.
> We found a bunch of randomly introduced VMSTATE flags in the past, I used
> to remove some, at least my plan is in the future each time we introduce a
> new one (by request from other modules) we better justify it before landing
> too easily, in case it needs a revert again.
>
> This vhost regression started 11.0 so IIUC we don't need to rush in 11.1.
> I just noticed I read that patch and didn't notice this, my bad to not have
> noticed..
>
> For this one specifically..
>
> >
> > > On Sun, Jul 26, 2026, 5:29 p.m. Michael S. Tsirkin <mst@redhat.com> wrote:
> > >
> > > vhost user currently saves the inflight buffer to the migration stream
> > > using VMSTATE_VBUFFER_UINT64. The size is controlled by the vhost-user
> > > backend.
> > >
> > > But the implementation of that is broken if size is >2G: it stores the
> > > buffer size in a uint64_t field, but vmstate_size() always reads the
> > > size field as int32_t regardless of the macro used. This, in turn,
> > > causes negative or truncated lengths on load, leading to undersized
> > > allocations and down the road out-of-bounds buffer access.
> > >
> > > There's no practical reason to support such large sizes, so it's enough
>
> If there's no real demand to use 2G or more, I suggest we change size to
> int32_t instead on the user, and revert f6fdd8b2 VMSTATE_VBUFFER_UINT64().
>
> Fabiano and I were looking at rest 20+ possible security related bugs in
> the past 1-2 weeks, I've some patches to be posted for 11.2 too when we
> went through all of them. One relevant patch I haven't sent but will do
> soon:
>
> https://gitlab.com/peterx/qemu/-/commit/afd2cb25defdf78a4ab5279cc16634884792c57a
>
> We encountered quite a few of possible over-allocation on destionation side
> by manipulating on-wire length field like this one, I believe Fabiano is
> looking at how to further limit that from 2G if ever possible per-user.
>
> I'm not sure if that idea will fly, but I think anything bigger than 2G
> definitely is not suggested for now when it's only for a type match not
> real demand..
>
> I believe VMSTATE_VBUFFER_UINT32 is problematic on its own too, I'll see
> how to fix that. That one is slightly easier, worst case is we bail out
> for 2G (hence ignore bit 31, which shouldn't be used in reality for legit
> users), but I'll think about it.
>
> Thanks,
>
> > > to validate: read the field as uint64_t when VMS_VBUFFER_UINT64 is set,
> > > reject negative or oversized values, and propagate errors to
> > > vmstate_load_vmsd().
> > >
> > > Note: the large value is coming from the backend, not guest, so this
> > > shouldn't be considered a security issue. The CVE was assigned before
> > > the qemu security policy was updated to exclude this class of bugs.
> > >
> > > Fixes: CVE-2026-6426
> > > Fixes: f6fdd8b2bd ("vmstate: introduce VMSTATE_VBUFFER_UINT64")
> > > Cc: Alexandr Moshkov <dtalexundeer@yandex-team.ru>
> > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3675
> > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > Message-ID: <
> > > 801b1501ee10241f7ac49a10570d548352b36347.1784890517.git.mst@redhat.com>
> > > ---
> > > include/migration/vmstate.h | 5 ++++-
> > > migration/vmstate.c | 31 ++++++++++++++++++++++++++++---
> > > 2 files changed, 32 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > > index 1b7f295417..e7095cd977 100644
> > > --- a/include/migration/vmstate.h
> > > +++ b/include/migration/vmstate.h
> > > @@ -168,6 +168,9 @@ enum VMStateFlags {
> > > */
> > > VMS_ARRAY_OF_POINTER_AUTO_ALLOC = 0x10000,
> > >
> > > + /* Use a uint64_t size field for VMS_VBUFFER instead of int32_t. */
> > > + VMS_VBUFFER_UINT64 = 0x40000,
> > > +
> > > /* Marker for end of list */
> > > VMS_END = 0x20000,
> > > };
> > > @@ -788,7 +791,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
> > > .field_exists = (_test), \
> > > .size_offset = vmstate_offset_value(_state, _field_size, uint64_t),\
> > > .info = &vmstate_info_buffer, \
> > > - .flags = VMS_VBUFFER | VMS_POINTER, \
> > > + .flags = VMS_VBUFFER | VMS_VBUFFER_UINT64 | VMS_POINTER, \
> > > .offset = offsetof(_state, _field), \
> > > }
> > >
> > > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > > index 50ebe37845..d7f03a9f5b 100644
> > > --- a/migration/vmstate.c
> > > +++ b/migration/vmstate.c
> > > @@ -103,10 +103,24 @@ static int vmstate_size(void *opaque, const
> > > VMStateField *field)
> > > int size;
> > >
> > > if (field->flags & VMS_VBUFFER) {
> > > - size = *(int32_t *)(opaque + field->size_offset);
> > > - if (field->flags & VMS_MULTIPLY) {
> > > - size *= field->size;
> > > + uint64_t usize64;
> > > +
> > > + if (field->flags & VMS_VBUFFER_UINT64) {
> > > + usize64 = *(uint64_t *)(opaque + field->size_offset);
> > > + } else {
> > > + int32_t ssize32 = *(int32_t *)(opaque + field->size_offset);
> > > + if (ssize32 < 0) {
> > > + return -1;
> > > + }
> > > + usize64 = ssize32;
> > > }
> > > + if (field->flags & VMS_MULTIPLY) {
> > > + usize64 *= field->size;
> > > + }
> > > + if (usize64 > INT_MAX) {
> > > + return -1;
> > > + }
> > > + size = usize64;
> > > } else if (field->flags & VMS_ARRAY_OF_POINTER) {
> > > /*
> > > * For an array of pointer, the each element is always size of a
> > > @@ -337,6 +351,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const
> > > VMStateDescription *vmsd,
> > > void *first_elem = opaque + field->offset;
> > > int i, n_elems = vmstate_n_elems(opaque, field);
> > > int size = vmstate_size(opaque, field);
> > > + if (size < 0) {
> > > + error_setg(errp, "VMState field '%s': invalid size",
> > > + field->name);
> > > + return false;
> > > + }
> > >
> > > vmstate_handle_alloc(first_elem, field, opaque);
> > > if (field->flags & VMS_POINTER) {
> > > @@ -661,6 +680,12 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const
> > > VMStateDescription *vmsd,
> > > bool use_dynamic_array =
> > > field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
> > >
> > > + if (size < 0) {
> > > + error_setg(errp, "VMState field '%s': invalid size",
> > > + field->name);
> > > + ok = false;
> > > + goto out;
> > > + }
> > > trace_vmstate_save_state_loop(vmsd->name, field->name,
> > > n_elems);
> > > if (field->flags & VMS_POINTER) {
> > > first_elem = *(void **)first_elem;
> > > --
> > > MST
> > >
> > >
> >
>
> --
> Peter Xu
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
2026-07-27 13:17 ` Michael S. Tsirkin
@ 2026-07-27 14:12 ` Peter Xu
0 siblings, 0 replies; 41+ messages in thread
From: Peter Xu @ 2026-07-27 14:12 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: QEMU Developers, Peter Maydell, Alexandr Moshkov, Fabiano Rosas
On Mon, Jul 27, 2026 at 09:17:25AM -0400, Michael S. Tsirkin wrote:
> On Mon, Jul 27, 2026 at 08:49:44AM -0400, Peter Xu wrote:
> > On Mon, Jul 27, 2026 at 04:53:15AM -0400, Michael S. Tsirkin wrote:
> > > On Sun, Jul 26, 2026 at 08:31:57PM -0400, Peter Xu wrote:
> > > > This patch is migration only change and hasn't been reviewed. Give us a few
> > > > days to review it?
> > > > Can't do it now because it is on cellphone and I just bathed my son.
> > > >
> > > > Please hold off merging.
> > > >
> > > > Thanks.
> > >
> > > OK. I'll drop this and you will merge it through the migration tree
> > > as appropriate?
> >
> > Let's drop it first so it won't block this pull. I can definitely pick it
> > up when ready, but I want to discuss on how to fix first. Which tree to
> > pick it up isn't a huge matter to me, but the review.
>
> Done.
> Pls include:
>
> Reported-by: Seungjung Kim <seungjung0711@gmail.com>
>
> when you are merging this.
Michael,
Please continue read at least until [1] below. I want to discuss if we
should fix it in another way..
Thanks,
>
> > We found a bunch of randomly introduced VMSTATE flags in the past, I used
> > to remove some, at least my plan is in the future each time we introduce a
> > new one (by request from other modules) we better justify it before landing
> > too easily, in case it needs a revert again.
> >
> > This vhost regression started 11.0 so IIUC we don't need to rush in 11.1.
> > I just noticed I read that patch and didn't notice this, my bad to not have
> > noticed..
> >
> > For this one specifically..
> >
> > >
> > > > On Sun, Jul 26, 2026, 5:29 p.m. Michael S. Tsirkin <mst@redhat.com> wrote:
> > > >
> > > > vhost user currently saves the inflight buffer to the migration stream
> > > > using VMSTATE_VBUFFER_UINT64. The size is controlled by the vhost-user
> > > > backend.
> > > >
> > > > But the implementation of that is broken if size is >2G: it stores the
> > > > buffer size in a uint64_t field, but vmstate_size() always reads the
> > > > size field as int32_t regardless of the macro used. This, in turn,
> > > > causes negative or truncated lengths on load, leading to undersized
> > > > allocations and down the road out-of-bounds buffer access.
> > > >
> > > > There's no practical reason to support such large sizes, so it's enough
> >
> > If there's no real demand to use 2G or more, I suggest we change size to
> > int32_t instead on the user, and revert f6fdd8b2 VMSTATE_VBUFFER_UINT64().
[1]
> >
> > Fabiano and I were looking at rest 20+ possible security related bugs in
> > the past 1-2 weeks, I've some patches to be posted for 11.2 too when we
> > went through all of them. One relevant patch I haven't sent but will do
> > soon:
> >
> > https://gitlab.com/peterx/qemu/-/commit/afd2cb25defdf78a4ab5279cc16634884792c57a
> >
> > We encountered quite a few of possible over-allocation on destionation side
> > by manipulating on-wire length field like this one, I believe Fabiano is
> > looking at how to further limit that from 2G if ever possible per-user.
> >
> > I'm not sure if that idea will fly, but I think anything bigger than 2G
> > definitely is not suggested for now when it's only for a type match not
> > real demand..
> >
> > I believe VMSTATE_VBUFFER_UINT32 is problematic on its own too, I'll see
> > how to fix that. That one is slightly easier, worst case is we bail out
> > for 2G (hence ignore bit 31, which shouldn't be used in reality for legit
> > users), but I'll think about it.
> >
> > Thanks,
> >
> > > > to validate: read the field as uint64_t when VMS_VBUFFER_UINT64 is set,
> > > > reject negative or oversized values, and propagate errors to
> > > > vmstate_load_vmsd().
> > > >
> > > > Note: the large value is coming from the backend, not guest, so this
> > > > shouldn't be considered a security issue. The CVE was assigned before
> > > > the qemu security policy was updated to exclude this class of bugs.
> > > >
> > > > Fixes: CVE-2026-6426
> > > > Fixes: f6fdd8b2bd ("vmstate: introduce VMSTATE_VBUFFER_UINT64")
> > > > Cc: Alexandr Moshkov <dtalexundeer@yandex-team.ru>
> > > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3675
> > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > Message-ID: <
> > > > 801b1501ee10241f7ac49a10570d548352b36347.1784890517.git.mst@redhat.com>
> > > > ---
> > > > include/migration/vmstate.h | 5 ++++-
> > > > migration/vmstate.c | 31 ++++++++++++++++++++++++++++---
> > > > 2 files changed, 32 insertions(+), 4 deletions(-)
> > > >
> > > > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > > > index 1b7f295417..e7095cd977 100644
> > > > --- a/include/migration/vmstate.h
> > > > +++ b/include/migration/vmstate.h
> > > > @@ -168,6 +168,9 @@ enum VMStateFlags {
> > > > */
> > > > VMS_ARRAY_OF_POINTER_AUTO_ALLOC = 0x10000,
> > > >
> > > > + /* Use a uint64_t size field for VMS_VBUFFER instead of int32_t. */
> > > > + VMS_VBUFFER_UINT64 = 0x40000,
> > > > +
> > > > /* Marker for end of list */
> > > > VMS_END = 0x20000,
> > > > };
> > > > @@ -788,7 +791,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
> > > > .field_exists = (_test), \
> > > > .size_offset = vmstate_offset_value(_state, _field_size, uint64_t),\
> > > > .info = &vmstate_info_buffer, \
> > > > - .flags = VMS_VBUFFER | VMS_POINTER, \
> > > > + .flags = VMS_VBUFFER | VMS_VBUFFER_UINT64 | VMS_POINTER, \
> > > > .offset = offsetof(_state, _field), \
> > > > }
> > > >
> > > > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > > > index 50ebe37845..d7f03a9f5b 100644
> > > > --- a/migration/vmstate.c
> > > > +++ b/migration/vmstate.c
> > > > @@ -103,10 +103,24 @@ static int vmstate_size(void *opaque, const
> > > > VMStateField *field)
> > > > int size;
> > > >
> > > > if (field->flags & VMS_VBUFFER) {
> > > > - size = *(int32_t *)(opaque + field->size_offset);
> > > > - if (field->flags & VMS_MULTIPLY) {
> > > > - size *= field->size;
> > > > + uint64_t usize64;
> > > > +
> > > > + if (field->flags & VMS_VBUFFER_UINT64) {
> > > > + usize64 = *(uint64_t *)(opaque + field->size_offset);
> > > > + } else {
> > > > + int32_t ssize32 = *(int32_t *)(opaque + field->size_offset);
> > > > + if (ssize32 < 0) {
> > > > + return -1;
> > > > + }
> > > > + usize64 = ssize32;
> > > > }
> > > > + if (field->flags & VMS_MULTIPLY) {
> > > > + usize64 *= field->size;
> > > > + }
> > > > + if (usize64 > INT_MAX) {
> > > > + return -1;
> > > > + }
> > > > + size = usize64;
> > > > } else if (field->flags & VMS_ARRAY_OF_POINTER) {
> > > > /*
> > > > * For an array of pointer, the each element is always size of a
> > > > @@ -337,6 +351,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const
> > > > VMStateDescription *vmsd,
> > > > void *first_elem = opaque + field->offset;
> > > > int i, n_elems = vmstate_n_elems(opaque, field);
> > > > int size = vmstate_size(opaque, field);
> > > > + if (size < 0) {
> > > > + error_setg(errp, "VMState field '%s': invalid size",
> > > > + field->name);
> > > > + return false;
> > > > + }
> > > >
> > > > vmstate_handle_alloc(first_elem, field, opaque);
> > > > if (field->flags & VMS_POINTER) {
> > > > @@ -661,6 +680,12 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const
> > > > VMStateDescription *vmsd,
> > > > bool use_dynamic_array =
> > > > field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
> > > >
> > > > + if (size < 0) {
> > > > + error_setg(errp, "VMState field '%s': invalid size",
> > > > + field->name);
> > > > + ok = false;
> > > > + goto out;
> > > > + }
> > > > trace_vmstate_save_state_loop(vmsd->name, field->name,
> > > > n_elems);
> > > > if (field->flags & VMS_POINTER) {
> > > > first_elem = *(void **)first_elem;
> > > > --
> > > > MST
> > > >
> > > >
> > >
> >
> > --
> > Peter Xu
>
--
Peter Xu
^ permalink raw reply [flat|nested] 41+ messages in thread
* Re: [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
2026-07-27 12:49 ` Peter Xu
2026-07-27 13:17 ` Michael S. Tsirkin
@ 2026-07-27 19:06 ` Michael S. Tsirkin
2026-07-27 20:29 ` Peter Xu
1 sibling, 1 reply; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-27 19:06 UTC (permalink / raw)
To: Peter Xu; +Cc: QEMU Developers, Peter Maydell, Alexandr Moshkov, Fabiano Rosas
On Mon, Jul 27, 2026 at 08:49:44AM -0400, Peter Xu wrote:
> On Mon, Jul 27, 2026 at 04:53:15AM -0400, Michael S. Tsirkin wrote:
> > On Sun, Jul 26, 2026 at 08:31:57PM -0400, Peter Xu wrote:
> > > This patch is migration only change and hasn't been reviewed. Give us a few
> > > days to review it?
> > > Can't do it now because it is on cellphone and I just bathed my son.
> > >
> > > Please hold off merging.
> > >
> > > Thanks.
> >
> > OK. I'll drop this and you will merge it through the migration tree
> > as appropriate?
>
> Let's drop it first so it won't block this pull. I can definitely pick it
> up when ready, but I want to discuss on how to fix first. Which tree to
> pick it up isn't a huge matter to me, but the review.
>
> We found a bunch of randomly introduced VMSTATE flags in the past, I used
> to remove some, at least my plan is in the future each time we introduce a
> new one (by request from other modules) we better justify it before landing
> too easily, in case it needs a revert again.
>
> This vhost regression started 11.0 so IIUC we don't need to rush in 11.1.
> I just noticed I read that patch and didn't notice this, my bad to not have
> noticed..
>
> For this one specifically..
>
> >
> > > On Sun, Jul 26, 2026, 5:29 p.m. Michael S. Tsirkin <mst@redhat.com> wrote:
> > >
> > > vhost user currently saves the inflight buffer to the migration stream
> > > using VMSTATE_VBUFFER_UINT64. The size is controlled by the vhost-user
> > > backend.
> > >
> > > But the implementation of that is broken if size is >2G: it stores the
> > > buffer size in a uint64_t field, but vmstate_size() always reads the
> > > size field as int32_t regardless of the macro used. This, in turn,
> > > causes negative or truncated lengths on load, leading to undersized
> > > allocations and down the road out-of-bounds buffer access.
> > >
> > > There's no practical reason to support such large sizes, so it's enough
>
> If there's no real demand to use 2G or more, I suggest we change size to
> int32_t instead on the user, and revert f6fdd8b2 VMSTATE_VBUFFER_UINT64().
We can't just change it we'll need some tricks to avoid breaking existing
migration format. I don't see how it will be much simpler if you take
that into account.
> Fabiano and I were looking at rest 20+ possible security related bugs in
> the past 1-2 weeks, I've some patches to be posted for 11.2 too when we
> went through all of them. One relevant patch I haven't sent but will do
> soon:
>
> https://gitlab.com/peterx/qemu/-/commit/afd2cb25defdf78a4ab5279cc16634884792c57a
>
> We encountered quite a few of possible over-allocation on destionation side
> by manipulating on-wire length field like this one, I believe Fabiano is
> looking at how to further limit that from 2G if ever possible per-user.
>
> I'm not sure if that idea will fly, but I think anything bigger than 2G
> definitely is not suggested for now when it's only for a type match not
> real demand..
Frankly 2G is crazy too. I see little reason to focus specifically on >2G.
> I believe VMSTATE_VBUFFER_UINT32 is problematic on its own too, I'll see
> how to fix that. That one is slightly easier, worst case is we bail out
> for 2G (hence ignore bit 31, which shouldn't be used in reality for legit
> users), but I'll think about it.
>
> Thanks,
I just do not see (almost) any case where migration destination
does not know the actual size needed, or at least
an upper bound on such.
> > > to validate: read the field as uint64_t when VMS_VBUFFER_UINT64 is set,
> > > reject negative or oversized values, and propagate errors to
> > > vmstate_load_vmsd().
> > >
> > > Note: the large value is coming from the backend, not guest, so this
> > > shouldn't be considered a security issue. The CVE was assigned before
> > > the qemu security policy was updated to exclude this class of bugs.
> > >
> > > Fixes: CVE-2026-6426
> > > Fixes: f6fdd8b2bd ("vmstate: introduce VMSTATE_VBUFFER_UINT64")
> > > Cc: Alexandr Moshkov <dtalexundeer@yandex-team.ru>
> > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3675
> > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > Message-ID: <
> > > 801b1501ee10241f7ac49a10570d548352b36347.1784890517.git.mst@redhat.com>
> > > ---
> > > include/migration/vmstate.h | 5 ++++-
> > > migration/vmstate.c | 31 ++++++++++++++++++++++++++++---
> > > 2 files changed, 32 insertions(+), 4 deletions(-)
> > >
> > > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > > index 1b7f295417..e7095cd977 100644
> > > --- a/include/migration/vmstate.h
> > > +++ b/include/migration/vmstate.h
> > > @@ -168,6 +168,9 @@ enum VMStateFlags {
> > > */
> > > VMS_ARRAY_OF_POINTER_AUTO_ALLOC = 0x10000,
> > >
> > > + /* Use a uint64_t size field for VMS_VBUFFER instead of int32_t. */
> > > + VMS_VBUFFER_UINT64 = 0x40000,
> > > +
> > > /* Marker for end of list */
> > > VMS_END = 0x20000,
> > > };
> > > @@ -788,7 +791,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
> > > .field_exists = (_test), \
> > > .size_offset = vmstate_offset_value(_state, _field_size, uint64_t),\
> > > .info = &vmstate_info_buffer, \
> > > - .flags = VMS_VBUFFER | VMS_POINTER, \
> > > + .flags = VMS_VBUFFER | VMS_VBUFFER_UINT64 | VMS_POINTER, \
> > > .offset = offsetof(_state, _field), \
> > > }
> > >
> > > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > > index 50ebe37845..d7f03a9f5b 100644
> > > --- a/migration/vmstate.c
> > > +++ b/migration/vmstate.c
> > > @@ -103,10 +103,24 @@ static int vmstate_size(void *opaque, const
> > > VMStateField *field)
> > > int size;
> > >
> > > if (field->flags & VMS_VBUFFER) {
> > > - size = *(int32_t *)(opaque + field->size_offset);
> > > - if (field->flags & VMS_MULTIPLY) {
> > > - size *= field->size;
> > > + uint64_t usize64;
> > > +
> > > + if (field->flags & VMS_VBUFFER_UINT64) {
> > > + usize64 = *(uint64_t *)(opaque + field->size_offset);
> > > + } else {
> > > + int32_t ssize32 = *(int32_t *)(opaque + field->size_offset);
> > > + if (ssize32 < 0) {
> > > + return -1;
> > > + }
> > > + usize64 = ssize32;
> > > }
> > > + if (field->flags & VMS_MULTIPLY) {
> > > + usize64 *= field->size;
> > > + }
> > > + if (usize64 > INT_MAX) {
> > > + return -1;
> > > + }
> > > + size = usize64;
> > > } else if (field->flags & VMS_ARRAY_OF_POINTER) {
> > > /*
> > > * For an array of pointer, the each element is always size of a
> > > @@ -337,6 +351,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const
> > > VMStateDescription *vmsd,
> > > void *first_elem = opaque + field->offset;
> > > int i, n_elems = vmstate_n_elems(opaque, field);
> > > int size = vmstate_size(opaque, field);
> > > + if (size < 0) {
> > > + error_setg(errp, "VMState field '%s': invalid size",
> > > + field->name);
> > > + return false;
> > > + }
> > >
> > > vmstate_handle_alloc(first_elem, field, opaque);
> > > if (field->flags & VMS_POINTER) {
> > > @@ -661,6 +680,12 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const
> > > VMStateDescription *vmsd,
> > > bool use_dynamic_array =
> > > field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
> > >
> > > + if (size < 0) {
> > > + error_setg(errp, "VMState field '%s': invalid size",
> > > + field->name);
> > > + ok = false;
> > > + goto out;
> > > + }
> > > trace_vmstate_save_state_loop(vmsd->name, field->name,
> > > n_elems);
> > > if (field->flags & VMS_POINTER) {
> > > first_elem = *(void **)first_elem;
> > > --
> > > MST
> > >
> > >
> >
>
> --
> Peter Xu
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
2026-07-27 19:06 ` Michael S. Tsirkin
@ 2026-07-27 20:29 ` Peter Xu
2026-07-27 20:49 ` Michael S. Tsirkin
0 siblings, 1 reply; 41+ messages in thread
From: Peter Xu @ 2026-07-27 20:29 UTC (permalink / raw)
To: Michael S. Tsirkin
Cc: QEMU Developers, Peter Maydell, Alexandr Moshkov, Fabiano Rosas
On Mon, Jul 27, 2026 at 03:06:38PM -0400, Michael S. Tsirkin wrote:
> On Mon, Jul 27, 2026 at 08:49:44AM -0400, Peter Xu wrote:
> > On Mon, Jul 27, 2026 at 04:53:15AM -0400, Michael S. Tsirkin wrote:
> > > On Sun, Jul 26, 2026 at 08:31:57PM -0400, Peter Xu wrote:
> > > > This patch is migration only change and hasn't been reviewed. Give us a few
> > > > days to review it?
> > > > Can't do it now because it is on cellphone and I just bathed my son.
> > > >
> > > > Please hold off merging.
> > > >
> > > > Thanks.
> > >
> > > OK. I'll drop this and you will merge it through the migration tree
> > > as appropriate?
> >
> > Let's drop it first so it won't block this pull. I can definitely pick it
> > up when ready, but I want to discuss on how to fix first. Which tree to
> > pick it up isn't a huge matter to me, but the review.
> >
> > We found a bunch of randomly introduced VMSTATE flags in the past, I used
> > to remove some, at least my plan is in the future each time we introduce a
> > new one (by request from other modules) we better justify it before landing
> > too easily, in case it needs a revert again.
> >
> > This vhost regression started 11.0 so IIUC we don't need to rush in 11.1.
> > I just noticed I read that patch and didn't notice this, my bad to not have
> > noticed..
> >
> > For this one specifically..
> >
> > >
> > > > On Sun, Jul 26, 2026, 5:29 p.m. Michael S. Tsirkin <mst@redhat.com> wrote:
> > > >
> > > > vhost user currently saves the inflight buffer to the migration stream
> > > > using VMSTATE_VBUFFER_UINT64. The size is controlled by the vhost-user
> > > > backend.
> > > >
> > > > But the implementation of that is broken if size is >2G: it stores the
> > > > buffer size in a uint64_t field, but vmstate_size() always reads the
> > > > size field as int32_t regardless of the macro used. This, in turn,
> > > > causes negative or truncated lengths on load, leading to undersized
> > > > allocations and down the road out-of-bounds buffer access.
> > > >
> > > > There's no practical reason to support such large sizes, so it's enough
> >
> > If there's no real demand to use 2G or more, I suggest we change size to
> > int32_t instead on the user, and revert f6fdd8b2 VMSTATE_VBUFFER_UINT64().
>
> We can't just change it we'll need some tricks to avoid breaking existing
> migration format. I don't see how it will be much simpler if you take
> that into account.
It's not part of the stream, right?
Here IIUC the VMSD field "size" only hard-coded the binary offset to fetch
the int32_t from the object* pointer. IIUC we can simply change it to
int32_t and IIUC it will be able to recv stream from src with uint64_t.
The stream shouldn't be affected when e.g. we migrate from an older QEMU.
>
> > Fabiano and I were looking at rest 20+ possible security related bugs in
> > the past 1-2 weeks, I've some patches to be posted for 11.2 too when we
> > went through all of them. One relevant patch I haven't sent but will do
> > soon:
> >
> > https://gitlab.com/peterx/qemu/-/commit/afd2cb25defdf78a4ab5279cc16634884792c57a
> >
> > We encountered quite a few of possible over-allocation on destionation side
> > by manipulating on-wire length field like this one, I believe Fabiano is
> > looking at how to further limit that from 2G if ever possible per-user.
> >
> > I'm not sure if that idea will fly, but I think anything bigger than 2G
> > definitely is not suggested for now when it's only for a type match not
> > real demand..
>
> Frankly 2G is crazy too. I see little reason to focus specifically on >2G.
Yeah..
>
>
> > I believe VMSTATE_VBUFFER_UINT32 is problematic on its own too, I'll see
> > how to fix that. That one is slightly easier, worst case is we bail out
> > for 2G (hence ignore bit 31, which shouldn't be used in reality for legit
> > users), but I'll think about it.
> >
> > Thanks,
>
> I just do not see (almost) any case where migration destination
> does not know the actual size needed, or at least
> an upper bound on such.
In many cases we transfer the length first then the array following that
with the length. That's a common trick we played like vhost here.
The upper bound is indeed a challenge, I confess I don't know an answer,
and we will need to be careful on adding anything that might break a legit
user. I believe Fabiano might have some better clue there, so I'd leave it
to him until I can read his patches.
Thanks,
>
>
> > > > to validate: read the field as uint64_t when VMS_VBUFFER_UINT64 is set,
> > > > reject negative or oversized values, and propagate errors to
> > > > vmstate_load_vmsd().
> > > >
> > > > Note: the large value is coming from the backend, not guest, so this
> > > > shouldn't be considered a security issue. The CVE was assigned before
> > > > the qemu security policy was updated to exclude this class of bugs.
> > > >
> > > > Fixes: CVE-2026-6426
> > > > Fixes: f6fdd8b2bd ("vmstate: introduce VMSTATE_VBUFFER_UINT64")
> > > > Cc: Alexandr Moshkov <dtalexundeer@yandex-team.ru>
> > > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3675
> > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > Message-ID: <
> > > > 801b1501ee10241f7ac49a10570d548352b36347.1784890517.git.mst@redhat.com>
> > > > ---
> > > > include/migration/vmstate.h | 5 ++++-
> > > > migration/vmstate.c | 31 ++++++++++++++++++++++++++++---
> > > > 2 files changed, 32 insertions(+), 4 deletions(-)
> > > >
> > > > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > > > index 1b7f295417..e7095cd977 100644
> > > > --- a/include/migration/vmstate.h
> > > > +++ b/include/migration/vmstate.h
> > > > @@ -168,6 +168,9 @@ enum VMStateFlags {
> > > > */
> > > > VMS_ARRAY_OF_POINTER_AUTO_ALLOC = 0x10000,
> > > >
> > > > + /* Use a uint64_t size field for VMS_VBUFFER instead of int32_t. */
> > > > + VMS_VBUFFER_UINT64 = 0x40000,
> > > > +
> > > > /* Marker for end of list */
> > > > VMS_END = 0x20000,
> > > > };
> > > > @@ -788,7 +791,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
> > > > .field_exists = (_test), \
> > > > .size_offset = vmstate_offset_value(_state, _field_size, uint64_t),\
> > > > .info = &vmstate_info_buffer, \
> > > > - .flags = VMS_VBUFFER | VMS_POINTER, \
> > > > + .flags = VMS_VBUFFER | VMS_VBUFFER_UINT64 | VMS_POINTER, \
> > > > .offset = offsetof(_state, _field), \
> > > > }
> > > >
> > > > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > > > index 50ebe37845..d7f03a9f5b 100644
> > > > --- a/migration/vmstate.c
> > > > +++ b/migration/vmstate.c
> > > > @@ -103,10 +103,24 @@ static int vmstate_size(void *opaque, const
> > > > VMStateField *field)
> > > > int size;
> > > >
> > > > if (field->flags & VMS_VBUFFER) {
> > > > - size = *(int32_t *)(opaque + field->size_offset);
> > > > - if (field->flags & VMS_MULTIPLY) {
> > > > - size *= field->size;
> > > > + uint64_t usize64;
> > > > +
> > > > + if (field->flags & VMS_VBUFFER_UINT64) {
> > > > + usize64 = *(uint64_t *)(opaque + field->size_offset);
> > > > + } else {
> > > > + int32_t ssize32 = *(int32_t *)(opaque + field->size_offset);
> > > > + if (ssize32 < 0) {
> > > > + return -1;
> > > > + }
> > > > + usize64 = ssize32;
> > > > }
> > > > + if (field->flags & VMS_MULTIPLY) {
> > > > + usize64 *= field->size;
> > > > + }
> > > > + if (usize64 > INT_MAX) {
> > > > + return -1;
> > > > + }
> > > > + size = usize64;
> > > > } else if (field->flags & VMS_ARRAY_OF_POINTER) {
> > > > /*
> > > > * For an array of pointer, the each element is always size of a
> > > > @@ -337,6 +351,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const
> > > > VMStateDescription *vmsd,
> > > > void *first_elem = opaque + field->offset;
> > > > int i, n_elems = vmstate_n_elems(opaque, field);
> > > > int size = vmstate_size(opaque, field);
> > > > + if (size < 0) {
> > > > + error_setg(errp, "VMState field '%s': invalid size",
> > > > + field->name);
> > > > + return false;
> > > > + }
> > > >
> > > > vmstate_handle_alloc(first_elem, field, opaque);
> > > > if (field->flags & VMS_POINTER) {
> > > > @@ -661,6 +680,12 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const
> > > > VMStateDescription *vmsd,
> > > > bool use_dynamic_array =
> > > > field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
> > > >
> > > > + if (size < 0) {
> > > > + error_setg(errp, "VMState field '%s': invalid size",
> > > > + field->name);
> > > > + ok = false;
> > > > + goto out;
> > > > + }
> > > > trace_vmstate_save_state_loop(vmsd->name, field->name,
> > > > n_elems);
> > > > if (field->flags & VMS_POINTER) {
> > > > first_elem = *(void **)first_elem;
> > > > --
> > > > MST
> > > >
> > > >
> > >
> >
> > --
> > Peter Xu
>
--
Peter Xu
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
2026-07-27 20:29 ` Peter Xu
@ 2026-07-27 20:49 ` Michael S. Tsirkin
0 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-27 20:49 UTC (permalink / raw)
To: Peter Xu; +Cc: QEMU Developers, Peter Maydell, Alexandr Moshkov, Fabiano Rosas
On Mon, Jul 27, 2026 at 04:29:55PM -0400, Peter Xu wrote:
> On Mon, Jul 27, 2026 at 03:06:38PM -0400, Michael S. Tsirkin wrote:
> > On Mon, Jul 27, 2026 at 08:49:44AM -0400, Peter Xu wrote:
> > > On Mon, Jul 27, 2026 at 04:53:15AM -0400, Michael S. Tsirkin wrote:
> > > > On Sun, Jul 26, 2026 at 08:31:57PM -0400, Peter Xu wrote:
> > > > > This patch is migration only change and hasn't been reviewed. Give us a few
> > > > > days to review it?
> > > > > Can't do it now because it is on cellphone and I just bathed my son.
> > > > >
> > > > > Please hold off merging.
> > > > >
> > > > > Thanks.
> > > >
> > > > OK. I'll drop this and you will merge it through the migration tree
> > > > as appropriate?
> > >
> > > Let's drop it first so it won't block this pull. I can definitely pick it
> > > up when ready, but I want to discuss on how to fix first. Which tree to
> > > pick it up isn't a huge matter to me, but the review.
> > >
> > > We found a bunch of randomly introduced VMSTATE flags in the past, I used
> > > to remove some, at least my plan is in the future each time we introduce a
> > > new one (by request from other modules) we better justify it before landing
> > > too easily, in case it needs a revert again.
> > >
> > > This vhost regression started 11.0 so IIUC we don't need to rush in 11.1.
> > > I just noticed I read that patch and didn't notice this, my bad to not have
> > > noticed..
> > >
> > > For this one specifically..
> > >
> > > >
> > > > > On Sun, Jul 26, 2026, 5:29 p.m. Michael S. Tsirkin <mst@redhat.com> wrote:
> > > > >
> > > > > vhost user currently saves the inflight buffer to the migration stream
> > > > > using VMSTATE_VBUFFER_UINT64. The size is controlled by the vhost-user
> > > > > backend.
> > > > >
> > > > > But the implementation of that is broken if size is >2G: it stores the
> > > > > buffer size in a uint64_t field, but vmstate_size() always reads the
> > > > > size field as int32_t regardless of the macro used. This, in turn,
> > > > > causes negative or truncated lengths on load, leading to undersized
> > > > > allocations and down the road out-of-bounds buffer access.
> > > > >
> > > > > There's no practical reason to support such large sizes, so it's enough
> > >
> > > If there's no real demand to use 2G or more, I suggest we change size to
> > > int32_t instead on the user, and revert f6fdd8b2 VMSTATE_VBUFFER_UINT64().
> >
> > We can't just change it we'll need some tricks to avoid breaking existing
> > migration format. I don't see how it will be much simpler if you take
> > that into account.
>
> It's not part of the stream, right?
I think it is?
VMSTATE_UINT64(size, struct vhost_inflight) at hw/virtio/vhost.c
eventually leads to qemu_put_be64s / qemu_get_be64s in migration/vmstate-types.c
> Here IIUC the VMSD field "size" only hard-coded the binary offset to fetch
> the int32_t from the object* pointer. IIUC we can simply change it to
> int32_t and IIUC it will be able to recv stream from src with uint64_t.
> The stream shouldn't be affected when e.g. we migrate from an older QEMU.
I don't really know what you mean. Yes vmsd macros tie migration stream
and the storage format. it kinda makes it easy to add one but the
cost is issues like this.
> >
> > > Fabiano and I were looking at rest 20+ possible security related bugs in
> > > the past 1-2 weeks, I've some patches to be posted for 11.2 too when we
> > > went through all of them. One relevant patch I haven't sent but will do
> > > soon:
> > >
> > > https://gitlab.com/peterx/qemu/-/commit/afd2cb25defdf78a4ab5279cc16634884792c57a
> > >
> > > We encountered quite a few of possible over-allocation on destionation side
> > > by manipulating on-wire length field like this one, I believe Fabiano is
> > > looking at how to further limit that from 2G if ever possible per-user.
> > >
> > > I'm not sure if that idea will fly, but I think anything bigger than 2G
> > > definitely is not suggested for now when it's only for a type match not
> > > real demand..
> >
> > Frankly 2G is crazy too. I see little reason to focus specifically on >2G.
>
> Yeah..
>
> >
> >
> > > I believe VMSTATE_VBUFFER_UINT32 is problematic on its own too, I'll see
> > > how to fix that. That one is slightly easier, worst case is we bail out
> > > for 2G (hence ignore bit 31, which shouldn't be used in reality for legit
> > > users), but I'll think about it.
> > >
> > > Thanks,
> >
> > I just do not see (almost) any case where migration destination
> > does not know the actual size needed, or at least
> > an upper bound on such.
>
> In many cases we transfer the length first then the array following that
> with the length. That's a common trick we played like vhost here.
we need to start specifying the cap for these.
> The upper bound is indeed a challenge, I confess I don't know an answer,
> and we will need to be careful on adding anything that might break a legit
> user. I believe Fabiano might have some better clue there, so I'd leave it
> to him until I can read his patches.
>
> Thanks,
>
> >
> >
> > > > > to validate: read the field as uint64_t when VMS_VBUFFER_UINT64 is set,
> > > > > reject negative or oversized values, and propagate errors to
> > > > > vmstate_load_vmsd().
> > > > >
> > > > > Note: the large value is coming from the backend, not guest, so this
> > > > > shouldn't be considered a security issue. The CVE was assigned before
> > > > > the qemu security policy was updated to exclude this class of bugs.
> > > > >
> > > > > Fixes: CVE-2026-6426
> > > > > Fixes: f6fdd8b2bd ("vmstate: introduce VMSTATE_VBUFFER_UINT64")
> > > > > Cc: Alexandr Moshkov <dtalexundeer@yandex-team.ru>
> > > > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3675
> > > > > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> > > > > Message-ID: <
> > > > > 801b1501ee10241f7ac49a10570d548352b36347.1784890517.git.mst@redhat.com>
> > > > > ---
> > > > > include/migration/vmstate.h | 5 ++++-
> > > > > migration/vmstate.c | 31 ++++++++++++++++++++++++++++---
> > > > > 2 files changed, 32 insertions(+), 4 deletions(-)
> > > > >
> > > > > diff --git a/include/migration/vmstate.h b/include/migration/vmstate.h
> > > > > index 1b7f295417..e7095cd977 100644
> > > > > --- a/include/migration/vmstate.h
> > > > > +++ b/include/migration/vmstate.h
> > > > > @@ -168,6 +168,9 @@ enum VMStateFlags {
> > > > > */
> > > > > VMS_ARRAY_OF_POINTER_AUTO_ALLOC = 0x10000,
> > > > >
> > > > > + /* Use a uint64_t size field for VMS_VBUFFER instead of int32_t. */
> > > > > + VMS_VBUFFER_UINT64 = 0x40000,
> > > > > +
> > > > > /* Marker for end of list */
> > > > > VMS_END = 0x20000,
> > > > > };
> > > > > @@ -788,7 +791,7 @@ extern const VMStateInfo vmstate_info_g_byte_array;
> > > > > .field_exists = (_test), \
> > > > > .size_offset = vmstate_offset_value(_state, _field_size, uint64_t),\
> > > > > .info = &vmstate_info_buffer, \
> > > > > - .flags = VMS_VBUFFER | VMS_POINTER, \
> > > > > + .flags = VMS_VBUFFER | VMS_VBUFFER_UINT64 | VMS_POINTER, \
> > > > > .offset = offsetof(_state, _field), \
> > > > > }
> > > > >
> > > > > diff --git a/migration/vmstate.c b/migration/vmstate.c
> > > > > index 50ebe37845..d7f03a9f5b 100644
> > > > > --- a/migration/vmstate.c
> > > > > +++ b/migration/vmstate.c
> > > > > @@ -103,10 +103,24 @@ static int vmstate_size(void *opaque, const
> > > > > VMStateField *field)
> > > > > int size;
> > > > >
> > > > > if (field->flags & VMS_VBUFFER) {
> > > > > - size = *(int32_t *)(opaque + field->size_offset);
> > > > > - if (field->flags & VMS_MULTIPLY) {
> > > > > - size *= field->size;
> > > > > + uint64_t usize64;
> > > > > +
> > > > > + if (field->flags & VMS_VBUFFER_UINT64) {
> > > > > + usize64 = *(uint64_t *)(opaque + field->size_offset);
> > > > > + } else {
> > > > > + int32_t ssize32 = *(int32_t *)(opaque + field->size_offset);
> > > > > + if (ssize32 < 0) {
> > > > > + return -1;
> > > > > + }
> > > > > + usize64 = ssize32;
> > > > > }
> > > > > + if (field->flags & VMS_MULTIPLY) {
> > > > > + usize64 *= field->size;
> > > > > + }
> > > > > + if (usize64 > INT_MAX) {
> > > > > + return -1;
> > > > > + }
> > > > > + size = usize64;
> > > > > } else if (field->flags & VMS_ARRAY_OF_POINTER) {
> > > > > /*
> > > > > * For an array of pointer, the each element is always size of a
> > > > > @@ -337,6 +351,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const
> > > > > VMStateDescription *vmsd,
> > > > > void *first_elem = opaque + field->offset;
> > > > > int i, n_elems = vmstate_n_elems(opaque, field);
> > > > > int size = vmstate_size(opaque, field);
> > > > > + if (size < 0) {
> > > > > + error_setg(errp, "VMState field '%s': invalid size",
> > > > > + field->name);
> > > > > + return false;
> > > > > + }
> > > > >
> > > > > vmstate_handle_alloc(first_elem, field, opaque);
> > > > > if (field->flags & VMS_POINTER) {
> > > > > @@ -661,6 +680,12 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const
> > > > > VMStateDescription *vmsd,
> > > > > bool use_dynamic_array =
> > > > > field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
> > > > >
> > > > > + if (size < 0) {
> > > > > + error_setg(errp, "VMState field '%s': invalid size",
> > > > > + field->name);
> > > > > + ok = false;
> > > > > + goto out;
> > > > > + }
> > > > > trace_vmstate_save_state_loop(vmsd->name, field->name,
> > > > > n_elems);
> > > > > if (field->flags & VMS_POINTER) {
> > > > > first_elem = *(void **)first_elem;
> > > > > --
> > > > > MST
> > > > >
> > > > >
> > > >
> > >
> > > --
> > > Peter Xu
> >
>
> --
> Peter Xu
^ permalink raw reply [flat|nested] 41+ messages in thread
* [PULL 18/30] libvduse: validate vq size
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (16 preceding siblings ...)
2026-07-26 21:29 ` [PULL 17/30] vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64 Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 19/30] virtio-iommu: fix OOM due to unbounded call_rcu Michael S. Tsirkin
` (12 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Jia Jia, Xie Yongji
libvduse assumes that vq size (aka vq num) is below VIRTQUEUE_MAX_SIZE
and maps logs large enough based on this assumption.
However, vduse_queue_enable() accepts the vq size returned through
VDUSE_VQ_GET_INFO without validation, so a value above
VIRTQUEUE_MAX_SIZE (1024) overruns the inflight log and causes
out-of-bounds writes in vduse_queue_inflight_get().
According to the virtio spec, vq size can only be reduced, not
increased, so vq size must not exceed the previously configured
max_size, but the kernel vduse module does not validate this for us, and
we should not trust another process to follow the spec.
Validate and reject vq size values above VIRTQUEUE_MAX_SIZE.
Fixes: CVE-2026-61402
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3652
Reported-by: Jia Jia <physicalmtea@gmail.com>
Message-ID: <bf7e71b3139875e5e00fd53970c772d6c90dc2a1.1784888961.git.mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
subprojects/libvduse/libvduse.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/subprojects/libvduse/libvduse.c b/subprojects/libvduse/libvduse.c
index df9ca5e56f..712b97b4c3 100644
--- a/subprojects/libvduse/libvduse.c
+++ b/subprojects/libvduse/libvduse.c
@@ -902,6 +902,11 @@ static void vduse_queue_enable(VduseVirtq *vq)
return;
}
+ if (vq_info.num > VIRTQUEUE_MAX_SIZE) {
+ fprintf(stderr, "vq[%d] vring num %u exceeds max %u\n",
+ vq->index, vq_info.num, VIRTQUEUE_MAX_SIZE);
+ return;
+ }
vq->vring.num = vq_info.num;
vq->vring.desc_addr = vq_info.desc_addr;
vq->vring.avail_addr = vq_info.driver_addr;
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 19/30] virtio-iommu: fix OOM due to unbounded call_rcu
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (17 preceding siblings ...)
2026-07-26 21:29 ` [PULL 18/30] libvduse: validate vq size Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 20/30] virtio-snd: check rx buffer descriptor size Michael S. Tsirkin
` (11 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Eric Auger, Jean-Philippe Brucker
Currently, within virtio-iommu, handle_command processes the command vq
without any limits on the number of entries processed.
This can easily and repeatedly enable/disable multiple memory regions.
Within the memory code, this causes an accumulation of an
unbounded number of RCU-deferred FlatViews - each of these
is supposed to be freed with call_rcu, but that never happens
because the main thread never returns to the main loop.
Given FlatView is big, it's easy to have this balloon out to multiple
Gigabytes of memory.
Limit the loop defer any remaining work to a timer.
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3930
Cc: Eric Auger <eric.auger@redhat.com>
Cc: Jean-Philippe Brucker <jean-philippe@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Tested-by: Eric Auger <eric.auger@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <eb46ab360dbe28c29cfa78812a7440dcb7444d59.1784807826.git.mst@redhat.com>
---
include/hw/virtio/virtio-iommu.h | 1 +
hw/virtio/virtio-iommu.c | 29 +++++++++++++++++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/include/hw/virtio/virtio-iommu.h b/include/hw/virtio/virtio-iommu.h
index 3b86050f2c..1f265540ad 100644
--- a/include/hw/virtio/virtio-iommu.h
+++ b/include/hw/virtio/virtio-iommu.h
@@ -65,6 +65,7 @@ struct VirtIOIOMMU {
GTree *domains;
QemuRecMutex mutex;
GTree *endpoints;
+ QEMUTimer *cmd_timer;
bool boot_bypass;
Notifier machine_done;
bool granule_frozen;
diff --git a/hw/virtio/virtio-iommu.c b/hw/virtio/virtio-iommu.c
index 08f7e8b783..533bd5073f 100644
--- a/hw/virtio/virtio-iommu.c
+++ b/hw/virtio/virtio-iommu.c
@@ -993,6 +993,18 @@ static int virtio_iommu_handle_probe(VirtIOIOMMU *s,
return ret ? ret : virtio_iommu_probe(s, &req, buf);
}
+static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq);
+
+static void virtio_iommu_handle_command_timer(void *opaque)
+{
+ VirtIOIOMMU *s = opaque;
+ VirtIODevice *vdev = VIRTIO_DEVICE(s);
+
+ if (virtio_device_started(vdev, vdev->status) && !vdev->broken) {
+ virtio_iommu_handle_command(vdev, s->req_vq);
+ }
+}
+
static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq)
{
VirtIOIOMMU *s = VIRTIO_IOMMU(vdev);
@@ -1003,10 +1015,17 @@ static void virtio_iommu_handle_command(VirtIODevice *vdev, VirtQueue *vq)
struct iovec *iov;
void *buf = NULL;
size_t sz;
+ unsigned int batch = 0;
for (;;) {
size_t output_size = sizeof(tail);
+ if (++batch > virtio_queue_get_num(vdev, virtio_get_queue_index(vq))) {
+ timer_mod(s->cmd_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + 1);
+ break;
+ }
+
elem = virtqueue_pop(vq, sizeof(VirtQueueElement));
if (!elem) {
return;
@@ -1416,6 +1435,8 @@ static void virtio_iommu_device_realize(DeviceState *dev, Error **errp)
s->req_vq = virtio_add_queue(vdev, VIOMMU_DEFAULT_QUEUE_SIZE,
virtio_iommu_handle_command);
s->event_vq = virtio_add_queue(vdev, VIOMMU_DEFAULT_QUEUE_SIZE, NULL);
+ s->cmd_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL_RT,
+ virtio_iommu_handle_command_timer, s);
/*
* config.bypass is needed to get initial address space early, such as
@@ -1498,6 +1519,7 @@ static void virtio_iommu_device_unrealize(DeviceState *dev)
qemu_rec_mutex_destroy(&s->mutex);
+ timer_free(s->cmd_timer);
virtio_delete_queue(s->req_vq);
virtio_delete_queue(s->event_vq);
virtio_cleanup(vdev);
@@ -1509,6 +1531,8 @@ static void virtio_iommu_device_reset_exit(Object *obj, ResetType type)
trace_virtio_iommu_device_reset_exit();
+ timer_del(s->cmd_timer);
+
if (s->domains) {
g_tree_destroy(s->domains);
}
@@ -1628,6 +1652,11 @@ static int iommu_post_load(void *opaque, int version_id)
* still correct.
*/
virtio_iommu_switch_address_space_all(s);
+
+ if (virtio_device_started(VIRTIO_DEVICE(s), VIRTIO_DEVICE(s)->status)) {
+ timer_mod(s->cmd_timer,
+ qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL_RT) + 1);
+ }
return 0;
}
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 20/30] virtio-snd: check rx buffer descriptor size
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (18 preceding siblings ...)
2026-07-26 21:29 ` [PULL 19/30] virtio-iommu: fix OOM due to unbounded call_rcu Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 21/30] virtio-snd: check for overflow before g_malloc0 Michael S. Tsirkin
` (10 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Manos Pitsidianakis, Alex Bennée,
Gerd Hoffmann
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
It must be at least sizeof(virtio_snd_pcm_status).
I haven't verified if it's possible to get an underflow, but coverity
points it out in CID 1547527 so add a check.
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260420-virtio-fixups-v3-1-07aef1eff9d2@linaro.org>
---
hw/audio/virtio-snd.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index fb5cff3866..93fbcfb43f 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -970,12 +970,14 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
}
stream = vsnd->pcm.streams[stream_id];
- if (stream == NULL || stream->info.direction != VIRTIO_SND_D_INPUT) {
+ size = iov_size(elem->in_sg, elem->in_num);
+ if (stream == NULL
+ || stream->info.direction != VIRTIO_SND_D_INPUT
+ || size < sizeof(virtio_snd_pcm_status)) {
goto rx_err;
}
+ size -= sizeof(virtio_snd_pcm_status);
WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
- size = iov_size(elem->in_sg, elem->in_num) -
- sizeof(virtio_snd_pcm_status);
buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
buffer->elem = elem;
buffer->vq = vq;
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 21/30] virtio-snd: check for overflow before g_malloc0
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (19 preceding siblings ...)
2026-07-26 21:29 ` [PULL 20/30] virtio-snd: check rx buffer descriptor size Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 22/30] hw/pci-host/q35.c: Always initialize smram-region even if SMM disabled Michael S. Tsirkin
` (9 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Manos Pitsidianakis, Gerd Hoffmann
From: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Coverity points out one g_malloc0 overflow, but it seems to be a false
positive. Add a check to it regardless to fortify the code, and also add
checks for every other g_malloc0 use.
Resolves: Coverity CID 1547527
Signed-off-by: Manos Pitsidianakis <manos.pitsidianakis@linaro.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260420-virtio-fixups-v3-2-07aef1eff9d2@linaro.org>
---
hw/audio/virtio-snd.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/hw/audio/virtio-snd.c b/hw/audio/virtio-snd.c
index 93fbcfb43f..694bcebb60 100644
--- a/hw/audio/virtio-snd.c
+++ b/hw/audio/virtio-snd.c
@@ -850,7 +850,7 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
VirtIOSound *vsnd = VIRTIO_SND(vdev);
VirtIOSoundPCMBuffer *buffer;
VirtQueueElement *elem;
- size_t msg_sz, size;
+ size_t msg_sz, size, tmp;
virtio_snd_pcm_xfer hdr;
uint32_t stream_id;
/*
@@ -880,6 +880,8 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
if (msg_sz != sizeof(virtio_snd_pcm_xfer)) {
goto tx_err;
}
+ assert(iov_size(elem->out_sg, elem->out_num) >= msg_sz);
+ size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
stream_id = le32_to_cpu(hdr.stream_id);
if (stream_id >= vsnd->snd_conf.streams
@@ -892,9 +894,11 @@ static void virtio_snd_handle_tx_xfer(VirtIODevice *vdev, VirtQueue *vq)
goto tx_err;
}
+ /* Check for g_malloc0 overflow. */
+ if (!g_size_checked_add(&tmp, sizeof(VirtIOSoundPCMBuffer), size)) {
+ goto tx_err;
+ }
WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
- size = iov_size(elem->out_sg, elem->out_num) - msg_sz;
-
buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
buffer->elem = elem;
buffer->populated = false;
@@ -932,7 +936,7 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
VirtIOSound *vsnd = VIRTIO_SND(vdev);
VirtIOSoundPCMBuffer *buffer;
VirtQueueElement *elem;
- size_t msg_sz, size;
+ size_t msg_sz, size, tmp;
virtio_snd_pcm_xfer hdr;
uint32_t stream_id;
/*
@@ -977,6 +981,10 @@ static void virtio_snd_handle_rx_xfer(VirtIODevice *vdev, VirtQueue *vq)
goto rx_err;
}
size -= sizeof(virtio_snd_pcm_status);
+ /* Check for g_malloc0 overflow. */
+ if (!g_size_checked_add(&tmp, sizeof(VirtIOSoundPCMBuffer), size)) {
+ goto rx_err;
+ }
WITH_QEMU_LOCK_GUARD(&stream->queue_mutex) {
buffer = g_malloc0(sizeof(VirtIOSoundPCMBuffer) + size);
buffer->elem = elem;
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 22/30] hw/pci-host/q35.c: Always initialize smram-region even if SMM disabled
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (20 preceding siblings ...)
2026-07-26 21:29 ` [PULL 21/30] virtio-snd: check for overflow before g_malloc0 Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 23/30] hw/pci-host/q35.c: Factor out creation of SMRAM MRs Michael S. Tsirkin
` (8 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, qemu-stable, Michael Tokarev
From: Peter Maydell <peter.maydell@linaro.org>
The MCHPCIState::smram_region looks like it ought to be SMM-specific,
but it isn't, because its behaviour is "alias the PCI address space
into system memory at the SMRAM_C_BASE offset", and it must be
enabled for "hide SMRAM", and disabled for "show SMRAM". If the
SMRAM regions are disabled, we want "hide SMRAM", so we need to
initialize and place this MR. Do this in the minimal way, by moving
the "bail out of realize if has_smm_ranges is false" check down below
the initialization code.
This fixes a bug where disabling SMM causes the VGA screen to be
blank during seabios output, until the OS graphics driver is
initialized. This is most obvious for accelerators which have no SMM
support (e.g. NVMM, HVF, WHPX) as there smm=off is the default, but
you can also see it on KVM and TCG if you explicitly pass smm=off:
qemu-system-x86_64 -machine q35,accel=kvm,smm=off
The early return is bug-prone, so we can refactor the code to clean
it up, but this is the minimal bug fix for backports, and is what
Debian used to work around this:
https://salsa.debian.org/qemu-team/qemu/-/commit/6e0766f0f897dc2b75ab87dd59da0d4639bb37ee
Another proposed fix for this:
https://patchew.org/QEMU/20260413170407.57574-1-mohamed@unpredictable.fr/
also moves an early return in mch_update-smram() and tweaks
mch_update_smram() accordingly. This shouldn't be necessary, because
in the no-SMM case smram_region should always be enabled and we don't
want to allow the guest to make it disabled.
NetBSD bug: https://gnats.NetBSD.org/59721
Cc: qemu-stable@nongnu.org
Fixes: b07bf7b7 ("q35: Introduce smm_ranges property for q35-pci-host")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/2608
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Michael Tokarev <mjt@tls.msk.ru>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260708121011.1653365-2-peter.maydell@linaro.org>
---
hw/pci-host/q35.c | 17 ++++++++++++-----
1 file changed, 12 insertions(+), 5 deletions(-)
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 4784b8f59b..47e726c41d 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -596,11 +596,14 @@ static void mch_realize(PCIDevice *d, Error **errp)
PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
}
- if (!mch->has_smm_ranges) {
- return;
- }
-
- /* if *disabled* show SMRAM to all CPUs */
+ /*
+ * This memory region looks like it's SMM specific, but it is not.
+ * It's an alias that makes the pci_address_space appear in system
+ * memory at the SMRAM_C_BASE address. The alias is enabled when the
+ * CPU should not see SMRAM, and *disabled* when the low SMRAM should be
+ * visible. So for non-SMM configs we need to create the alias, and
+ * leave it permanently enabled.
+ */
memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region",
mch->pci_address_space, MCH_HOST_BRIDGE_SMRAM_C_BASE,
MCH_HOST_BRIDGE_SMRAM_C_SIZE);
@@ -608,6 +611,10 @@ static void mch_realize(PCIDevice *d, Error **errp)
&mch->smram_region, 1);
memory_region_set_enabled(&mch->smram_region, true);
+ if (!mch->has_smm_ranges) {
+ return;
+ }
+
memory_region_init_alias(&mch->open_high_smram, OBJECT(mch), "smram-open-high",
mch->ram_memory, MCH_HOST_BRIDGE_SMRAM_C_BASE,
MCH_HOST_BRIDGE_SMRAM_C_SIZE);
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 23/30] hw/pci-host/q35.c: Factor out creation of SMRAM MRs
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (21 preceding siblings ...)
2026-07-26 21:29 ` [PULL 22/30] hw/pci-host/q35.c: Always initialize smram-region even if SMM disabled Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:29 ` [PULL 24/30] hw/pci-host/q35.c: Avoid early return in mch_write_config() Michael S. Tsirkin
` (7 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Michael Tokarev
From: Peter Maydell <peter.maydell@linaro.org>
mch_realize has a large section that deals with initializing the
SMRAM-specific MemoryRegions. Currently we do an early return from
the realize function if mch->has_smm_ranges is false, but this has
the potential for bugs if somebody adds new code at the end of the
function that isn't SMM-specific. Pull the MR init code out into its
own function, so we can do the smm-ranges specific handling in the
realize function in a more obvious way.
This commit shouldn't change behaviour at all.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260708121011.1653365-3-peter.maydell@linaro.org>
---
hw/pci-host/q35.c | 91 ++++++++++++++++++++++++-----------------------
1 file changed, 47 insertions(+), 44 deletions(-)
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index 47e726c41d..e42b84b978 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -572,49 +572,9 @@ static void mch_reset(DeviceState *qdev)
mch_update(mch);
}
-static void mch_realize(PCIDevice *d, Error **errp)
+static void mch_init_smram_regions(MCHPCIState *mch)
{
- int i;
- MCHPCIState *mch = MCH_PCI_DEVICE(d);
-
- if (mch->ext_tseg_mbytes > MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_MAX) {
- error_setg(errp, "invalid extended-tseg-mbytes value: %" PRIu16,
- mch->ext_tseg_mbytes);
- return;
- }
-
- /* setup pci memory mapping */
- pc_pci_as_mapping_init(mch->system_memory, mch->pci_address_space);
-
- /* PAM */
- init_pam(&mch->pam_regions[0], OBJECT(mch), mch->ram_memory,
- mch->system_memory, mch->pci_address_space,
- PAM_BIOS_BASE, PAM_BIOS_SIZE);
- for (i = 0; i < ARRAY_SIZE(mch->pam_regions) - 1; ++i) {
- init_pam(&mch->pam_regions[i + 1], OBJECT(mch), mch->ram_memory,
- mch->system_memory, mch->pci_address_space,
- PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
- }
-
- /*
- * This memory region looks like it's SMM specific, but it is not.
- * It's an alias that makes the pci_address_space appear in system
- * memory at the SMRAM_C_BASE address. The alias is enabled when the
- * CPU should not see SMRAM, and *disabled* when the low SMRAM should be
- * visible. So for non-SMM configs we need to create the alias, and
- * leave it permanently enabled.
- */
- memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region",
- mch->pci_address_space, MCH_HOST_BRIDGE_SMRAM_C_BASE,
- MCH_HOST_BRIDGE_SMRAM_C_SIZE);
- memory_region_add_subregion_overlap(mch->system_memory, MCH_HOST_BRIDGE_SMRAM_C_BASE,
- &mch->smram_region, 1);
- memory_region_set_enabled(&mch->smram_region, true);
-
- if (!mch->has_smm_ranges) {
- return;
- }
-
+ /* Initialize all the SMRAM specific MemoryRegions */
memory_region_init_alias(&mch->open_high_smram, OBJECT(mch), "smram-open-high",
mch->ram_memory, MCH_HOST_BRIDGE_SMRAM_C_BASE,
MCH_HOST_BRIDGE_SMRAM_C_SIZE);
@@ -670,9 +630,52 @@ static void mch_realize(PCIDevice *d, Error **errp)
memory_region_set_enabled(&mch->smbase_window, false);
memory_region_add_subregion(&mch->smram, MCH_HOST_BRIDGE_SMBASE_ADDR,
&mch->smbase_window);
+}
- object_property_add_const_link(qdev_get_machine(), "smram",
- OBJECT(&mch->smram));
+static void mch_realize(PCIDevice *d, Error **errp)
+{
+ int i;
+ MCHPCIState *mch = MCH_PCI_DEVICE(d);
+
+ if (mch->ext_tseg_mbytes > MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_MAX) {
+ error_setg(errp, "invalid extended-tseg-mbytes value: %" PRIu16,
+ mch->ext_tseg_mbytes);
+ return;
+ }
+
+ /* setup pci memory mapping */
+ pc_pci_as_mapping_init(mch->system_memory, mch->pci_address_space);
+
+ /* PAM */
+ init_pam(&mch->pam_regions[0], OBJECT(mch), mch->ram_memory,
+ mch->system_memory, mch->pci_address_space,
+ PAM_BIOS_BASE, PAM_BIOS_SIZE);
+ for (i = 0; i < ARRAY_SIZE(mch->pam_regions) - 1; ++i) {
+ init_pam(&mch->pam_regions[i + 1], OBJECT(mch), mch->ram_memory,
+ mch->system_memory, mch->pci_address_space,
+ PAM_EXPAN_BASE + i * PAM_EXPAN_SIZE, PAM_EXPAN_SIZE);
+ }
+
+ /*
+ * This memory region looks like it's SMM specific, but it is not.
+ * It's an alias that makes the pci_address_space appear in system
+ * memory at the SMRAM_C_BASE address. The alias is enabled when the
+ * CPU should not see SMRAM, and *disabled* when the low SMRAM should be
+ * visible. So for non-SMM configs we need to create the alias, and
+ * leave it permanently enabled.
+ */
+ memory_region_init_alias(&mch->smram_region, OBJECT(mch), "smram-region",
+ mch->pci_address_space, MCH_HOST_BRIDGE_SMRAM_C_BASE,
+ MCH_HOST_BRIDGE_SMRAM_C_SIZE);
+ memory_region_add_subregion_overlap(mch->system_memory, MCH_HOST_BRIDGE_SMRAM_C_BASE,
+ &mch->smram_region, 1);
+ memory_region_set_enabled(&mch->smram_region, true);
+
+ if (mch->has_smm_ranges) {
+ mch_init_smram_regions(mch);
+ object_property_add_const_link(qdev_get_machine(), "smram",
+ OBJECT(&mch->smram));
+ }
}
static const Property mch_props[] = {
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 24/30] hw/pci-host/q35.c: Avoid early return in mch_write_config()
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (22 preceding siblings ...)
2026-07-26 21:29 ` [PULL 23/30] hw/pci-host/q35.c: Factor out creation of SMRAM MRs Michael S. Tsirkin
@ 2026-07-26 21:29 ` Michael S. Tsirkin
2026-07-26 21:30 ` [PULL 25/30] hw/virtio/vdpa-dev: pass set_config buffer to vhost backend Michael S. Tsirkin
` (6 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:29 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell, Michael Tokarev
From: Peter Maydell <peter.maydell@linaro.org>
In mch_write_config() we return early if has_smm_ranges is false.
This is slightly bug-prone because it leaves the door open to somebody
later adding non-SMM-specific code at the bottom of the function.
This case isn't as bad as the one in realize, because the function is
a lot shorter. But putting the handling of the three SMM specific
ranges into an if() rather than having an early return seems better.
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Michael Tokarev <mjt@tls.msk.ru>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260708121011.1653365-4-peter.maydell@linaro.org>
---
hw/pci-host/q35.c | 26 ++++++++++++--------------
1 file changed, 12 insertions(+), 14 deletions(-)
diff --git a/hw/pci-host/q35.c b/hw/pci-host/q35.c
index e42b84b978..f4556ad03a 100644
--- a/hw/pci-host/q35.c
+++ b/hw/pci-host/q35.c
@@ -485,22 +485,20 @@ static void mch_write_config(PCIDevice *d,
mch_update_pciexbar(mch);
}
- if (!mch->has_smm_ranges) {
- return;
- }
+ if (mch->has_smm_ranges) {
+ if (ranges_overlap(address, len, MCH_HOST_BRIDGE_SMRAM,
+ MCH_HOST_BRIDGE_SMRAM_SIZE)) {
+ mch_update_smram(mch);
+ }
- if (ranges_overlap(address, len, MCH_HOST_BRIDGE_SMRAM,
- MCH_HOST_BRIDGE_SMRAM_SIZE)) {
- mch_update_smram(mch);
- }
+ if (ranges_overlap(address, len, MCH_HOST_BRIDGE_EXT_TSEG_MBYTES,
+ MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_SIZE)) {
+ mch_update_ext_tseg_mbytes(mch);
+ }
- if (ranges_overlap(address, len, MCH_HOST_BRIDGE_EXT_TSEG_MBYTES,
- MCH_HOST_BRIDGE_EXT_TSEG_MBYTES_SIZE)) {
- mch_update_ext_tseg_mbytes(mch);
- }
-
- if (ranges_overlap(address, len, MCH_HOST_BRIDGE_F_SMBASE, 1)) {
- mch_update_smbase_smram(mch);
+ if (ranges_overlap(address, len, MCH_HOST_BRIDGE_F_SMBASE, 1)) {
+ mch_update_smbase_smram(mch);
+ }
}
}
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 25/30] hw/virtio/vdpa-dev: pass set_config buffer to vhost backend
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (23 preceding siblings ...)
2026-07-26 21:29 ` [PULL 24/30] hw/pci-host/q35.c: Avoid early return in mch_write_config() Michael S. Tsirkin
@ 2026-07-26 21:30 ` Michael S. Tsirkin
2026-07-26 21:30 ` [PULL 26/30] hw/cxl: fix OOB access in cxl_doe_cdat_rsp via entry_handle Michael S. Tsirkin
` (5 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:30 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, GuoHan Zhao, Paolo Bonzini, Li Zhaoxin,
Daniil Tatianin, Vladimir Sementsov-Ogievskiy
From: GuoHan Zhao <zhaoguohan@kylinos.cn>
vhost_vdpa_device_set_config() receives the updated config buffer, but
forwards s->config to the vhost backend. Since s->config is refreshed by
get_config(), it may contain stale backend state.
Pass the supplied config buffer to vhost_dev_set_config() instead.
Fixes: b430a2bd2303 ("vdpa: add vdpa-dev support")
Signed-off-by: GuoHan Zhao <zhaoguohan@kylinos.cn>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260709073225.2341642-1-zhaoguohan@kylinos.cn>
---
hw/virtio/vdpa-dev.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/hw/virtio/vdpa-dev.c b/hw/virtio/vdpa-dev.c
index 089a77f4d0..6dc684ab09 100644
--- a/hw/virtio/vdpa-dev.c
+++ b/hw/virtio/vdpa-dev.c
@@ -212,7 +212,7 @@ vhost_vdpa_device_set_config(VirtIODevice *vdev, const uint8_t *config)
VhostVdpaDevice *s = VHOST_VDPA_DEVICE(vdev);
int ret;
- ret = vhost_dev_set_config(&s->dev, s->config, 0, s->config_size,
+ ret = vhost_dev_set_config(&s->dev, config, 0, s->config_size,
VHOST_SET_CONFIG_TYPE_FRONTEND);
if (ret) {
error_report("set device config space failed");
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 26/30] hw/cxl: fix OOB access in cxl_doe_cdat_rsp via entry_handle
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (24 preceding siblings ...)
2026-07-26 21:30 ` [PULL 25/30] hw/virtio/vdpa-dev: pass set_config buffer to vhost backend Michael S. Tsirkin
@ 2026-07-26 21:30 ` Michael S. Tsirkin
2026-07-26 21:30 ` [PULL 27/30] intel_iommu: Check address mask before using it in pasid-based iotlb invalidation Michael S. Tsirkin
` (4 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:30 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Haotian Jiang, qemu-stable, Jonathan Cameron,
linux-cxl
From: Haotian Jiang <jianghaotian.sunday@gmail.com>
cxl_doe_cdat_rsp() takes ent = req->entry_handle (uint16_t, fully
guest-controlled, 0..0xFFFF) and directly indexes cdat->entry[ent]
without checking ent < cdat->entry_len. For a default cxl-type3 with
one volatile memory region, entry_len = 1 + CT3_CDAT_NUM_ENTRIES = 7,
so any entry_handle >= 7 reads past the CDATEntry array into host heap.
The OOB-read base/length are then used in
memcpy(read_mbox + offset, base, len) at cxl_type3.c:298-299, leaking
host heap memory to the guest via PCI_EXP_DOE_RD_DATA_MBOX, and
potentially overflowing the 1 MiB read_mbox heap buffer when the OOB
length field is large.
The same bug exists in the cxl-upstream implementation.
Existing checks do not bound ent: assert(cdat->entry_len) only ensures
the table is loaded; the minimum-length check only guards against a
truncated CDATReq; the entry_handle ternary at line 293 only decides
the next-handle echo, not the current access; pcie_doe_get_obj_len
reads header.length, not entry_handle.
Reproduce: build QEMU with CONFIG_CXL, boot
-M q35,cxl=on -device pxb-cxl,bus_nr=52 ... -device cxl-type3,...
then send a CDATReq with entry_handle=0xFFFF via the DOE mailbox at
config offset 0x190. Under ASAN this reports SEGV in cxl_doe_cdat_rsp
at cxl_type3.c:281.
Fixes: f5ee7413d5 ("hw/mem/cxl-type3: Add CXL CDAT Data Object Exchange")
Fixes: 882877fc35 ("hw/pci-bridge/cxl-upstream: Add a CDAT table access DOE")
Signed-off-by: Haotian Jiang <jianghaotian.sunday@gmail.com>
Cc: qemu-stable@nongnu.org
Reviewed-by: Jonathan Cameron <jic23@kernel.org>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260713072336.623604-2-jianghaotian.sunday@gmail.com>
---
hw/mem/cxl_type3.c | 3 +++
hw/pci-bridge/cxl_upstream.c | 3 +++
2 files changed, 6 insertions(+)
diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index cba05ec57d..28f41fa623 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -278,6 +278,9 @@ static bool cxl_doe_cdat_rsp(DOECap *doe_cap)
}
ent = req->entry_handle;
+ if (ent >= cdat->entry_len) {
+ return false;
+ }
base = cdat->entry[ent].base;
len = cdat->entry[ent].length;
diff --git a/hw/pci-bridge/cxl_upstream.c b/hw/pci-bridge/cxl_upstream.c
index b6281cbd4c..69773ff163 100644
--- a/hw/pci-bridge/cxl_upstream.c
+++ b/hw/pci-bridge/cxl_upstream.c
@@ -158,6 +158,9 @@ static bool cxl_doe_cdat_rsp(DOECap *doe_cap)
}
ent = req->entry_handle;
+ if (ent >= cdat->entry_len) {
+ return false;
+ }
base = cdat->entry[ent].base;
len = cdat->entry[ent].length;
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 27/30] intel_iommu: Check address mask before using it in pasid-based iotlb invalidation
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (25 preceding siblings ...)
2026-07-26 21:30 ` [PULL 26/30] hw/cxl: fix OOB access in cxl_doe_cdat_rsp via entry_handle Michael S. Tsirkin
@ 2026-07-26 21:30 ` Michael S. Tsirkin
2026-07-26 21:30 ` [PULL 28/30] hw/net/virtio-net: Protect from DMA re-entrancy bugs Michael S. Tsirkin
` (3 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:30 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Clément MATHIEU--DRIF,
Philippe Mathieu-Daudé, Zhenzhong Duan, Jason Wang, Yi Liu,
Paolo Bonzini, Richard Henderson
From: Clément MATHIEU--DRIF <clement.mathieu--drif@bull.com>
Prevent a buggy driver to execute malformed invalidation operations.
Add the same assert as in vtd_iotlb_page_invalidate.
Link: https://gitlab.com/qemu-project/qemu/-/work_items/3619
Fixes: 6ebe6cf2a066 ("intel_iommu: Process PASID-based iotlb invalidation")
Signed-off-by: Clement Mathieu--Drif <clement.mathieu--drif@bull.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260724111424.376680-1-clement.mathieu--drif@bull.com>
---
hw/i386/intel_iommu.c | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/hw/i386/intel_iommu.c b/hw/i386/intel_iommu.c
index d1af7a3135..82c3c3b2c3 100644
--- a/hw/i386/intel_iommu.c
+++ b/hw/i386/intel_iommu.c
@@ -3021,6 +3021,8 @@ static void vtd_piotlb_page_invalidate(IntelIOMMUState *s, uint16_t domain_id,
{
VTDIOTLBPageInvInfo info;
+ assert(am <= VTD_MAMV);
+
info.domain_id = domain_id;
info.pasid = pasid;
info.addr = addr;
@@ -3060,6 +3062,13 @@ static bool vtd_process_piotlb_desc(IntelIOMMUState *s,
case VTD_INV_DESC_PIOTLB_PSI_IN_PASID:
am = VTD_INV_DESC_PIOTLB_AM(inv_desc->val[1]);
+ if (am > VTD_MAMV) {
+ error_report_once("%s: invalid piotlb inv desc: hi=0x%"PRIx64
+ ", lo=0x%"PRIx64" (am=%u > VTD_MAMV=%llu)",
+ __func__, inv_desc->val[1], inv_desc->val[0],
+ am, VTD_MAMV);
+ return false;
+ }
addr = (hwaddr) VTD_INV_DESC_PIOTLB_ADDR(inv_desc->val[1]);
vtd_piotlb_page_invalidate(s, domain_id, pasid, addr, am,
VTD_INV_DESC_PIOTLB_IH(inv_desc));
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 28/30] hw/net/virtio-net: Protect from DMA re-entrancy bugs
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (26 preceding siblings ...)
2026-07-26 21:30 ` [PULL 27/30] intel_iommu: Check address mask before using it in pasid-based iotlb invalidation Michael S. Tsirkin
@ 2026-07-26 21:30 ` Michael S. Tsirkin
2026-07-26 21:30 ` [PULL 29/30] hw/virtio-rng: Fix host use-after-free (CVE-2026-50624) Michael S. Tsirkin
` (2 subsequent siblings)
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:30 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Laurent Vivier, qemu-stable,
Philippe Mathieu-Daudé, alxndr, Jason Wang
From: Laurent Vivier <lvivier@redhat.com>
Replace qemu_bh_new_guarded() by virtio_bh_new_guarded()
so the bus and device use the same guard. Otherwise the
DMA-reentrancy protection can be bypassed.
This update was missing in CVE-2024-3446 fix.
Fixes: CVE-2026-66022
Cc: qemu-stable@nongnu.org
Cc: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Cc: alxndr@bu.edu
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4073
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260723233555.2970619-1-lvivier@redhat.com>
---
hw/net/virtio-net.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/hw/net/virtio-net.c b/hw/net/virtio-net.c
index 7e0c984ec6..814b99a43d 100644
--- a/hw/net/virtio-net.c
+++ b/hw/net/virtio-net.c
@@ -3009,8 +3009,9 @@ static void virtio_net_add_queue(VirtIONet *n, int index)
n->vqs[index].tx_vq =
virtio_add_queue(vdev, n->net_conf.tx_queue_size,
virtio_net_handle_tx_bh);
- n->vqs[index].tx_bh = qemu_bh_new_guarded(virtio_net_tx_bh, &n->vqs[index],
- &DEVICE(vdev)->mem_reentrancy_guard);
+ n->vqs[index].tx_bh = virtio_bh_new_guarded(DEVICE(vdev),
+ virtio_net_tx_bh,
+ &n->vqs[index]);
}
n->vqs[index].tx_waiting = 0;
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 29/30] hw/virtio-rng: Fix host use-after-free (CVE-2026-50624)
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (27 preceding siblings ...)
2026-07-26 21:30 ` [PULL 28/30] hw/net/virtio-net: Protect from DMA re-entrancy bugs Michael S. Tsirkin
@ 2026-07-26 21:30 ` Michael S. Tsirkin
2026-07-26 21:30 ` [PULL 30/30] backends/rng: cap request size to avoid oversized allocation Michael S. Tsirkin
2026-07-27 8:55 ` [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:30 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Laurent Vivier, Jia Jia,
Philippe Mathieu-Daudé, Amit Shah
From: Laurent Vivier <lvivier@redhat.com>
Fix a heap-use-after-free in the virtio-rng frontend when a delayed
rng-random backend completion arrives after the virtio-rng device has been
hot-unplugged.
Fixes: CVE-2026-50624
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3917
Reported-by: Jia Jia <physicalmtea@gmail.com>
Reviewed-by: Philippe Mathieu-Daudé <philmd@oss.qualcomm.com>
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260724094931.3005968-1-lvivier@redhat.com>
---
include/system/rng.h | 14 ++++++++++++++
backends/rng.c | 16 ++++++++++++++++
hw/virtio/virtio-rng.c | 2 ++
3 files changed, 32 insertions(+)
diff --git a/include/system/rng.h b/include/system/rng.h
index e383f87d20..a2667d75ef 100644
--- a/include/system/rng.h
+++ b/include/system/rng.h
@@ -86,4 +86,18 @@ void rng_backend_request_entropy(RngBackend *s, size_t size,
* deleted.
*/
void rng_backend_finalize_request(RngBackend *s, RngRequest *req);
+
+/**
+ * rng_backend_cancel_requests:
+ * @s: the backend that created the request
+ * @receive_entropy: the function invoked when entropy is available
+ * @opaque: data passed to @receive_entropy
+ *
+ * This function is used by the front-end to cancel all requests to a
+ * given backend. Requests to cancel are identified by the receive_entropy
+ * function and the data passed to the function.
+ */
+void rng_backend_cancel_requests(RngBackend *s,
+ EntropyReceiveFunc *receive_entropy,
+ const void *opaque);
#endif
diff --git a/backends/rng.c b/backends/rng.c
index ab94dfea85..7bed62616a 100644
--- a/backends/rng.c
+++ b/backends/rng.c
@@ -68,6 +68,22 @@ static void rng_backend_free_request(RngRequest *req)
g_free(req);
}
+void rng_backend_cancel_requests(RngBackend *s,
+ EntropyReceiveFunc *receive_entropy,
+ const void *opaque)
+{
+ RngRequest *req, *next;
+
+ QSIMPLEQ_FOREACH_SAFE(req, &s->requests, next, next) {
+ if (req->receive_entropy != receive_entropy ||
+ req->opaque != opaque) {
+ continue;
+ }
+ QSIMPLEQ_REMOVE(&s->requests, req, RngRequest, next);
+ rng_backend_free_request(req);
+ }
+}
+
static void rng_backend_free_requests(RngBackend *s)
{
RngRequest *req, *next;
diff --git a/hw/virtio/virtio-rng.c b/hw/virtio/virtio-rng.c
index 66690a34dc..d68d901195 100644
--- a/hw/virtio/virtio-rng.c
+++ b/hw/virtio/virtio-rng.c
@@ -234,6 +234,8 @@ static void virtio_rng_device_unrealize(DeviceState *dev)
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
VirtIORNG *vrng = VIRTIO_RNG(dev);
+ rng_backend_cancel_requests(vrng->rng, chr_read, vrng);
+
qemu_del_vm_change_state_handler(vrng->vmstate);
timer_free(vrng->rate_limit_timer);
virtio_del_queue(vdev, 0);
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* [PULL 30/30] backends/rng: cap request size to avoid oversized allocation
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (28 preceding siblings ...)
2026-07-26 21:30 ` [PULL 29/30] hw/virtio-rng: Fix host use-after-free (CVE-2026-50624) Michael S. Tsirkin
@ 2026-07-26 21:30 ` Michael S. Tsirkin
2026-07-27 8:55 ` [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
30 siblings, 0 replies; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-26 21:30 UTC (permalink / raw)
To: qemu-devel
Cc: Peter Maydell, Laurent Vivier, qemu-stable, Thomas Huth,
Amit Shah
From: Laurent Vivier <lvivier@redhat.com>
rng_backend_request_entropy() uses the requested size to allocate
a buffer with g_malloc(). With virtio-rng, this size comes from
guest-supplied descriptor lengths. A malicious guest can set a very
large descriptor length, causing QEMU to attempt a multi-gigabyte
allocation and abort.
Cap the allocation to 64 KiB. The virtio-rng queue size is
hardcoded to 8 entries, the EGD backend protocol limits requests
to 255 bytes, the Linux kernel hwrng framework requests at most
SMP_CACHE_BYTES per call (64 bytes on x86_64), and the Windows
viorng driver uses a 4 KiB buffer. The worst legitimate case is
8 x 4 KiB = 32 KiB, so 64 KiB is well above any legitimate use.
Fixes: 14417039653d ("virtio-rng: use virtqueue_get_avail_bytes, fix migration")
Cc: qemu-stable@nongnu.org
Resolves: https://gitlab.com/qemu-project/qemu/-/issues/3983
Signed-off-by: Laurent Vivier <lvivier@redhat.com>
Reviewed-by: Thomas Huth <thuth@redhat.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Message-ID: <20260715141300.2295392-1-lvivier@redhat.com>
---
backends/rng.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/backends/rng.c b/backends/rng.c
index 7bed62616a..bc9c7a5ab3 100644
--- a/backends/rng.c
+++ b/backends/rng.c
@@ -11,11 +11,14 @@
*/
#include "qemu/osdep.h"
+#include "qemu/units.h"
#include "system/rng.h"
#include "qapi/error.h"
#include "qemu/module.h"
#include "qom/object_interfaces.h"
+#define RNG_MAX_REQUEST_SIZE (64 * KiB)
+
void rng_backend_request_entropy(RngBackend *s, size_t size,
EntropyReceiveFunc *receive_entropy,
void *opaque)
@@ -27,7 +30,7 @@ void rng_backend_request_entropy(RngBackend *s, size_t size,
req = g_malloc(sizeof(*req));
req->offset = 0;
- req->size = size;
+ req->size = MIN(size, RNG_MAX_REQUEST_SIZE);
req->receive_entropy = receive_entropy;
req->opaque = opaque;
req->data = g_malloc(req->size);
--
MST
^ permalink raw reply related [flat|nested] 41+ messages in thread* Re: [PULL 00/30] pci, vhost, virtio, iommu: bugfixes
2026-07-26 21:28 [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
` (29 preceding siblings ...)
2026-07-26 21:30 ` [PULL 30/30] backends/rng: cap request size to avoid oversized allocation Michael S. Tsirkin
@ 2026-07-27 8:55 ` Michael S. Tsirkin
2026-07-27 9:05 ` Marc-André Lureau
30 siblings, 1 reply; 41+ messages in thread
From: Michael S. Tsirkin @ 2026-07-27 8:55 UTC (permalink / raw)
To: qemu-devel; +Cc: Peter Maydell
On Sun, Jul 26, 2026 at 05:29:01PM -0400, Michael S. Tsirkin wrote:
> The following changes since commit cbd42e2b75b23953a9bdb073c8531518b1bd6163:
>
> Update version for v11.1.0-rc1 release (2026-07-21 13:18:25 -0400)
>
> are available in the Git repository at:
>
> https://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git tags/for_upstream
>
> for you to fetch changes up to 13342b9c4104f3bf93c2e52e7de4b383971d7bd6:
moved to f2fe2afd27ddf93b49a16a29e8224d16b9888953 now:
I dropped
vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
will go in through the migration tree.
> backends/rng: cap request size to avoid oversized allocation (2026-07-26 17:26:41 -0400)
>
> ----------------------------------------------------------------
> pci, vhost, virtio, iommu: bugfixes
>
> Fixes all over the place, including a bunch of CVE fixes.
>
> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
>
> ----------------------------------------------------------------
> Clément MATHIEU--DRIF (1):
> intel_iommu: Check address mask before using it in pasid-based iotlb invalidation
>
> GuoHan Zhao (1):
> hw/virtio/vdpa-dev: pass set_config buffer to vhost backend
>
> Haotian Jiang (1):
> hw/cxl: fix OOB access in cxl_doe_cdat_rsp via entry_handle
>
> Laurent Vivier (4):
> hw/virtio: reject zero-length packed indirect descriptor table
> hw/net/virtio-net: Protect from DMA re-entrancy bugs
> hw/virtio-rng: Fix host use-after-free (CVE-2026-50624)
> backends/rng: cap request size to avoid oversized allocation
>
> Manos Pitsidianakis (2):
> virtio-snd: check rx buffer descriptor size
> virtio-snd: check for overflow before g_malloc0
>
> Michael S. Tsirkin (18):
> virtio: use masked features with set_features_ex
> virtio-net: fix OOB read in RSC receive path
> virtio-net: fix short frame OOB read in receive_filter()
> libvhost-user: protect against OOB writes in vu_set_inflight_fd
> libvhost-user: protect against OOB vring queue access
> vhost: do not crash on ring map failure
> virtio-scsi: fix SCSIRequest leak on a bad request
> virtio-mmio: fix QUEUE_NUM_MAX
> virtio: fix queue size validation against allocated maximum
> virtio: stop migrating num_default, validate vring.num on load
> virtio: fail early on bad config_len in migration
> vhost-user: assert nregions within limit
> virtio-pmem: wait for flush requests on unrealize
> libvhost-user: validate last_batch_head in vu_check_queue_inflights
> libvhost-user: fix heap overflow in vu_check_queue_inflights
> vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
> libvduse: validate vq size
> virtio-iommu: fix OOM due to unbounded call_rcu
>
> Peter Maydell (3):
> hw/pci-host/q35.c: Always initialize smram-region even if SMM disabled
> hw/pci-host/q35.c: Factor out creation of SMRAM MRs
> hw/pci-host/q35.c: Avoid early return in mch_write_config()
>
> include/hw/scsi/scsi.h | 1 +
> include/hw/virtio/virtio-bus.h | 1 +
> include/hw/virtio/virtio-iommu.h | 1 +
> include/hw/virtio/virtio-mmio.h | 1 +
> include/hw/virtio/virtio-pmem.h | 1 +
> include/migration/vmstate.h | 5 +-
> include/system/rng.h | 14 ++++
> backends/rng.c | 21 +++++-
> hw/audio/virtio-snd.c | 24 +++++--
> hw/core/machine.c | 1 +
> hw/i386/intel_iommu.c | 9 +++
> hw/mem/cxl_type3.c | 3 +
> hw/net/virtio-net.c | 25 ++++++-
> hw/pci-bridge/cxl_upstream.c | 3 +
> hw/pci-host/q35.c | 110 ++++++++++++++++--------------
> hw/scsi/scsi-bus.c | 7 ++
> hw/scsi/virtio-scsi.c | 2 +
> hw/virtio/vdpa-dev.c | 2 +-
> hw/virtio/vhost-user.c | 3 +
> hw/virtio/vhost.c | 5 +-
> hw/virtio/virtio-iommu.c | 29 ++++++++
> hw/virtio/virtio-mmio.c | 7 +-
> hw/virtio/virtio-pmem.c | 17 ++++-
> hw/virtio/virtio-rng.c | 2 +
> hw/virtio/virtio.c | 43 ++++++++----
> migration/vmstate.c | 31 ++++++++-
> subprojects/libvduse/libvduse.c | 5 ++
> subprojects/libvhost-user/libvhost-user.c | 61 ++++++++++++++++-
> 28 files changed, 345 insertions(+), 89 deletions(-)
>
^ permalink raw reply [flat|nested] 41+ messages in thread* Re: [PULL 00/30] pci, vhost, virtio, iommu: bugfixes
2026-07-27 8:55 ` [PULL 00/30] pci, vhost, virtio, iommu: bugfixes Michael S. Tsirkin
@ 2026-07-27 9:05 ` Marc-André Lureau
0 siblings, 0 replies; 41+ messages in thread
From: Marc-André Lureau @ 2026-07-27 9:05 UTC (permalink / raw)
To: Michael S. Tsirkin; +Cc: qemu-devel, Peter Maydell
Hi Michael
On Mon, Jul 27, 2026 at 12:57 PM Michael S. Tsirkin <mst@redhat.com> wrote:
>
> On Sun, Jul 26, 2026 at 05:29:01PM -0400, Michael S. Tsirkin wrote:
> > The following changes since commit cbd42e2b75b23953a9bdb073c8531518b1bd6163:
> >
> > Update version for v11.1.0-rc1 release (2026-07-21 13:18:25 -0400)
> >
> > are available in the Git repository at:
> >
> > https://git.kernel.org/pub/scm/virt/kvm/mst/qemu.git tags/for_upstream
> >
> > for you to fetch changes up to 13342b9c4104f3bf93c2e52e7de4b383971d7bd6:
>
>
> moved to f2fe2afd27ddf93b49a16a29e8224d16b9888953 now:
> I dropped
> vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
> will go in through the migration tree.
>
Some of the commits have duplicate Signed-off lines. It's also strange
to be both the Author and Reviewed-by (and some did not receive
external review)
I guess we could teach checkpatch about those quirks
> > backends/rng: cap request size to avoid oversized allocation (2026-07-26 17:26:41 -0400)
> >
> > ----------------------------------------------------------------
> > pci, vhost, virtio, iommu: bugfixes
> >
> > Fixes all over the place, including a bunch of CVE fixes.
> >
> > Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
> >
> > ----------------------------------------------------------------
> > Clément MATHIEU--DRIF (1):
> > intel_iommu: Check address mask before using it in pasid-based iotlb invalidation
> >
> > GuoHan Zhao (1):
> > hw/virtio/vdpa-dev: pass set_config buffer to vhost backend
> >
> > Haotian Jiang (1):
> > hw/cxl: fix OOB access in cxl_doe_cdat_rsp via entry_handle
> >
> > Laurent Vivier (4):
> > hw/virtio: reject zero-length packed indirect descriptor table
> > hw/net/virtio-net: Protect from DMA re-entrancy bugs
> > hw/virtio-rng: Fix host use-after-free (CVE-2026-50624)
> > backends/rng: cap request size to avoid oversized allocation
> >
> > Manos Pitsidianakis (2):
> > virtio-snd: check rx buffer descriptor size
> > virtio-snd: check for overflow before g_malloc0
> >
> > Michael S. Tsirkin (18):
> > virtio: use masked features with set_features_ex
> > virtio-net: fix OOB read in RSC receive path
> > virtio-net: fix short frame OOB read in receive_filter()
> > libvhost-user: protect against OOB writes in vu_set_inflight_fd
> > libvhost-user: protect against OOB vring queue access
> > vhost: do not crash on ring map failure
> > virtio-scsi: fix SCSIRequest leak on a bad request
> > virtio-mmio: fix QUEUE_NUM_MAX
> > virtio: fix queue size validation against allocated maximum
> > virtio: stop migrating num_default, validate vring.num on load
> > virtio: fail early on bad config_len in migration
> > vhost-user: assert nregions within limit
> > virtio-pmem: wait for flush requests on unrealize
> > libvhost-user: validate last_batch_head in vu_check_queue_inflights
> > libvhost-user: fix heap overflow in vu_check_queue_inflights
> > vmstate: fix type confusion in vmstate_size() for VMSTATE_VBUFFER_UINT64
> > libvduse: validate vq size
> > virtio-iommu: fix OOM due to unbounded call_rcu
> >
> > Peter Maydell (3):
> > hw/pci-host/q35.c: Always initialize smram-region even if SMM disabled
> > hw/pci-host/q35.c: Factor out creation of SMRAM MRs
> > hw/pci-host/q35.c: Avoid early return in mch_write_config()
> >
> > include/hw/scsi/scsi.h | 1 +
> > include/hw/virtio/virtio-bus.h | 1 +
> > include/hw/virtio/virtio-iommu.h | 1 +
> > include/hw/virtio/virtio-mmio.h | 1 +
> > include/hw/virtio/virtio-pmem.h | 1 +
> > include/migration/vmstate.h | 5 +-
> > include/system/rng.h | 14 ++++
> > backends/rng.c | 21 +++++-
> > hw/audio/virtio-snd.c | 24 +++++--
> > hw/core/machine.c | 1 +
> > hw/i386/intel_iommu.c | 9 +++
> > hw/mem/cxl_type3.c | 3 +
> > hw/net/virtio-net.c | 25 ++++++-
> > hw/pci-bridge/cxl_upstream.c | 3 +
> > hw/pci-host/q35.c | 110 ++++++++++++++++--------------
> > hw/scsi/scsi-bus.c | 7 ++
> > hw/scsi/virtio-scsi.c | 2 +
> > hw/virtio/vdpa-dev.c | 2 +-
> > hw/virtio/vhost-user.c | 3 +
> > hw/virtio/vhost.c | 5 +-
> > hw/virtio/virtio-iommu.c | 29 ++++++++
> > hw/virtio/virtio-mmio.c | 7 +-
> > hw/virtio/virtio-pmem.c | 17 ++++-
> > hw/virtio/virtio-rng.c | 2 +
> > hw/virtio/virtio.c | 43 ++++++++----
> > migration/vmstate.c | 31 ++++++++-
> > subprojects/libvduse/libvduse.c | 5 ++
> > subprojects/libvhost-user/libvhost-user.c | 61 ++++++++++++++++-
> > 28 files changed, 345 insertions(+), 89 deletions(-)
> >
>
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 41+ messages in thread