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
