Re: [PATCH] drm/vmwgfx: do not hand the embedded sg_table to the PRIME core

From: Aldo Ariel Panzardo

Date: Sat Oct 03 2026 - 13:06:44 EST


Hi Maaz,

Thanks for testing.

I think the reason you could not reproduce is that the original PoC
opens two fds to the same vmwgfx render node. When the importer
and exporter are the same device, drm_gem_prime_import_dev() hits
the drm_gem_is_prime_exported_dma_buf() check (drm_prime.c:976):
it sees dma_buf->ops == drm_gem_prime_dmabuf_ops && obj->dev == dev,
and returns dma_buf->priv directly without attaching or mapping —
so drm_gem_unmap_dma_buf() is never reached and the kfree never fires.

To hit the invalid-free, the PRIME import must go through a
different DRM device (e.g. virtio-gpu) so the full attachment
map/unmap path is taken. In addition, the BO must be bound to a GB
surface before the import, so that vmw_ttm_map_dma() runs and
caches vsgt.sgt = &vmw_tt->sgt (the embedded member). Without the
bind, the TTM is not DMA-mapped and get_sg_table falls through to
drm_prime_pages_to_sg(), which allocates a fresh table — no bug.

With an updated PoC that uses a second GPU for import and binds the
BO first, I was able to reproduce on mainline 7.3-rc4 (6edd14dd67d7):

BUG: KASAN: invalid-free in drm_gem_unmap_dma_buf+0x6b/0x80
Free of addr ffff888103c34e60 by task poc_mm04_attack/242

CPU: 2 UID: 65534 PID: 242 Comm: poc_mm04_attack Not tainted
7.3.0-rc4-g6edd14dd67d7-dirty #8 PREEMPT(lazy)
Call Trace:
<TASK>
kasan_report_invalid_free+0xb8/0xe0
check_slab_allocation+0xf5/0x100
kfree+0x163/0x510
drm_gem_unmap_dma_buf+0x6b/0x80
dma_buf_unmap_attachment_unlocked+0x72/0xc0
drm_gem_prime_import_dev+0x1f5/0x260
virtgpu_gem_prime_import+0x328/0x580
drm_gem_prime_fd_to_handle+0x116/0x370
drm_ioctl+0x3d4/0x790

Allocated by task 242:
vmw_ttm_tt_create+0x4c/0x130
ttm_tt_create+0xca/0x190
ttm_bo_handle_move_mem+0xea/0x270
vmw_bo_create+0x248/0x3c0
vmw_gem_object_create_ioctl+0xa1/0x1a0

The buggy address belongs to the cache kmalloc-192 of size 192
The buggy address is located 96 bytes inside of
160-byte region [ffff888103c34e00, ffff888103c34ea0)

Setup:
- QEMU with -device vmware-svga -device virtio-gpu-pci
- Kernel: 7.3-rc4, KASAN, CONFIG_DRM_VMWGFX=y
- Three local-only changes to make vmwgfx probe on QEMU:
1. pitchlock error return bypassed (hardware capability
check, not security-relevant — VMware real passes it)
2. SVGA_CAP_GBOBJECTS forced (QEMU does not advertise it;
VMware real does)
3. max_mob_pages/max_mob_size forced to 256 MB (QEMU
returns 0; VMware real provides real values)
None of these touch the PRIME export/import path or the
sg_table ownership code.
- DMA map mode: vmw_dma_map_populate (line in boot log:
"DMA map mode: Caching DMA mappings")

Steps (runs as uid 65534):
1. DRM_VMW_ALLOC_DMABUF(262144) on vmwgfx renderD128
2. DRM_IOCTL_PRIME_HANDLE_TO_FD
3. DRM_VMW_GB_SURFACE_CREATE 256x256
4. EXECBUF BIND_GB_SURFACE(sid, mobid=handle)
-> vmw_ttm_bind -> vmw_ttm_map_dma
-> sets vsgt.sgt = &vmw_tt->sgt (embedded, vmw_dma_map_populate)
5. DRM_IOCTL_PRIME_FD_TO_HANDLE on virtio-gpu renderD129
-> dma_buf_map_attachment -> drm_gem_map_dma_buf
-> vmw_gem_object_get_sg_table returns &vmw_tt->sgt
-> virtgpu_gem_prime_import_sg_table fails with -ENODEV
(no blob resource support in this QEMU config)
-> error cleanup: dma_buf_unmap_attachment_unlocked
-> drm_gem_unmap_dma_buf: sg_free_table + kfree(&vmw_tt->sgt)
=> KASAN: invalid-free (interior pointer of vmw_ttm_tt)

I also found a second, related bug in the same function. When
testing without the GBOBJECTS/MOB patches (i.e. vanilla QEMU where
BOs go to VRAM only), vmw_gem_object_get_sg_table() does
container_of(bo->ttm, ...) without checking that bo->ttm is
non-NULL. Without MOB, the BO stays in VRAM and no TTM TT is
ever allocated, so bo->ttm is NULL and the dereference faults:

BUG: KASAN: null-ptr-deref in vmw_gem_object_get_sg_table+0x2f/0xa0
Read of size 8 at addr 0000000000000088 by task poc_sgtable/330

CPU: 0 UID: 0 PID: 330 Comm: poc_sgtable Not tainted
7.3.0-rc4-g6edd14dd67d7-dirty #7 PREEMPT(lazy)
Call Trace:
vmw_gem_object_get_sg_table+0x2f/0xa0
drm_gem_map_dma_buf+0x79/0x120
dma_buf_map_attachment+0xc1/0x4f0
drm_gem_prime_import_dev+0xe0/0x260
virtgpu_gem_prime_import+0x328/0x580
drm_gem_prime_fd_to_handle+0x116/0x370

Steps:
1. DRM_IOCTL_MODE_CREATE_DUMB on vmwgfx (64x64x32)
2. DRM_IOCTL_PRIME_HANDLE_TO_FD
3. DRM_IOCTL_PRIME_FD_TO_HANDLE on virtio-gpu
-> NULL pointer dereference at offset 0x88

I have both PoC sources and the full KASAN/dmesg logs ready.
Regarding Zack's request for igt tests: I have not written those
yet but plan to include them with v2.

Would you like me to send v2 as two patches (1/2 NULL-check,
2/2 embedded sg_table fix) in this same thread, or do you prefer
the NULL-deref fix as a separate submission?

thanks,
Aldo