The blob size is encoded as a 64-bit integer in the virtio protocol, but
it is encoded as a 32-bit integer in the migration stream, and
a large blob whose size cannot be expressed in a 32-bit integer will
be corrupted after migration.
Block migration with such large blobs, and, if it is not possible, deny
creating a large blob.
Fixes: f66767f75c9c ("virtio-gpu: add virtio-gpu/blob vmstate subsection")
Fixes: 10b9ddbc83b9 ("Revert "virtio-gpu: block migration of VMs with blob=true"")
Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
---
Supersedes: <20260727-blob-v2-1-d0b9af38a975@rsg.ci.i.u-tokyo.ac.jp>
("[PATCH v2] hw/display/virtio-gpu: Reject non-migratable large blobs")
---
hw/display/virtio-gpu.c | 32 ++++++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index bb0f41bb1e05..5d43ffb99184 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -27,6 +27,7 @@
#include "hw/virtio/virtio-gpu-pixman.h"
#include "hw/virtio/virtio-bus.h"
#include "hw/core/qdev-properties.h"
+#include "migration/blocker.h"
#include "qemu/log.h"
#include "qemu/memfd.h"
#include "qemu/module.h"
@@ -35,6 +36,9 @@
#define VIRTIO_GPU_VM_VERSION 1
+static size_t num_large_blobs;
+static Error *large_blob_blocker;
+
static struct virtio_gpu_simple_resource *
virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id,
const char *caller, uint32_t *error);
@@ -355,6 +359,7 @@ end:
static void virtio_gpu_resource_create_blob(VirtIOGPU *g,
struct virtio_gpu_ctrl_command *cmd)
{
+ Error *local_err = NULL;
struct virtio_gpu_simple_resource *res;
struct virtio_gpu_resource_create_blob cblob;
int ret;
@@ -415,6 +420,26 @@ static void virtio_gpu_resource_create_blob(VirtIOGPU *g,
}
}
+ if (cblob.size > UINT32_MAX) {
+ if (!num_large_blobs) {
+ error_setg(&large_blob_blocker,
+ "a large virtio-gpu blob is present");
+ if (migrate_add_blocker(&large_blob_blocker, &local_err)) {
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: blocking migration for a large blob failed: %s\n",
+ __func__, error_get_pretty(local_err));
+ error_free(local_err);
+ cmd->error = VIRTIO_GPU_RESP_ERR_UNSPEC;
+ virtio_gpu_fini_udmabuf(res);
+ virtio_gpu_cleanup_mapping(g, res);
+ g_free(res);
+ return;
+ }
+ }
+
+ num_large_blobs++;
+ }
+
QTAILQ_INSERT_HEAD(&g->reslist, res, next);
}
@@ -460,6 +485,13 @@ static void virtio_gpu_resource_destroy(VirtIOGPU *g,
{
virtio_gpu_disable_scanout_for_resource(g, res->resource_id);
+ if (res->blob_size > UINT32_MAX) {
+ num_large_blobs--;
+ if (!num_large_blobs) {
+ migrate_del_blocker(&large_blob_blocker);
+ }
+ }
+
qemu_pixman_image_unref(res->image);
virtio_gpu_cleanup_mapping(g, res);
QTAILQ_REMOVE(&g->reslist, res, next);
---
base-commit: 209b2afaface001c7d4d981e38f186afe7b24a50
change-id: 20260729-block-2efd66ec23cd
Best regards,
--
Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>