⬢ DragonFlyBSD Kernel Audit
DF-4584 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4584",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Code-proven race, unverifiable on the audit guest. radeon_bo_get_surface_reg (radeon_object.c:601) walks and steals the device-global rdev->surface_regs[] under ONLY the requesting BOs reservation (assert at :609); the victim BO in reg->bo is dereferenced (:628, :641) and written (:642, surface_reg=-1) with no lock, while the victims final-unref path radeon_ttm_bo_destroy -> radeon_bo_clear_surface_reg (:656, reg->bo=NULL at :667) -> kfree (:85) runs unlocked. NULL-deref panic (interleaving B) or a 4-byte 0xFFFFFFFF write into freed radeon_bo slab (interleaving A). Unprivileged reach: GEM_SET_TILING stores RADEON_TILING_SURFACE (radeon_gem.c:503), mmap fault -> radeon_bo_fault_reserve_notify (:793) -> check_tiling(:804) -> get_surface_reg with all 8 regs busy. Trigger built cleanly on the guest but the guest has no radeon GPU (virtio VGA 0x1111:1234 only), no /dev/dri, and no radeonkms.ko in /boot/kernel, so the path is live-unreachable there: open(/dev/dri/renderD128) = ENOENT (run.log). Status inconclusive = attempted, hardware absent, neither reproduced nor refuted on-guest.",
  "exploit_chain": "unpriv user: create 8+ VRAM GEM BOs, GEM_SET_TILING RADEON_TILING_SURFACE, mmap+fault each -> all 8 surface regs busy; thread A faults a 9th SURFACE BO (steal path), thread B creates+faults+closes SURFACE BOs (destroy -> clear) -> A reads reg->bo after Bs clear: NULL deref -> panic; or Bs kfree lands between As read (:638) and use (:641/:642) -> UAF read + fixed-value 4-byte write at offsetof(radeon_bo, surface_reg) in freed slab -> groomable toward control (not developed: no HW).",
  "evidence": "VERDICT.md (interleaving analysis), run.log (open ENOENT + no radeonkms.ko + virtio VGA pciconf), build.log (BUILD_OK), fix.diff (device-lock fix)",
  "kernel_refs": [
    "sys/dev/drm/radeon/radeon_object.c:601",
    "sys/dev/drm/radeon/radeon_object.c:609",
    "sys/dev/drm/radeon/radeon_object.c:621-630",
    "sys/dev/drm/radeon/radeon_object.c:637-643",
    "sys/dev/drm/radeon/radeon_object.c:656-669",
    "sys/dev/drm/radeon/radeon_object.c:69-86",
    "sys/dev/drm/radeon/radeon_object.c:793-812",
    "sys/dev/drm/radeon/radeon_gem.c:503-519"
  ],
  "poc_changes": "Self-authored trigger (no seed existed): self-contained uapi replicas, two pthread racers, render-node-first open; added missing errno.h after first guest compile.",
  "attempts": 1,
  "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 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": 45,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -pthread -o df4584_trigger df4584_trigger.c",
  "run_cmd": "./df4584_trigger /dev/dri/renderD128; ./df4584_trigger /dev/dri/card0",
  "code_hash": "6cd709138cac6be20add86e4f0ffbed66a77f6053508146e1fac7997e70025bf",
  "notes": "Guest lacks radeon HW and radeonkms.ko entirely (env.txt); per the strict poc-status enum this is recorded as inconclusive (attempted, environment-absent) instead of the usual not_testable label. has_moved==1 callers of radeon_bo_check_tiling do not exist in this tree; get_surface_reg is reached only via radeon_bo_kmap (:289) and fault_reserve_notify (:804).",
  "recommended_fix": "Add device-level rdev->surface_regs_lock held across radeon_bo_get_surface_reg()s registry walk/steal and radeon_bo_clear_surface_reg()s body (fix.diff); victim liveness follows because destroy calls clear before kfree.",
  "fix_status": "not_applicable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Fix validation impossible on this guest: baseline itself is not reproducible (no radeon hardware/driver), so no patched-kernel comparison can be made. fix.diff is inspection-validated only.",
  "fix_evidence": "fix.diff (git-apply-able vs read-only sys/ tree; never applied); see VERDICT.md Recommended fix"
}