Hi On Thu, Jul 16, 2026 at 2:35 PM Akihiko Odaki <[email protected]> wrote: > > On 2026/07/16 16:55, [email protected] wrote: > > From: Marc-André Lureau <[email protected]> > > > > Both virgl_cmd_submit_3d() and rutabaga_cmd_submit_3d() pass the > > guest-controlled cs.size directly to malloc() without bounds checking. A > > malicious guest can set cs.size to an arbitrarily large value, causing > > an OOM abort that crashes the QEMU process. > > I rechecked and found vhost-user-gpu is also affected. The changes of > virgl and rutabaga look good to me.
Yes, I did it for vhost-user-gpu too (now outdated): https://patchew.org/QEMU/[email protected]/ I should probably merge them together and resend then. > > Regards, > Akihiko Odaki > > > > > Checking cs.size against the descriptor payload length (iov_size) is not > > sufficient: indirect descriptor tables can repeat entries aliasing the > > same guest-physical range, inflating iov_size() to nearly 4 GiB while > > referring to only a small amount of unique memory. > > > > Instead, cap cs.size at 4 MiB. With 4 KiB pages and QEMU's > > VIRTQUEUE_MAX_SIZE (1024) mapped-iov limit, the Linux virtio driver > > cannot carry more than ~4 MiB of inline command data, so legitimate > > submissions are unaffected. > > > > Fixes: 9d9e152136bd ("virtio-gpu: add 3d mode and virgl rendering support.") > > Fixes: 1dcc6adbc168 ("gfxstream + rutabaga: add initial support for > > gfxstream") > > Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/3776 > > Reported-by: [email protected] > > Signed-off-by: Marc-André Lureau <[email protected]> > > --- > > include/hw/virtio/virtio-gpu.h | 8 ++++++++ > > hw/display/virtio-gpu-rutabaga.c | 8 ++++++++ > > hw/display/virtio-gpu-virgl.c | 8 ++++++++ > > 3 files changed, 24 insertions(+) > > > > diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h > > index f69fc194627..c10bfbd596f 100644 > > --- a/include/hw/virtio/virtio-gpu.h > > +++ b/include/hw/virtio/virtio-gpu.h > > @@ -299,6 +299,14 @@ struct VirtIOGPURutabaga { > > struct rutabaga *rutabaga; > > }; > > > > +/* > > + * With 4 KiB pages and QEMU's VIRTQUEUE_MAX_SIZE (1024) mapped-iov > > + * limit, the largest inline command is ~4 MiB. Cap submit_3d > > + * allocations to this value to prevent a malicious guest from > > + * triggering an OOM abort via an inflated cs.size field. > > + */ > > +#define VIRTIO_GPU_MAX_CMD_SUBMIT_SIZE (4 * 1024 * 1024) > > + > > #define VIRTIO_GPU_FILL_CMD(out) do { \ > > size_t virtiogpufillcmd_s_ = \ > > iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, 0, \ > > diff --git a/hw/display/virtio-gpu-rutabaga.c > > b/hw/display/virtio-gpu-rutabaga.c > > index 6ff12639012..4d7d7b24592 100644 > > --- a/hw/display/virtio-gpu-rutabaga.c > > +++ b/hw/display/virtio-gpu-rutabaga.c > > @@ -351,6 +351,14 @@ rutabaga_cmd_submit_3d(VirtIOGPU *g, > > VIRTIO_GPU_FILL_CMD(cs); > > trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size); > > > > + if (cs.size > VIRTIO_GPU_MAX_CMD_SUBMIT_SIZE) { > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "%s: command buffer too large (%u)\n", > > + __func__, cs.size); > > + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; > > + return; > > + } > > + > > buf = g_new0(uint8_t, cs.size); > > s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, > > sizeof(cs), buf, cs.size); > > diff --git a/hw/display/virtio-gpu-virgl.c b/hw/display/virtio-gpu-virgl.c > > index 60c78af06a4..d9e5b011049 100644 > > --- a/hw/display/virtio-gpu-virgl.c > > +++ b/hw/display/virtio-gpu-virgl.c > > @@ -607,6 +607,14 @@ static void virgl_cmd_submit_3d(VirtIOGPU *g, > > VIRTIO_GPU_FILL_CMD(cs); > > trace_virtio_gpu_cmd_ctx_submit(cs.hdr.ctx_id, cs.size); > > > > + if (cs.size > VIRTIO_GPU_MAX_CMD_SUBMIT_SIZE) { > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "%s: command buffer too large (%u)\n", > > + __func__, cs.size); > > + cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; > > + return; > > + } > > + > > buf = g_malloc(cs.size); > > s = iov_to_buf(cmd->elem.out_sg, cmd->elem.out_num, > > sizeof(cs), buf, cs.size); > >
