On Fri, Jul 10, 2026 at 05:47:19PM +0400, [email protected] wrote:
> From: Marc-André Lureau <[email protected]>
>
> A malicious guest can trigger a heap buffer overflow in the
> vhost-user-gpu backend by sending a VIRTIO_GPU_CMD_RESOURCE_CREATE_2D
> with large width and height values (e.g. 65537x65537). The allocation
> size width * height * 4 silently wraps in uint32_t arithmetic,
> resulting in a much smaller allocation than expected. Subsequent
> VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D writes past the heap buffer.
>
> The in-tree virtio-gpu device (hw/display/virtio-gpu.c) already handles
> this via calc_image_hostmem() with uint64_t arithmetic and an overflow
> check. Apply the same approach to the vhost-user-gpu contrib backend:
>
> - Add an overflow check in vugbm_buffer_create() rejecting dimensions
> where width * height * 4 exceeds UINT32_MAX
> - Promote the size arithmetic to uint64_t in mem_alloc_bo() and
> udmabuf_get_size()
> - Check the return value of vugbm_buffer_create() in
> vg_resource_create_2d(), which was previously ignored
>
> Fixes: CVE-2026-15264
> Reported-by: "Vulnerability Report" <[email protected]>
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3940
> Signed-off-by: Marc-Andre Lureau <[email protected]>
> ---
> contrib/vhost-user-gpu/vhost-user-gpu.c | 8 +++++++-
> contrib/vhost-user-gpu/vugbm.c | 11 +++++++++--
> 2 files changed, 16 insertions(+), 3 deletions(-)
>
> diff --git a/contrib/vhost-user-gpu/vhost-user-gpu.c
> b/contrib/vhost-user-gpu/vhost-user-gpu.c
> index bb41758e345..ee9858c397c 100644
> --- a/contrib/vhost-user-gpu/vhost-user-gpu.c
> +++ b/contrib/vhost-user-gpu/vhost-user-gpu.c
> @@ -388,7 +388,13 @@ vg_resource_create_2d(VuGpu *g,
> cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
> return;
> }
> - vugbm_buffer_create(&res->buffer, &g->gdev, c2d.width, c2d.height);
> + if (!vugbm_buffer_create(&res->buffer, &g->gdev, c2d.width, c2d.height))
> {
> + g_critical("%s: buffer creation failed %d %d %d",
> + __func__, c2d.resource_id, c2d.width, c2d.height);
> + g_free(res);
> + cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
> + return;
> + }
> res->image = pixman_image_create_bits(pformat,
> c2d.width,
> c2d.height,
> diff --git a/contrib/vhost-user-gpu/vugbm.c b/contrib/vhost-user-gpu/vugbm.c
> index 503d0a4566f..710d5452977 100644
> --- a/contrib/vhost-user-gpu/vugbm.c
> +++ b/contrib/vhost-user-gpu/vugbm.c
> @@ -13,7 +13,7 @@
> static bool
> mem_alloc_bo(struct vugbm_buffer *buf)
> {
> - buf->mmap = g_malloc(buf->width * buf->height * 4);
> + buf->mmap = g_malloc((uint64_t)buf->width * buf->height * 4);
> buf->stride = buf->width * 4;
> return true;
> }
I apologise but we are still allocating up to 2Gbytes is that really
sane? Isn't there a limit on these things? Like the size of the screen?
And width * 4 can still wrap around and then will it really behave
correctly?
> @@ -53,7 +53,8 @@ struct udmabuf_create {
> static size_t
> udmabuf_get_size(struct vugbm_buffer *buf)
> {
> - return ROUND_UP(buf->width * buf->height * 4,
> qemu_real_host_page_size());
> + return ROUND_UP((uint64_t)buf->width * buf->height * 4,
> + qemu_real_host_page_size());
> }
>
> static bool
> @@ -293,6 +294,12 @@ bool
> vugbm_buffer_create(struct vugbm_buffer *buffer, struct vugbm_device *dev,
> uint32_t width, uint32_t height)
> {
> + uint64_t size = (uint64_t)width * height * 4;
> + if (size > UINT32_MAX) {
> + g_warning("buffer dimensions too large: %ux%u", width, height);
> + return false;
> + }
> +
> buffer->dev = dev;
> buffer->width = width;
> buffer->height = height;
> --
> 2.55.0