Commit 884363589b for qemu.org

commit 884363589b68049cb344b8f8089464bada32a8e7
Author: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Date:   Tue Aug 25 16:28:51 2026 +0900

    hw/display/virtio-gpu: Validate resource per command

    virtio_gpu_find_check_resource() checks if the resource has backing
    storage if require_backing is true, but the condition conflates backing
    storage attachment with host representation; it checks
    !res->iov || (!res->image && !res->blob), but !res->iov is sufficient.

    Furthermore, its callers passing true as require_backing have different
    requirements:

    - virtio_gpu_transfer_to_host_2d() requires a non-blob with
      backing storage.
    - virtio_gpu_set_scanout() requires a non-blob but does not require
      backing storage.
    - virtio_gpu_set_scanout_blob() requires a blob with backing storage.
    - virtio_gpu_resource_detach_backing() accepts any resource.

    Remove the require_backing parameter and open-code checks appropriate
    for each function instead.

    Fixes: 25c001a40346 ("virtio-gpu: Add virtio_gpu_find_check_resource")
    Fixes: e0933d91b1cd ("virtio-gpu: Add virtio_gpu_resource_create_blob")
    Fixes: 32db3c63ae11 ("virtio-gpu: Add virtio_gpu_set_scanout_blob")
    Signed-off-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
    Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
    Message-ID: <20260825-dmabuf-v2-5-b3d64d3b9a0e@rsg.ci.i.u-tokyo.ac.jp>

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 01549d29d8..55a1c7f80f 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -37,7 +37,6 @@

 static struct virtio_gpu_simple_resource *
 virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id,
-                               bool require_backing,
                                const char *caller, uint32_t *error);

 static void virtio_gpu_reset_bh(void *opaque);
@@ -50,8 +49,7 @@ void virtio_gpu_update_cursor_data(VirtIOGPU *g,
     uint32_t pixels;
     void *data;

-    res = virtio_gpu_find_check_resource(g, resource_id, false,
-                                         __func__, NULL);
+    res = virtio_gpu_find_check_resource(g, resource_id, __func__, NULL);
     if (!res) {
         return;
     }
@@ -128,7 +126,6 @@ virtio_gpu_find_resource(VirtIOGPU *g, uint32_t resource_id)

 static struct virtio_gpu_simple_resource *
 virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id,
-                               bool require_backing,
                                const char *caller, uint32_t *error)
 {
     struct virtio_gpu_simple_resource *res;
@@ -143,17 +140,6 @@ virtio_gpu_find_check_resource(VirtIOGPU *g, uint32_t resource_id,
         return NULL;
     }

-    if (require_backing) {
-        if (!res->iov || (!res->image && !res->blob)) {
-            qemu_log_mask(LOG_GUEST_ERROR, "%s: no backing storage %d\n",
-                          caller, resource_id);
-            if (error) {
-                *error = VIRTIO_GPU_RESP_ERR_UNSPEC;
-            }
-            return NULL;
-        }
-    }
-
     return res;
 }

@@ -474,9 +460,24 @@ static void virtio_gpu_transfer_to_host_2d(VirtIOGPU *g,
     virtio_gpu_t2d_bswap(&t2d);
     trace_virtio_gpu_cmd_res_xfer_toh_2d(t2d.resource_id);

-    res = virtio_gpu_find_check_resource(g, t2d.resource_id, true,
+    res = virtio_gpu_find_check_resource(g, t2d.resource_id,
                                          __func__, &cmd->error);
-    if (!res || res->blob) {
+    if (!res) {
+        return;
+    }
+
+    if (!res->image) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource %d is a blob\n",
+                      __func__, t2d.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+
+    if (!res->iov) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: resource %d has no backing storage\n",
+                      __func__, t2d.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
         return;
     }

@@ -533,7 +534,7 @@ static void virtio_gpu_resource_flush(VirtIOGPU *g,
     trace_virtio_gpu_cmd_res_flush(rf.resource_id,
                                    rf.r.width, rf.r.height, rf.r.x, rf.r.y);

-    res = virtio_gpu_find_check_resource(g, rf.resource_id, false,
+    res = virtio_gpu_find_check_resource(g, rf.resource_id,
                                          __func__, &cmd->error);
     if (!res) {
         return;
@@ -771,12 +772,19 @@ static void virtio_gpu_set_scanout(VirtIOGPU *g,
         return;
     }

-    res = virtio_gpu_find_check_resource(g, ss.resource_id, true,
+    res = virtio_gpu_find_check_resource(g, ss.resource_id,
                                          __func__, &cmd->error);
     if (!res) {
         return;
     }

+    if (!res->image) {
+        qemu_log_mask(LOG_GUEST_ERROR, "%s: resource %d is a blob\n",
+                      __func__, ss.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+
     fb.format = pixman_image_get_format(res->image);
     bytes_pp = virtio_gpu_format_bytes_pp(fb.format);
     fb.width  = pixman_image_get_width(res->image);
@@ -866,12 +874,28 @@ static void virtio_gpu_set_scanout_blob(VirtIOGPU *g,
         return;
     }

-    res = virtio_gpu_find_check_resource(g, ss.resource_id, true,
+    res = virtio_gpu_find_check_resource(g, ss.resource_id,
                                          __func__, &cmd->error);
     if (!res) {
         return;
     }

+    if (res->image) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: resource %d is not a blob\n",
+                      __func__, ss.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+
+    if (!res->iov) {
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: resource %d has no backing storage\n",
+                      __func__, ss.resource_id);
+        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID;
+        return;
+    }
+
     if (!virtio_gpu_scanout_blob_to_fb(&fb, &ss, res->blob_size)) {
         cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
         return;
@@ -1067,7 +1091,7 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g,
     virtio_gpu_bswap_32(&detach, sizeof(detach));
     trace_virtio_gpu_cmd_res_back_detach(detach.resource_id);

-    res = virtio_gpu_find_check_resource(g, detach.resource_id, true,
+    res = virtio_gpu_find_check_resource(g, detach.resource_id,
                                          __func__, &cmd->error);
     if (!res) {
         return;