[PATCH] vhost-user-gpu: fix integer overflow in buffer allocation

marcandre.lureau@redhat.com posted 1 patch 1 day, 10 hours ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20260710134720.2317856-1-marcandre.lureau@redhat.com
Maintainers: "Marc-André Lureau" <marcandre.lureau@redhat.com>, "Michael S. Tsirkin" <mst@redhat.com>, Stefano Garzarella <sgarzare@redhat.com>
contrib/vhost-user-gpu/vhost-user-gpu.c |  8 +++++++-
contrib/vhost-user-gpu/vugbm.c          | 11 +++++++++--
2 files changed, 16 insertions(+), 3 deletions(-)
[PATCH] vhost-user-gpu: fix integer overflow in buffer allocation
Posted by marcandre.lureau@redhat.com 1 day, 10 hours ago
From: Marc-André Lureau <marcandre.lureau@redhat.com>

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" <vr@darknavy.com>
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3940
Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
---
 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;
 }
@@ -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


Re: [PATCH] vhost-user-gpu: fix integer overflow in buffer allocation
Posted by Philippe Mathieu-Daudé 1 day, 8 hours ago
On 10/7/26 15:47, marcandre.lureau@redhat.com wrote:
> From: Marc-André Lureau <marcandre.lureau@redhat.com>
> 
> 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" <vr@darknavy.com>
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3940
> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com>
> ---
>   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/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);

Just curious, would this also work safely?

        buf->mmap = g_malloc_n(4, buf->width * buf->height);

The GLib description is:

   This function is similar to g_malloc(),
   allocating (n_blocks * n_block_bytes) bytes,
   but care is taken to detect possible overflow
   during multiplication.

>       buf->stride = buf->width * 4;
>       return true;
>   }