⬢ DragonFlyBSD Kernel Audit
DF-5126 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-5126",
  "status": "reproduced",
  "verdict": "The drm RCU shims read side (rcu_read_lock -> preempt_disable -> cpu_ccfence) provides no preemption/blocking exclusion while its reclaim side is a fixed 1-second delay line with no reader tracking (linux_rcu.c:81-83), so __kfree_rcu/call_rcu free objects while readers are still inside their critical sections. Reproduced deterministically (3/3 every run): a reader blocked 2s inside rcu_read_lock() had its object freed at ~+1s by the REAL drm.ko __kfree_rcu ring, the slot reclaimed with controlled content, and then read poisoned data and CALLED a function pointer written into the freed object; with rip_panic=1 the kernel took a fatal trap at the attacker-chosen RIP (0xffffffff52170000). fix.diff (read-side nesting counter + deferral of rcu_timer reclamation while readers are in flight) drives stage-B hits to 0.",
  "reproduced": true,
  "impact": "panic",
  "confidence": "certain",
  "exploit_chain": "reader cpu2 blocks 2s INSIDE rcu_read_lock (legal under this shim: preempt_disable is cpu_ccfence) holding v -> writer cpu0 swaps gp and calls the shipped __kfree_rcu(v) -> shims per-cpu ring (dmesg: drm: expand RCU cpu 0 to 16) kfrees v at ~+1s per its fixed delta>=hz rule -> same-cpu slab reclaim with controlled {magic,fp} -> reader wakes still in-section, reads poison (UAF read) and calls v->v_fp (kernel indirect call via freed-object content) -> fp=0xffffffff52170000: Fatal trap 12, RIP = attacker value. uid=0 end-to-end blocked on this guest only by absent GPU hardware (no render node); primitive fully reproduced.",
  "evidence": "run.log/run.2.log (stageB_uaf 3/3, poison_reads 3, canary 3 every run), panic.txt (rip=0xffffffff52170000), run.fixed.log (post-fix stageB_uaf 0 across 6 rounds incl rip_panic=1, guest up), fix.diff",
  "kernel_refs": [
    "sys/dev/drm/linux_rcu.c:81",
    "sys/dev/drm/linux_rcu.c:71",
    "sys/dev/drm/linux_rcu.c:187",
    "sys/dev/drm/linux_rcu.c:127",
    "sys/dev/drm/include/linux/rcupdate.h:46",
    "sys/dev/drm/include/linux/rcupdate.h:52",
    "sys/dev/drm/include/linux/preempt.h:37",
    "sys/dev/drm/scheduler/sched_fence.c:112",
    "sys/dev/drm/amd/amdgpu/amdgpu_fence.c:648",
    "sys/dev/drm/linux_reservation.c:196"
  ],
  "poc_changes": "Shared harness with DF-5125 (stage B is this findings trigger); all harness repairs listed in DF-5125/verdict.json poc_changes apply. Deterministic by construction: readers 2s in-section sleep spans the shims 1s grace line.",
  "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": 3780,
  "guest_dirty": 1,
  "build_cmd": "cd /tmp/poc && make   (SYSDIR=/usr/src/sys; CFLAGS+=-I/usr/src/sys/dev/drm/include)",
  "run_cmd": "kldload drm; kldload /tmp/poc/rcu_race.ko; sleep 45; sysctl rcu_race.stageB_uaf rcu_race.poison_reads rcu_race.canary",
  "code_hash": "729966d3d8f7922ec134319c18228cfab6c3fc8e2fe4eb548d9f5d596a3c37ba",
  "notes": "Distinct from DF-5033 (idr_find vs synchronous idr_grow kfree) and DF-1881 (dma_fence_get_rcu helper): this finding is the shims own grace model, exercised through the shipped __kfree_rcu symbol. Stage B hit 3/3 in every baseline run (9/9 total) and 0/6 post-fix.",
  "recommended_fix": "Account read-side critical sections (rcu_read_acquire/release in rcu_read_lock/unlock) and defer rcu_timer reclamation while any reader is in flight -- see fix.diff.",
  "fix_status": "fixed",
  "fix_baseline_reproduced": true,
  "fix_patched_reproduced": false,
  "fix_verdict": "fix.diff applied in guest /usr/src, drm.ko rebuilt, identical harness rebuilt against fixed headers: stageB_uaf 0/6 rounds (was 3/3 per run), canary 0, guest survived rip_panic=1 trigger rounds. Delay-line free now correctly deferred until the blocked reader exits its section.",
  "fix_evidence": "run.fixed.log; drmbuild.log; fix.diff"
}