On 2026/07/13 21:55, [email protected] wrote:
From: Marc-AndrĂ© Lureau <[email protected]>

Cap iov_cnt at 16384 in virtio_gpu_load() and virtio_gpu_blob_load()
to match the existing limit enforced in virtio_gpu_create_mapping_iov().

These limits apply to different quantities. virtio_gpu_create_mapping_iov() limits the guest-supplied nr_entries,
whereas iov_cnt is the number of mappings produced by dma_memory_map().
Since dma_memory_map() may split one guest entry into multiple mappings,
iov_cnt may exceed nr_entries and therefore 16384.

Both save paths serialize this expanded count, so migration can fail even for mappings accepted by virtio_gpu_create_mapping_iov(), including between QEMU instances containing this patch.


An unbounded iov_cnt from the migration stream drives two g_new()
allocations whose combined size can exceed available memory, causing
GLib to abort the process.

Since there is no corresponding 16384 limit on the expanded iovec
count, I think these allocations should use g_try_new() and propagate
allocation failure as a migration error instead.

Regards,
Akihiko Odaki


Fixes: 0c244e50ee12 ("virtio-gpu: add live migration support")
Fixes: f66767f75c9c ("virtio-gpu: add virtio-gpu/blob vmstate subsection")
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3753
Reported-by: Feifan Qian <[email protected]>
Signed-off-by: Marc-AndrĂ© Lureau <[email protected]>
---
  hw/display/virtio-gpu.c | 18 +++++++++++++++---
  1 file changed, 15 insertions(+), 3 deletions(-)

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 88526051a99..6289bff9f3b 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -34,6 +34,7 @@
  #include "qemu/error-report.h"
#define VIRTIO_GPU_VM_VERSION 1
+#define VIRTIO_GPU_MAX_IOVEC 16384
static struct virtio_gpu_simple_resource *
  virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id,
@@ -820,10 +821,10 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
      size_t esize, s;
      int e, v;
- if (nr_entries > 16384) {
+    if (nr_entries > VIRTIO_GPU_MAX_IOVEC) {
          qemu_log_mask(LOG_GUEST_ERROR,
-                      "%s: nr_entries is too big (%d > 16384)\n",
-                      __func__, nr_entries);
+                      "%s: nr_entries is too big (%d > %d)\n",
+                      __func__, nr_entries, VIRTIO_GPU_MAX_IOVEC);
          return -1;
      }
@@ -1323,6 +1324,11 @@ static int virtio_gpu_load(QEMUFile *f, void *opaque, size_t size,
          res->format = qemu_get_be32(f);
          res->iov_cnt = qemu_get_be32(f);
+ if (res->iov_cnt > VIRTIO_GPU_MAX_IOVEC) {
+            g_free(res);
+            return -EINVAL;
+        }
+
          /* allocate */
          pformat = virtio_gpu_get_pixman_format(res->format);
          if (!pformat) {
@@ -1424,6 +1430,12 @@ static int virtio_gpu_blob_load(QEMUFile *f, void 
*opaque, size_t size,
          res->resource_id = resource_id;
          res->blob_size = qemu_get_be32(f);
          res->iov_cnt = qemu_get_be32(f);
+
+        if (res->iov_cnt > VIRTIO_GPU_MAX_IOVEC) {
+            g_free(res);
+            return -EINVAL;
+        }
+
          res->addrs = g_new(uint64_t, res->iov_cnt);
          res->iov = g_new(struct iovec, res->iov_cnt);


Reply via email to