radeon_vm_bo_set_addr() commits the mapping before page-table allocation β allocation failure leaves NULL page tables and the next update panics in radeon_vm_update_ptes()
Summary
set_addr inserts bo_va into the trees BEFORE the PT allocation loop; the error returns leave the mapping committed with page_tables[pt_idx].bo==NULL. Any subsequent update on that bo_va - including the GEM_VA UNMAP cleanup itself, a CS reloc, or an eviction invalidate - walks the range and dereferences pt->tbo.resv with pt==NULL: guaranteed panic once TTM cannot satisfy the 4KB VRAM PT under memory pressure (unpriv GEM_CREATE spam beats eviction). Rollback-on-failure fix.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-4413 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| trigger_nullpt.c | β | 4.3 KB | view raw | |
| radeon_abi.h | β | 2.4 KB | view raw | |
| build.sh | β | 107 B | view raw | |
| run.sh | β | 100 B | view raw | |
| run.log | β | 576 B | view raw | |
| full.log | β | 493 B | view raw | |
| VERDICT.md | β | 3.5 KB | β raw | |
| README.md | β | 1.4 KB | β raw | |
| fix.diff | β | 1.5 KB | view raw | |
| verdict.json | β | 2.4 KB | view raw | |
| env.txt | β | 585 B | view raw |
DF-4413 β radeon_vm_bo_set_addr() commits mapping before PT allocation; failure leaves NULL page tables β NULL-deref panic in radeon_vm_update_ptes()
Build
cc -O2 -Wall -o /tmp/trigger_nullpt DF-4413/trigger_nullpt.c # radeon_abi.h must sit next to the .c
Run
/tmp/trigger_nullpt
Requires a cayman-or-newer radeon KMS device.
Expected result on capable hardware
- The program fills VRAM/GTT (and drives TTM into system memory) until the
4 KB page-table
radeon_bo_create()insideradeon_vm_bo_set_addr()fails. GEM_VA MAPat 0x100000 returns an error β but the mapping has already been inserted intovm->vaandvm->cleared(radeon_vm.c:519-526) and the error paths at radeon_vm.c:554-560 return without unwinding it.- The follow-up
GEM_VA UNMAP(or any CS referencing the BO, or an eviction-driven invalidate) walks the full recorded range inradeon_vm_update_ptes(), hitsvm->page_tables[pt_idx].bo == NULLand dereferences it at radeon_vm.c:833 (pt->tbo.resv) β kernel panic (NULL+offset read in kernel mode).
Success criterion: Fatal kernel mode data access (fault va 0xβ¦) /
panic backtrace containing radeon_vm_update_ptes / radeon_sync_resv.
Observed on THIS audit guest
No radeon GPU (/dev/dri absent; std VGA only). Trigger builds and runs,
exits at device open (see run.log). The flaw is proven by trace in
VERDICT.md.
DF-4413 β VERDICT
status: not_reproduced (hardware absent) β finding certain by trace; not a false positive
Root cause (certain)
radeon_vm_bo_set_addr() records the mapping before it allocates the
backing page tables, and its page-table allocation loop has error returns
that leave the half-initialized mapping committed:
sys/dev/drm/radeon/radeon_vm.c:519-526β undervm->status_lock, setsbo_va->it.start/it.last, addsbo_vatovm->cleared, theninterval_tree_insert(&bo_va->it, &vm->va)β mapping committed.radeon_vm.c:538βradeon_bo_unreserve(bo_va->bo).radeon_vm.c:541-575β the PT allocation loop: *radeon_vm.c:550-555βradeon_bo_create(...)fails βreturn r;*radeon_vm.c:557-561βradeon_vm_clear_bo()fails βradeon_bo_unref(&pt); return r;Neither path removes the committed mapping βbo_vasits invm->va/vm->clearedwithvm->page_tables[pt_idx].bo == NULLfor the un-allocated tail (or for every index if the first PT failed).radeon_gem_va_ioctl()(radeon_gem.c:690-695) only callsradeon_gem_va_update_vm()if (!r)β the failed MAP is reported to userspace as an error while the kernel state keeps the mapping.
Crash sinks (every subsequent update of that bo_va)
radeon_vm_bo_update() passes bo_va->it.start, bo_va->it.last + 1 to
radeon_vm_update_ptes() (radeon_vm.c:1012-1014); the walk does:
827: uint64_t pt_idx = addr >> radeon_vm_block_size;
828: struct radeon_bo *pt = vm->page_tables[pt_idx].bo; /* NULL */
833: radeon_sync_resv(rdev, &ib->sync, pt->tbo.resv, true); /* panic */
(The pt_idx itself is in-bounds β the page_tables[] array is sized
num_pdes in radeon_vm_init β the stored value is NULL.)
Reachable from three unprivileged paths after the failed MAP:
- GEM_VA UNMAP of the same BO β
radeon_gem.c:586βradeon_vm_clear_freed()(radeon_vm.c:1060) βradeon_vm_bo_update(NULL)βradeon_vm_update_ptesβ NULL deref. The "cleanup" unmap is itself the trigger (deterministic). - CS referencing the BO β
radeon_cs.c:527β same walk. - Eviction/invalidate β
radeon_vm_bo_invalidate()+radeon_vm_clear_invalids()(radeon_vm.c:1098) β same walk.
Precondition realism
PT allocation failure requires TTM to be unable to provide one 4 KB VRAM
BO even after eviction: VRAM+GTT+system under pressure (unprivileged
GEM_CREATE spam), or radeon_vm_clear_bo()'s radeon_ib_get() failing
under SA-pool pressure / GPU reset. The error path exists precisely
because the authors expected these failures β but its state on return is
inconsistent, and the very next touch panics.
Why not reproduced here
No radeon GPU on the audit guest (std VGA only; /dev/dri absent).
Trigger compiles and runs, exits at open("/dev/dri/card0") (run.log).
The chain above is unconditional source fact; only the memory-pressure
setup is guest-hardware dependent. Severity Medium (local kernel panic /
DoS from an unprivileged DRI client).
Recommended fix
On failure inside the PT loop, roll the mapping back out of
vm->va/vm->cleared (restore it.start/it.last = 0) before returning.
See fix.diff.
Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest make -j6 nativekernel KERNCONF=X86_64_GENERIC completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
Fix verification
not_testablefix validation impossible on this guest (no radeon GPU; bug not triggerable). fix.diff adds an error_rollback path that removes the committed interval under the proper locks.
fix.diff (error_rollback: interval_tree_remove + status_lock-protected reset)
Confirmed kernel references
Detail
Evidence (decisive lines)
VERDICT.md (commit-before-alloc trace + three crash sinks); run.log (device-absent); fix.diff (rollback on failure)
PoC changes
kernel uapi include replaced by self-contained radeon_abi.h (uapi chain broken for userspace on DFly)
Verified recommended fix
Roll the mapping back out of vm->va/vm->cleared before returning the allocation error
Verdict
Partial-commit bug certain by trace: radeon_vm_bo_set_addr() inserts the mapping into vm->va/vm->cleared (radeon_vm.c:519-526) before the PT loop, and the error returns at radeon_vm.c:554-560 leave it there with vm->page_tables[pt_idx].bo == NULL; the next update (GEM_VA UNMAP cleanup, CS reloc, eviction invalidate) walks radeon_vm_update_ptes() which dereferences pt->tbo.resv at radeon_vm.c:833 with pt==NULL -> kernel panic. The audit guest has no radeon GPU (/dev/dri absent, std VGA) so the panic cannot be triggered at runtime; trigger compiles and runs, exits at open()=ENOENT (run.log). Analysis-classified impact: local kernel panic/DoS from an unprivileged DRI client (Medium).
No comments yet.