Hi

On Sat, Jul 25, 2026 at 7:46 PM Michael S. Tsirkin <[email protected]> wrote:
>
> 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?
>

By default, builtin-in virtio-gpu has a cumulative max hostmem=256mb
(https://www.qemu.org/docs/master/system/devices/virtio/virtio-gpu.html#virtio-gpu-virglrenderer).
For 3d/gpu resources this may be considered very low in today's
usages.

Vulkan 1.4+ requires 8192 in dimensions and has
VK_FORMAT_R64G64B64A64_SFLOAT = 256bpp
https://docs.vulkan.org/refpages/latest/refpages/source/Required_Limits.html#limits-required

So pretty much vulkan 1.4+ requires that a graphics card "accepts" 4Gb
allocations.

I don't think the virtio-gpu spec should impose a maximum limit.

The qemu vhost-user-gpu implementation could benefit from having a
hostmem tracking, similar to the built-in device.

>
> > @@ -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
>
>

Reply via email to