⬢ DragonFlyBSD Kernel Audit
DF-4164 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-4164",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Unlocked-walk structure source-certain, race timing hardware-gated (inconclusive per family convention). radeon_unmap_vram_bos (radeon_pm.c:146-157) walks rdev->gem.objects with no gem.mutex and no per-bo reference, invoked from radeon_pm_set_clocks (:279) under pm.mutex/ring_lock/mclk_lock -- none of which serialize GEM object lifetime. Writers mutate the same list under gem.mutex: GEM create list_add_tail (radeon_gem.c:89-91) and radeon_ttm_bo_destroys list_del_init+kfree(bo) (radeon_object.c:68-85), both reachable from unprivileged drm ioctls/handle-close. list_for_each_entry_safe only guards removal of the current element; a destroyed n target or racing tail insertion turns the next iterations bo->tbo.mem.mem_type read into a UAF read of freed memory (and can corrupt the walk). PM-side exposure: profile-method machines (pre-DPM asics or the rlc/smc firmware-missing fallback, radeon_pm.c:1533-1542/1571-1582) via ACPI events (:88), fbcon init/resume (radeon_device.c:1816/:1929) and fini_old; DPM-method machines never call the helper. PM_METHOD_DYNPM is dead on DFly (only entry is the #ifdef DUMBBELL_WIP sysfs block :354-786). Guest: virtio VGA only, zero 0x1002 devices (env.txt) -> not runtime-testable. Impact ceiling: unprivileged local panic (DoS); escalation from a list-walk UAF read is unlikely.",
  "exploit_chain": "On profile-method radeon hardware: unprivileged console user churns GEM VRAM objects (create/close loop via drm ioctls) while AC plug events or a resume drive radeon_pm_set_clocks -> radeon_unmap_vram_bos iterates into a concurrently freed radeon_bo -> UAF read/list corruption -> panic. No write primitive.",
  "evidence": "VERDICT.md (lock analysis + why _safe is insufficient + adjacent kills); env.txt (hardware absence + md5 match); fix.diff (gem.mutex around the walk, lock-order analysis: all existing holders guard pure list ops only, no inversion; git apply --check clean)",
  "kernel_refs": [
    "sys/dev/drm/radeon/radeon_pm.c:146",
    "sys/dev/drm/radeon/radeon_pm.c:279",
    "sys/dev/drm/radeon/radeon_gem.c:89",
    "sys/dev/drm/radeon/radeon_object.c:77",
    "sys/dev/drm/radeon/radeon_pm.c:1533"
  ],
  "poc_changes": "No seed PoC; race trigger documented in README.md (GEM churn + AC event).",
  "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": 15,
  "guest_dirty": 0,
  "build_cmd": "n/a (hardware-gated)",
  "run_cmd": "n/a (hardware-gated)",
  "code_hash": "",
  "notes": "Pass-2 depth item: refcount/lifetime race across PM work vs unprivileged GEM paths. Upstream-inherited pattern, real in this tree. Killed adjacent: print_states name-array indexing (legacy types only 0..4, radeon.h:1206-1225), vblank get/put symmetry (:281-307), dynpm idle handler dead on DFly (never scheduled), set_power_state index bounds.",
  "recommended_fix": "Hold rdev->gem.mutex across the gem.objects walk in radeon_unmap_vram_bos (see fix.diff).",
  "fix_status": "not_testable",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "fix.diff serializes the walk with the same mutex all list mutators already use; no lock-order inversion (existing holders guard pure list ops only); cannot be runtime-validated without radeon hardware.",
  "fix_evidence": "findings/poc/DF-4164/fix.diff"
}