virtio_gpu_resource_detach_backing() releases a resource's mapping
through virtio_gpu_cleanup_mapping(), which for a blob resource unmaps
and releases the udmabuf backing.  Two lifetime problems follow:

1. A blob resource may currently back a scanout: do_set_scanout()
   creates a pixman surface that aliases res->blob memory
   (scanout->ds -> data inside res->blob).  detach does not drop those
   scanouts, so after cleanup_mapping() releases the backing, a later
   display refresh reads freed memory (use-after-free).  Drop every
   scanout that still references the resource before unmapping,
   mirroring what virtio_gpu_resource_destroy() already does before it
   frees a resource.

2. cleanup_mapping() never clears res->blob after fini_udmabuf(), so
   the resource keeps a dangling pointer to released memory while it
   stays on reslist (detach does not remove the resource; the guest can
   re-attach backing later).  NULL it out so code that consults
   res->blob (e.g. cursor/scanout paths) cannot touch freed memory.

RFC: this overlaps the upstream virtio-gpu blob/DETACH_BACKING fix
series (CVE-2026-66020 family); confirm it does not duplicate an
in-flight version before applying.

Signed-off-by: Hongyan Xu <[email protected]>
---
 hw/display/virtio-gpu.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
index 55a1c7f80f..d0d15deb28 100644
--- a/hw/display/virtio-gpu.c
+++ b/hw/display/virtio-gpu.c
@@ -1030,6 +1030,7 @@ void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
 
     if (res->blob) {
         virtio_gpu_fini_udmabuf(g, res);
+        res->blob = NULL;
     }
 }
 
@@ -1096,6 +1097,23 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g,
     if (!res) {
         return;
     }
+
+    /*
+     * A blob resource may be backing a scanout: the scanout's surface
+     * aliases res->blob memory (do_set_scanout).  cleanup_mapping()
+     * below unmaps/releases that memory, so drop every scanout that
+     * still references this resource first, mirroring what
+     * virtio_gpu_resource_destroy() does before it frees a resource.
+     */
+    if (res->scanout_bitmask) {
+        int i;
+
+        for (i = 0; i < g->parent_obj.conf.max_outputs; i++) {
+            if (res->scanout_bitmask & (1 << i)) {
+                virtio_gpu_disable_scanout(g, i);
+            }
+        }
+    }
     virtio_gpu_cleanup_mapping(g, res);
 }
 
-- 
2.50.1.windows.1


Reply via email to