[PATCH] drm/vmwgfx: validate FIFO state before reserving commands
From: 潘煜杭
Date: Thu Oct 29 2026 - 04:29:06 EST
Hello,
GPT-5 assisted with the initial analysis and drafting the proposed fix. I am
responsible for this report and patch.
While fuzzing the vmwgfx device model, I observed faults in the FIFO command
reservation path. The issue has two related manifestations: a NULL
dereference when the FIFO state is absent, and an invalid kernel write when
FIFO ring offsets read from the device are outside the mapped FIFO region.
For the NULL-state case, the userspace operation was
DRM_IOCTL_VMW_CREATE_CONTEXT. The path is:
__x64_sys_ioctl()
-> vmw_unlocked_ioctl()
-> vmw_generic_ioctl()
-> drm_ioctl()
-> vmw_context_define_ioctl()
-> vmw_context_define()
-> vmw_context_init()
-> VMW_CMD_RESERVE()
-> vmw_cmd_ctx_reserve()
-> vmw_local_fifo_reserve()
In vmw_local_fifo_reserve(), the FIFO state is read from dev_priv->fifo and
its capabilities are accessed before checking that the pointer is valid.
When the device has no FIFO state, this access faults at offset
0x24:
BUG: kernel NULL pointer dereference, address: 0000000000000024
RIP: 0010:vmw_cmd_ctx_reserve+0x102/0x600
CR2: 0000000000000024
In the invalid-offset case, DRM_IOCTL_VMW_FENCE_EVENT reaches
vmw_cmd_send_fence(), which reserves a FIFO command and writes it at the
address derived from SVGA_FIFO_NEXT_CMD. The call path is:
__x64_sys_ioctl()
-> vmw_unlocked_ioctl()
-> vmw_generic_ioctl()
-> drm_ioctl()
-> vmw_fence_event_ioctl()
-> vmw_execbuf_fence_commands()
-> vmw_cmd_send_fence()
-> vmw_local_fifo_reserve()
-> vmw_local_fifo_commit()
The observed invalid write was:
BUG: unable to handle page fault for address: ffa000009e85232c
RIP: 0010:vmw_cmd_send_fence+0x16e/0x290
CR2: ffa000009e85232c
The report did not capture the raw SVGA_FIFO_NEXT_CMD value, so I cannot
state its exact value. The driver currently validates the requested command
size but does not first verify that FIFO MIN/MAX/NEXT_CMD/STOP form aligned
offsets within the mapped FIFO memory. This patch checks for missing FIFO
state and memory, validates those ring boundaries, and rejects invalid
offsets before using them to construct a command pointer.
The patch below is against the Linux 7.3 source
tree; it applies cleanly and passes checkpatch.pl --strict.
Assisted-by: OpenAI Codex (GPT-5)
Signed-off-by: Yuhang Pan <242270054@xxxxxxxxxx>
---
drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
index d932e38..02987d3 100644
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_cmd.c
@@ -282,15 +282,22 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv,
uint32_t max;
uint32_t min;
uint32_t next_cmd;
- uint32_t reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;
+ u32 reserveable;
int ret;
+ if (unlikely(!fifo_state || !fifo_mem))
+ return NULL;
+ reserveable = fifo_state->capabilities & SVGA_FIFO_CAP_RESERVE;
mutex_lock(&fifo_state->fifo_mutex);
max = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MAX);
min = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_MIN);
next_cmd = vmw_fifo_mem_read(dev_priv, SVGA_FIFO_NEXT_CMD);
- if (unlikely(bytes >= (max - min)))
+ if (unlikely(min < PAGE_SIZE || min >= max ||
+ max > dev_priv->fifo_mem_size ||
+ next_cmd < min || next_cmd >= max ||
+ ((min | max | next_cmd) & 3) ||
+ bytes >= (max - min)))
goto out_err;
BUG_ON(fifo_state->reserved_size != 0);
@@ -303,6 +310,9 @@ static void *vmw_local_fifo_reserve(struct vmw_private *dev_priv,
bool need_bounce = false;
bool reserve_in_place = false;
+ if (unlikely(stop < min || stop >= max || (stop & 3)))
+ goto out_err;
+
if (next_cmd >= stop) {
if (likely((next_cmd + bytes < max ||
(next_cmd + bytes == max && stop > min))))
--
2.34.1
Regards,
Yuhang Pan
242270054@xxxxxxxxxx