Re: [PATCH v2] virtio-gpu: use g_try_malloc to avoid guest-triggered abort

Akihiko Odaki <[email protected]>
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
On 2026/07/28 19:15, [email protected] wrote:
> From: Marc-André Lureau <[email protected]>
> 
> Use g_try_malloc/g_try_new0 for guest-controlled allocation, so failure
> returns an error to the guest rather than crashing the host (glib
> behaviour).
> 
> Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3898
> 
> Signed-off-by: Marc-André Lureau <[email protected]>
> ---
> Based-on: <[email protected]> ("[PATCH] vhost-user-gpu: fix integer overflow in buffer allocation")
> v2:
>   - accept NULL 0-size allocations
> ---
>   contrib/vhost-user-gpu/vhost-user-gpu.c | 25 +++++++++++++++++--------
>   contrib/vhost-user-gpu/virgl.c          |  6 +++++-
>   contrib/vhost-user-gpu/vugbm.c          |  5 ++++-
>   hw/display/virtio-gpu-rutabaga.c        | 14 ++++++++++++--
>   hw/display/virtio-gpu-virgl.c           |  6 +++++-
>   hw/display/virtio-gpu.c                 |  5 ++++-
>   6 files changed, 47 insertions(+), 14 deletions(-)
> 
> diff --git a/contrib/vhost-user-gpu/vhost-user-gpu.c b/contrib/vhost-user-gpu/vhost-user-gpu.c
> index ee9858c397ce..0fd115300425 100644
> --- a/contrib/vhost-user-gpu/vhost-user-gpu.c
> +++ b/contrib/vhost-user-gpu/vhost-user-gpu.c
> @@ -487,7 +487,7 @@ vg_create_mapping_iov(VuGpu *g,
>                         struct virtio_gpu_ctrl_command *cmd,
>                         struct iovec **iov)
>   {
> -    struct virtio_gpu_mem_entry *ents;
> +    g_autofree struct virtio_gpu_mem_entry *ents = NULL;
>       size_t esize, s;
>       int i;
>   
> @@ -498,17 +498,22 @@ vg_create_mapping_iov(VuGpu *g,
>       }
>   
>       esize = sizeof(*ents) * ab->nr_entries;
> -    ents = g_malloc(esize);
> +    ents = g_try_malloc(esize);
> +    if (!ents && esize) {
> +        return -1;
> +    }
>       s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
>                      sizeof(*ab), ents, esize);
>       if (s != esize) {
>           g_critical("%s: command data size incorrect %zu vs %zu",
>                      __func__, s, esize);
> -        g_free(ents);
>           return -1;
>       }
>   
> -    *iov = g_new0(struct iovec, ab->nr_entries);
> +    *iov = g_try_new0(struct iovec, ab->nr_entries);
> +    if (!*iov && ab->nr_entries) {
> +        return -1;
> +    }
>       for (i = 0; i < ab->nr_entries; i++) {
>           uint64_t len = ents[i].length;
>           (*iov)[i].iov_len = ents[i].length;
> @@ -517,12 +522,10 @@ vg_create_mapping_iov(VuGpu *g,
>               g_critical("%s: resource %d element %d",
>                          __func__, ab->resource_id, i);
>               g_free(*iov);
> -            g_free(ents);
>               *iov = NULL;
>               return -1;
>           }
>       }
> -    g_free(ents);
>       return 0;
>   }
>   
> @@ -828,8 +831,14 @@ vg_resource_flush(VuGpu *g,
>                   PIXMAN_FORMAT_BPP(pixman_image_get_format(res->image)) / 8;
>               size_t size = width * height * bpp;
>   
> -            void *p = g_malloc(VHOST_USER_GPU_HDR_SIZE +
> -                               sizeof(VhostUserGpuUpdate) + size);
> +            void *p = g_try_malloc(VHOST_USER_GPU_HDR_SIZE +
> +                                   sizeof(VhostUserGpuUpdate) + size);
> +            if (!p) {
> +                pixman_region_fini(&region);
> +                pixman_region_fini(&finalregion);
> +                cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
> +                break;
> +            }
>               VhostUserGpuMsg *msg = p;
>               msg->request = VHOST_USER_GPU_UPDATE;
>               msg->size = sizeof(VhostUserGpuUpdate) + size;
> diff --git a/contrib/vhost-user-gpu/virgl.c b/contrib/vhost-user-gpu/virgl.c
> index 550fd03bf5c4..20bae57d0fe4 100644
> --- a/contrib/vhost-user-gpu/virgl.c
> +++ b/contrib/vhost-user-gpu/virgl.c
> @@ -209,7 +209,11 @@ virgl_cmd_submit_3d(VuGpu *g,
>           return;
>       }
>   
> -    buf = g_malloc(cs.size);
> +    buf = g_try_malloc(cs.size);
> +    if (!buf && cs.size) {
> +        cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
> +        return;
> +    }
>       s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
>                      sizeof(cs), buf, cs.size);
>       if (s != cs.size) {
> diff --git a/contrib/vhost-user-gpu/vugbm.c b/contrib/vhost-user-gpu/vugbm.c
> index 710d54529779..e2d8385fd857 100644
> --- a/contrib/vhost-user-gpu/vugbm.c
> +++ b/contrib/vhost-user-gpu/vugbm.c
> @@ -13,7 +13,10 @@
>   static bool
>   mem_alloc_bo(struct vugbm_buffer *buf)
>   {
> -    buf->mmap = g_malloc((uint64_t)buf->width * buf->height * 4);
> +    buf->mmap = g_try_malloc((uint64_t)buf->width * buf->height * 4);
> +    if (!buf->mmap && buf->width && buf->height) {
> +        return false;
> +    }
>       buf->stride = buf->width * 4;
>       return true;
>   }
> diff --git a/hw/display/virtio-gpu-rutabaga.c b/hw/display/virtio-gpu-rutabaga.c
> index e28aad94eead..60f64d9a8fa7 100644
> --- a/hw/display/virtio-gpu-rutabaga.c
> +++ b/hw/display/virtio-gpu-rutabaga.c
> @@ -360,10 +360,20 @@ rutabaga_cmd_submit_3d(VirtIOGPU *g,
>           return;
>       }
>   
> -    buf = g_new0(uint8_t, cs.size);
> +    buf = g_try_new0(uint8_t, cs.size);
> +    if (!buf && cs.size) {
> +        cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
> +        return;
> +    }
>       s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
>                      sizeof(cs), buf, cs.size);
> -    CHECK(s == cs.size, cmd);
> +    if (s != cs.size) {
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +                      "%s: size mismatch (%zu/%u)\n",
> +                      __func__, s, cs.size);
> +        cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER;
> +        return;
> +    }
>   
>       rutabaga_cmd.ctx_id = cs.hdr.ctx_id;
>       rutabaga_cmd.cmd = buf;
> diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c
> index d9e5b0110497..028ab776df6a 100644
> --- a/hw/display/virtio-gpu-virgl.c
> +++ b/hw/display/virtio-gpu-virgl.c
> @@ -615,7 +615,11 @@ static void virgl_cmd_submit_3d(VirtIOGPU *g,
>           return;
>       }
>   
> -    buf = g_malloc(cs.size);
> +    buf = g_try_malloc(cs.size);
> +    if (!buf && cs.size) {
> +        cmd->error = VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY;
> +        return;
> +    }
>       s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
>                      sizeof(cs), buf, cs.size);
>       if (s != cs.size) {
> diff --git a/hw/display/virtio-gpu.c b/hw/display/virtio-gpu.c
> index 8607d0c0b581..9bacd38b4521 100644
> --- a/hw/display/virtio-gpu.c
> +++ b/hw/display/virtio-gpu.c
> @@ -892,7 +892,10 @@ int virtio_gpu_create_mapping_iov(VirtIOGPU *g,
>       }
>   
>       esize = sizeof(*ents) * nr_entries;
> -    ents = g_malloc(esize);
> +    ents = g_try_malloc(esize);
> +    if (!ents && esize) {
> +        return -1;
> +    }

This converts the entry allocation to g_try_malloc(), but the resulting 
mapping arrays still grow with aborting g_renew() calls. 
dma_memory_map() may return only part of an entry; with fragmented IOMMU 
mappings, guest-controlled entries can expand into more IOVs than 
nr_entries.

Regards,
Akihiko Odaki

>       s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num,
>                      offset, ents, esize);
>       if (s != esize) {
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.