Hi

On Tue, Jul 28, 2026 at 6:28 PM Akihiko Odaki
<[email protected]> wrote:
>
> 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.
>

The goal is not to make QEMU OOM-safe. Even when malloc returns
non-zero we may reach that and get killed. This patch is more a safety
guard for easy guest triggered allocations that can crash QEMU.


Reply via email to