⬢ DragonFlyBSD Kernel Audit
DF-3863 / verdict.json
← back to finding ↓ download raw
{
  "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"
}