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); > } >