DF-3863 / verdict.json
{ "finding_id": "DF-3863", "status": "not_reproduced", "reproduced": 0, "impact": "none", "confidence": "likely", "verdict": "Sink certain, reachability config-gated: amdgpu_vm.c:1807 declares unsigned nptes, ncmds, ndw and :1841 truncates nptes = last - start + 1 (u64 math -> u32); a >=2^32-GPU-page (16TiB) single-call range (reachable from amdgpu_vm_clear_freed :2333 for a whole freed mapping, or split_mapping with nodes==NULL :2006 for BO-less PRT mappings, ioctl path amdgpu_gem.c:604-631) wraps nptes to 0, sizes the IB at ~100 dwords (:1879), while amdgpu_vm_update_ptes (:1915) walks the full range emitting unchecked write_pte packets (guard is only the post-hoc WARN_ON at :1920) -> kernel heap IB overflow. Trigger requires a 16TiB mapping whose PTs must first be allocated by alloc_pts (ioctl :638): with default block_size 9 that is ~8.4M PT BOs (infeasible); with amdgpu_vm_block_size>=16 (root tunable; VM size default 256TB on VEGA10 per gmc_v9_0.c:940) it is ~64K PTs (feasible). Linux v4.20/v5.0 carry the identical unsigned nptes (verified from upstream); removed by the 5.3 VM rework. Filed Low due to the config gate. Guest has no AMD GPU: trigger compiles (RC=0) and runs to the hardware gate (run.log).", "exploit_chain": "amdgpu.vm_block_size=16 + render node: GEM_VA MAP PRT 16TiB at 64GiB, then UNMAP -> clear_freed -> nptes wraps -> undersized kmallocd IB -> update_ptes writes attacker-range-sized packet stream past the IB -> adjacent slab corruption (packet dwords are GPU write commands; PTE payload values partially user-influenced)", "evidence": "VERDICT.md (truncation math + reachability analysis incl. why default config blocks it); build.log/run.log/env.txt", "kernel_refs": [ "sys/dev/drm/amd/amdgpu/amdgpu_vm.c:1807", "sys/dev/drm/amd/amdgpu/amdgpu_vm.c:1841", "sys/dev/drm/amd/amdgpu/amdgpu_vm.c:1879", "sys/dev/drm/amd/amdgpu/amdgpu_vm.c:1915", "sys/dev/drm/amd/amdgpu/amdgpu_vm.c:2006", "sys/dev/drm/amd/amdgpu/amdgpu_vm.c:2333" ], "poc_changes": "authored from scratch; ioctl ordinal left symbolic with pointer to amdgpu_drm.h since no hardware to finalize against", "attempts": 1, "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "runtime_sec": 10, "guest_dirty": 0, "build_cmd": "cc -Wall -O2 -o va_nptes_overflow va_nptes_overflow.c -lpthread", "run_cmd": "./va_nptes_overflow", "code_hash": "46cd505ea4dd528d0be0953949ce6a8e147386f3c8ab0f5ecdf56a1b2fcd454a", "notes": "Would be High on block_size>=16 configs (unprivileged heap overflow); default-config reachability blocked by PT-allocation cost - documented honestly.", "recommended_fix": "Make nptes/ncmds/ndw uint64_t in amdgpu_vm_bo_update_mapping and cap/fail the IB allocation explicitly (fix.diff)", "fix_status": "not_testable", "fix_baseline_reproduced": 0, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff switches the sizing math to u64 and caps the alloc; git apply --check clean; not exercisable without AMD hardware", "fix_evidence": "findings/poc/DF-3863/fix.diff" } |