Re: [PATCH] drm/virtio: reclaim pending vbufs before tearing down vqs

[email protected] Sun, 02 Aug 2026 15:56:23 +0000
Newsgroups org.freedesktop.lists.dri-devel
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:

New issues:
- [High] Data race and potential Use-After-Free between `dequeue_work` and `virtio_gpu_reclaim_vbufs` / `del_vqs`.

Pre-existing issues:
- [High] Memory leak of GEM objects (bo) due to missing cleanup of `vbuf->resp_cb_data` in `virtio_gpu_reclaim_vbufs`.
- [High] Permanent leak of `dma_fence` objects and potential infinite wait for stranded commands.
--

--- Patch [1]: [PATCH] drm/virtio: reclaim pending vbufs before tearing down vqs ---
commit 9dfeaad280a2a9a1d77041d3cd3a7b47ba0d4e3a
Author: Anuj Bolewar <[email protected]>

drm/virtio: reclaim pending vbufs before tearing down vqs

This commit attempts to drain any buffers still sitting in the control and
cursor virtqueues in virtio_gpu_deinit() after the device has been reset
and before the virtqueues are deleted to prevent a cache shutdown warning.

Link: https://syzkaller.appspot.com/bug?extid=06f9b2a53ba4a5a47644

> diff --git a/drivers/gpu/drm/virtio/virtgpu_kms.c b/drivers/gpu/drm/virtio/virtgpu_kms.c
> index b4329f28e9766..e5a6ae679f363 100644
> --- a/drivers/gpu/drm/virtio/virtgpu_kms.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_kms.c
> @@ -298,6 +298,7 @@ void virtio_gpu_deinit(struct drm_device *dev)
>  	flush_work(&vgdev->cursorq.dequeue_work);
>  	flush_work(&vgdev->config_changed_work);
>  	virtio_reset_device(vgdev->vdev);
> +	virtio_gpu_reclaim_vbufs(vgdev);

[Severity: High]
Could a late interrupt re-queue the work after it has been flushed?

Since flush_work() is called before virtio_reset_device(), if an interrupt
arrives just after flush_work() completes but before virtio_reset_device()
is called, the worker could be re-queued.

Because virtio_reset_device() stops new interrupts but doesn't cancel
pending asynchronous work, could the rescheduled worker execute concurrently
with the newly added virtio_gpu_reclaim_vbufs() and access the virtqueue?

>  	vgdev->vdev->config->del_vqs(vgdev->vdev);
>  }
>  
> diff --git a/drivers/gpu/drm/virtio/virtgpu_vq.c b/drivers/gpu/drm/virtio/virtgpu_vq.c
> index e5e1af8b8e8a0..95d7a9ef0d99d 100644
> --- a/drivers/gpu/drm/virtio/virtgpu_vq.c
> +++ b/drivers/gpu/drm/virtio/virtgpu_vq.c

[ ... ]

> @@ -208,6 +208,19 @@ static void free_vbuf(struct virtio_gpu_device *vgdev,
>  	kmem_cache_free(vgdev->vbufs, vbuf);
>  }
>  
> +void virtio_gpu_reclaim_vbufs(struct virtio_gpu_device *vgdev)
> +{
> +	struct virtio_gpu_vbuffer *vbuf;
> +
> +	while ((vbuf = virtqueue_detach_unused_buf(vgdev->ctrlq.vq))) {

[Severity: High]
If the dequeue_work worker is still running as mentioned above, could it
race with this lockless manipulation of the virtqueue?

The worker uses virtqueue_get_buf() under vgdev->ctrlq.qlock, but
virtqueue_detach_unused_buf() is called here without acquiring the lock.
This might lead to concurrent modification of the virtqueue internal state
or a use-after-free if the worker accesses it after the queues are deleted.

> +		if (vbuf->objs)
> +			virtio_gpu_array_put_free(vbuf->objs);

[Severity: High]
This isn't a bug introduced by this patch, but does this loop overlook
vbuf->resp_cb_data?

When the device is reset, pending VIRTIO_GPU_CMD_RESOURCE_UNREF commands are
left in the virtqueue. If they are detached and freed here without executing
their resp_cb callbacks (like virtio_gpu_cmd_unref_cb) or manually cleaning
up vbuf->resp_cb_data, does it permanently leak the underlying GEM objects
and their associated IDAs?

[Severity: High]
This is a pre-existing issue, but does this loop also silently discard
command buffers without signaling their associated fences?

When commands are queued with a fence via
virtio_gpu_queue_fenced_ctrl_buffer(), a reference to the dma_fence is added
to the vgdev->fence_drv.fences list. If virtio_gpu_reclaim_vbufs() detaches
and frees the vbufs without extracting or signaling these fences, could any
waiters hang indefinitely?

> +		free_vbuf(vgdev, vbuf);
> +	}
> +	while ((vbuf = virtqueue_detach_unused_buf(vgdev->cursorq.vq)))
> +		free_vbuf(vgdev, vbuf);
> +}

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1