DF-5126 / verdict.json
{ "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" } |