Re: [PATCH v2] hw/display/virtio-gpu: fix use-after-free on blob detach backing

Akihiko Odaki <[email protected]>
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
On 2026/07/28 19:58, [email protected] wrote:
> From: Marc-André Lureau <[email protected]>
> 
> virtio_gpu_cleanup_mapping() tears down the udmabuf mapping (or, for the
> small-iov case, the guest memory mapping) via virtio_gpu_fini_udmabuf(),
> but leaves res->blob pointing at it afterwards. Once a blob resource
> goes through RESOURCE_DETACH_BACKING, res->blob is left dangling while
> res->blob_size is still non-zero.
> 
> virtio_gpu_update_cursor_data() only checks res->blob_size before
> copying from res->blob, so UPDATE_CURSOR on a detached blob resource
> makes QEMU memcpy from freed memory.
> 
> virtio_gpu_do_set_scanout() also creates scanout->ds over
> res->blob + fb->offset. RESOURCE_DETACH_BACKING leaves that surface
> installed, so a subsequent display refresh can still read the backing
> after virtio_gpu_fini_udmabuf() has unmapped it.
> 
> Disable any active scanouts referencing the resource before tearing down
> its backing, clear res->blob afterwards, and check it before
> dereferencing in virtio_gpu_update_cursor_data().
> 
> Fixes: CVE-2026-66020
> Fixes: bdd53f739273 ("virtio-gpu: Update cursor data using blob")
> Fixes: 32db3c63ae11 ("virtio-gpu: Add virtio_gpu_set_scanout_blob")
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3881
> Reported-by: 章鱼哥@aipy (www.aipyaipy.com)
> Reported-by: swing <[email protected]>
> Signed-off-by: Marc-André Lureau <[email protected]>
> ---
> v3:
>   - only disable blob-based scanouts on detach_backing
> ---
>   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 574e68992925..9bacd38b4521 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c
> @@ -63,8 +63,16 @@ void virtio_gpu_update_cursor_data(VirtIOGPU *g,
>           }
>           data = pixman_image_get_data(res->image);
>       } else {
> +        if (!res->blob) {
> +            qemu_log_mask(LOG_GUEST_ERROR, "%s: resource %d has no blob\n",
> +                          __func__, resource_id);
> +            return;
> +        }
>           if (res->blob_size < (s->current_cursor->width *
>                                 s->current_cursor->height * 4)) {
> +            qemu_log_mask(LOG_GUEST_ERROR,
> +                          "%s: blob size too small for resource %d\n",
> +                          __func__, resource_id);
>               return;
>           }
>           data = res->blob;
> @@ -974,6 +982,7 @@ void virtio_gpu_cleanup_mapping(VirtIOGPU *g,
>   
>       if (res->blob) {
>           virtio_gpu_fini_udmabuf(g, res);
> +        res->blob = NULL;
>       }
>   }
>   
> @@ -1039,6 +1048,15 @@ virtio_gpu_resource_detach_backing(VirtIOGPU *g,
>       if (!res) {
>           return;
>       }
> +
> +    if (res->blob) {
> +        for (int i = 0; i < g->parent_obj.conf.max_outputs; i++) {
> +            if (res->scanout_bitmask & (1 << i)) {
> +                virtio_gpu_disable_scanout(g, i);

virtio_gpu_disable_scanout() switches the software surface but does not 
call qemu_console_gl_scanout_disable() and 
qemu_console_gl_release_dmabuf(). Consequently, GTK/SDL can remain in 
dmabuf scanout mode and continue displaying/pinning the imported guest 
backing after QEMU considers it detached. virtio_gpu_fini_udmabuf() only 
closes the fd.

Regards,
Akihiko Odaki

> +            }
> +        }
> +    }
> +
>       virtio_gpu_cleanup_mapping(g, res);
>   }
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.