Commit 1f24066fc8 for qemu.org
commit 1f24066fc88d33455ee54a20f29994d9e69997ba
Author: Ankur Saini <ankur98saini@gmail.com>
Date: Mon Aug 3 22:39:21 2026 +0530
virtio-gpu: reject requests with short/truncated control headers
A short control request can leave command data partially initialized.
For the common header, guest-controlled flags can then cause stale fence
metadata to be returned to the guest.
The command fill helpers detect a short copy but only log and return.
For the common header this leaves the request without any completion;
for type-specific commands the caller still completes the request but
reports VIRTIO_GPU_RESP_OK_NODATA, masking the error. Make
VIRTIO_GPU_FILL_CMD() clear the partially copied object and complete the
request with ERR_INVALID_PARAMETER. Make VUGPU_FILL_CMD() report the same
error through the existing vhost-user-gpu dispatcher. This also rejects
truncated type-specific commands.
The vhost-user-gpu common header is copied outside VUGPU_FILL_CMD(), so
clear it and complete the request directly when that copy is short.
Fixes: CVE-2026-18054
Resolves: https://gitlab.com/qemu-project/qemu/-/work_items/4094
Reported-by: Ankur Saini <ankur98saini@gmail.com>
Suggested-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Signed-off-by: Ankur Saini <ankur98saini@gmail.com>
Reviewed-by: Akihiko Odaki <odaki@rsg.ci.i.u-tokyo.ac.jp>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Message-ID: <20260803-virtio-gpu-short-header-v3-1-936c1daa8e61@gmail.com>
diff --git a/contrib/vhost-user-gpu/vhost-user-gpu.c b/contrib/vhost-user-gpu/vhost-user-gpu.c
index ee9858c397..7864881509 100644
--- a/contrib/vhost-user-gpu/vhost-user-gpu.c
+++ b/contrib/vhost-user-gpu/vhost-user-gpu.c
@@ -930,16 +930,19 @@ vg_handle_ctrl(VuDev *dev, int qidx)
if (len != sizeof(cmd->cmd_hdr)) {
g_warning("%s: command size incorrect %zu vs %zu\n",
__func__, len, sizeof(cmd->cmd_hdr));
- }
-
- virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr);
- g_debug("%d %s\n", cmd->cmd_hdr.type,
- vg_cmd_to_string(cmd->cmd_hdr.type));
-
- if (vg->virgl) {
- vg_virgl_process_cmd(vg, cmd);
+ memset(&cmd->cmd_hdr, 0, sizeof(cmd->cmd_hdr));
+ vg_ctrl_response_nodata(
+ vg, cmd, VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER);
} else {
- vg_process_cmd(vg, cmd);
+ virtio_gpu_ctrl_hdr_bswap(&cmd->cmd_hdr);
+ g_debug("%d %s\n", cmd->cmd_hdr.type,
+ vg_cmd_to_string(cmd->cmd_hdr.type));
+
+ if (vg->virgl) {
+ vg_virgl_process_cmd(vg, cmd);
+ } else {
+ vg_process_cmd(vg, cmd);
+ }
}
if (cmd->state != VG_CMD_STATE_FINISHED) {
diff --git a/contrib/vhost-user-gpu/vugpu.h b/contrib/vhost-user-gpu/vugpu.h
index 2374eb90cb..aaf2870cb2 100644
--- a/contrib/vhost-user-gpu/vugpu.h
+++ b/contrib/vhost-user-gpu/vugpu.h
@@ -179,6 +179,7 @@ struct virtio_gpu_ctrl_command {
if (vugpufillcmd_s_ != sizeof(out)) { \
g_critical("%s: command size incorrect %zu vs %zu", \
__func__, vugpufillcmd_s_, sizeof(out)); \
+ cmd->error = VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER; \
return; \
} \
} while (0)
diff --git a/include/hw/virtio/virtio-gpu.h b/include/hw/virtio/virtio-gpu.h
index 2f60c72078..f965defa6b 100644
--- a/include/hw/virtio/virtio-gpu.h
+++ b/include/hw/virtio/virtio-gpu.h
@@ -315,6 +315,9 @@ struct VirtIOGPURutabaga {
qemu_log_mask(LOG_GUEST_ERROR, \
"%s: command size incorrect %zu vs %zu\n", \
__func__, virtiogpufillcmd_s_, sizeof(out)); \
+ memset(&out, 0, sizeof(out)); \
+ virtio_gpu_ctrl_response_nodata( \
+ g, cmd, VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER); \
return; \
} \
} while (0)