NULL TTM backing in the PRIME import callback
From: 潘煜杭
Date: Wed Oct 28 2026 - 05:38:46 EST
Hello,
GPT-6-Luna assisted with the initial analysis and drafting the proposed fix.
I am responsible for this report.
I found a NULL-pointer page fault in vmw_gem_object_get_sg_table() during a
PRIME fd-to-handle import in the Linux 7.1.5 fuzz setup. The callback
assumes that the GEM object has a valid TTM translation table, but the crashing
object has `bo->ttm == NULL`.
The crash excerpt is:
BUG: kernel NULL pointer dereference, address: 0000000000000088
#PF: supervisor read access in kernel mode
RIP: vmw_gem_object_get_sg_table+0x2f/0xa0
CR2: 0000000000000088
RBP: 0000000000000000
Code: ... <4c> 8b a5 88 00 00 00 ...
Call Trace:
vmw_gem_object_get_sg_table
drm_gem_map_dma_buf
dma_buf_map_attachment
dma_buf_map_attachment_unlocked
drm_gem_prime_import_dev
drm_gem_prime_fd_to_handle
vmw_prime_fd_to_handle
drm_prime_fd_to_handle_ioctl
drm_ioctl
vmw_unlocked_ioctl
__x64_sys_ioctl
The faulting instruction reads `[RBP + 0x88]`; the recorded RBP is zero, so
the attempted read is from address 0x88. In `struct vmw_ttm_tt`, `dma_ttm` is
the first member. Therefore `container_of(bo->ttm, struct vmw_ttm_tt,
dma_ttm)` evaluates to a NULL-based `vmw_tt` when `bo->ttm` is NULL. The next
source access, `vmw_tt->vsgt.sgt`, reads a member at offset 0x88, matching the
fault address and the instruction in the log.
The crash is reached through these steps:
1. Userspace issues DRM_IOCTL_PRIME_FD_TO_HANDLE with the exported dma-buf fd.
2. vmw_prime_fd_to_handle() enters drm_gem_prime_fd_to_handle() and
drm_gem_prime_import_dev() to attach/map the dma-buf for this DRM device.
3. dma_buf_map_attachment() invokes the dma-buf map callback;
drm_gem_map_dma_buf() obtains the exporting GEM object and calls its
get_sg_table operation.
4. The vmwgfx get_sg_table callback, vmw_gem_object_get_sg_table(), obtains
the TTM BO and derives vmw_tt from bo->ttm without checking it.
5. Since bo->ttm is NULL in the crashing state, vmw_tt is NULL; reading
vmw_tt->vsgt.sgt accesses NULL + 0x88 and raises the page fault.
The corresponding source-level call path is:
__x64_sys_ioctl
-> vmw_unlocked_ioctl()
-> drm_ioctl()
-> drm_prime_fd_to_handle_ioctl()
-> vmw_prime_fd_to_handle()
-> drm_gem_prime_fd_to_handle()
-> drm_gem_prime_import_dev()
-> dma_buf_map_attachment()
-> drm_gem_map_dma_buf()
-> vmw_gem_object_get_sg_table()
-> container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm)
-> vmw_tt->vsgt.sgt /* NULL + 0x88 read */
The reproducer creates a dumb GEM object, exports it as a PRIME fd, and then
imports that fd with DRM_IOCTL_PRIME_FD_TO_HANDLE. A tested source reproducer
is available and can be provided privately to the maintainers.
The patch below checks `bo->ttm` before using it with container_of() and
returns -EINVAL through the DRM PRIME error path when the backing is absent.
This is confirmed in the stated QEMU run; it has not been verified on
physical VMware hardware. The patch passes `git apply --check`; runtime
regression testing has not yet been performed.
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c b/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c
--- a/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c
+++ b/drivers/gpu/drm/vmwgfx/vmwgfx_gem.c
@@ -70,8 +70,12 @@ static struct sg_table *vmw_gem_object_get_sg_table(struct drm_gem_object *obj)
static struct sg_table *vmw_gem_object_get_sg_table(struct drm_gem_object *obj)
{
struct ttm_buffer_object *bo = drm_gem_ttm_of_gem(obj);
- struct vmw_ttm_tt *vmw_tt =
- container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm);
+ struct vmw_ttm_tt *vmw_tt;
+
+ if (unlikely(!bo->ttm))
+ return ERR_PTR(-EINVAL);
+
+ vmw_tt = container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm);
if (vmw_tt->vsgt.sgt)
return vmw_tt->vsgt.sgt;
Regards,
Yuhang Pan
242270054@xxxxxxxxxx