{
  "finding_id": "DF-4927",
  "status": "inconclusive",
  "reproduced": 0,
  "impact": "none",
  "confidence": "certain",
  "verdict": "Kernel path could not be exercised: the QEMU/KVM audit guest has no radeon GPU, so radeon_sa.c is unreachable there (status inconclusive rather than not_reproduced - it was never runnable). The bug itself is certain from source and upstream history: DragonFly carries pre-2022 radeon_sa code - it HAS the 2016 fence-ref fix (ref loop at radeon_sa.c:352-353, upstream f6ff4f67cdf8) but LACKS the 2022 fences[i]=NULL initialization in radeon_sa_bo_next_hole (upstream 0381ac3ca2e7, whose commit message describes this exact UAF). A fence borrowed uncounted at sa.c:278 is freed by the SAME thread inside the same locked loop (try_free/next_hole removal once the GPU signals it; flist fences hold refcount 1 - radeon_ib.c:95-98), and the dangling fences[] entry then reaches radeon_fence_ref (UAF write, :352-353), radeon_fence_wait_any (UAF read, :356) and radeon_fence_unref (double kfree via dma_fence_release, :357-358, linux_fence.c:43-51). A line-faithful userspace port of sa.c:142-374 run on the guest as uid=1001 reproduces the full event chain deterministically (100/100, exit 42), and adding exactly the upstream one-liner eliminates all events (100/100, exit 0) - see run.log/run.2.log/run.3.log.",
  "exploit_chain": "Kernel (analysis, requires radeon HW): unprivileged DRI client exhausts the shared ring_tmp_bo IB pool with multi-ring workloads -> radeon_sa_bo_new blocking loop borrows a pending fence into fences[i] (sa.c:278) -> GPU signals it between two inner-loop scans -> same thread frees it via try_free/next_hole (sa.c:166/306 -> :150) -> radeon_fence_ref() kref_gets freed M_DRM slab memory at :353 (freelist-metadata corruption or victim-object field corruption if reused) -> radeon_fence_unref() drives refcount to 0 again at :358 -> second kfree of the same chunk (double free) -> slab-groom to victim object / function pointer -> code exec as uid 0. Not executable on this guest (no GPU). PoC-executed portion: deterministic borrow->kfree->UAF-ref->UAF-wait->double-free sequence on the ported allocator logic, plus fix validation on the same port.",
  "evidence": "run.log: [fence F1 refcount 0 -> kfree] followed by *** UAF-REF ... at radeon_sa_bo_new:352 fence_ref, *** UAF-WAIT ... :356 fence_wait_any, *** DOUBLE-FREE ... :358 fence_unref, exit=42. run.2.log (fixed): same kfree timeline, zero events, exit=0. run.3.log: 100/100 vs 100/100. VERDICT.md: full path:line trace + upstream commit quotes. fix.diff: exact port of 0381ac3ca2e7 (applies clean, zero offset).",
  "kernel_refs": [
    "sys/dev/drm/radeon/radeon_sa.c:278",
    "sys/dev/drm/radeon/radeon_sa.c:270-272",
    "sys/dev/drm/radeon/radeon_sa.c:335-338",
    "sys/dev/drm/radeon/radeon_sa.c:150",
    "sys/dev/drm/radeon/radeon_sa.c:166",
    "sys/dev/drm/radeon/radeon_sa.c:306",
    "sys/dev/drm/radeon/radeon_sa.c:352-353",
    "sys/dev/drm/radeon/radeon_sa.c:356",
    "sys/dev/drm/radeon/radeon_sa.c:357-358",
    "sys/dev/drm/linux_fence.c:43-51",
    "sys/dev/drm/radeon/radeon_fence.c:699-715",
    "sys/dev/drm/radeon/radeon_ib.c:95-98"
  ],
  "poc_changes": "Original finding sketch did not exist (pass-2 finding discovered in this run); PoC authored from scratch as a line-faithful port of sa.c:142-374 with: minimal list.h equivalent, locks dropped (bug is single-threaded), dma_fence_get/put modeled by refcount+dead-flag. Two fidelity fixes during bring-up: (1) main initially kept an extra reference on the target fence so it never died - fixed to mirror radeon_ib_frees handover (refcount 1 on flist); (2) the ported radeon_fence_ref lacked dma_fence_gets NULL guard and crashed on NULL fences[] entries - restored the guard. GPU signaling modeled as flip-on-3rd-check, placing the signal exactly between the borrow scan and the next scan.",
  "attempts": 3,
  "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": 480,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -o rsa_base radeon_sa_uaf.c && cc -O2 -Wall -DFIXED -o rsa_fixed radeon_sa_uaf.c",
  "run_cmd": "./rsa_base; ./rsa_fixed   (expect 42 then 0)",
  "code_hash": "0e596eb67c8a83dcf0e2e5728b6fb444772888d966aae97fe949f8d1134e19a6",
  "notes": "Guest has no radeon hardware: kernel-level reproduction impossible on this system (radeon module binds only to radeon PCs; QEMU exposes none). Assessment on radeon-equipped systems: High severity kernel heap UAF/double-free reachable by unprivileged users with DRI render access under sustained multi-ring IB pressure. Upstream fixed this exact pattern in 2022 (radeon 0381ac3ca2e7, amdgpu 6a15f3ff19a8); DragonFlys radeon_sa.c predates it. DF-1987 (BUG_ON panic) and DF-1988 (fini without lock) are separate, already-known findings and were not re-reported.",
  "recommended_fix": "Port upstream Linux 0381ac3ca2e7: add fences[i] = NULL; at the top of the per-ring scan in radeon_sa_bo_next_hole() and drop the redundant fences[] reset in radeon_sa_bo_new().",
  "fix_status": "fixed",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Validated at logic level: the -DFIXED build differs from baseline by EXACTLY the upstream one-liner (fences[i] = NULL in next_hole) and produces zero dangling-deref events where baseline produces the full UAF-ref/UAF-wait/double-free chain (100/100 runs each way). Kernel-level single-fix rebuild not performed: without a radeon GPU the modified code path cannot be entered on the audit guest, so a kernel build would only prove compilation; fix.diff applies to sys/dev/drm/radeon/radeon_sa.c cleanly at zero offset (verified with patch --dry-run).",
  "fix_evidence": "run.log (baseline: 3 events, exit 42) vs run.2.log (fixed: 0 events, exit 0); run.3.log stress 100x; fix.diff hunks at radeon_sa.c:267 and :332."
}