# DF-5126 VERDICT — no-op read side + fixed 1s delay line

## Status: REPRODUCED (deterministic 3/3 per run; RIP control; fix validated)

## Root cause

* `sys/dev/drm/include/linux/rcupdate.h:46-56`: `rcu_read_lock()`/`rcu_read_unlock()`
  map to `preempt_disable()`/`preempt_enable()`.
* `sys/dev/drm/include/linux/preempt.h:37-38`: those map to `cpu_ccfence()` —
  a compiler reordering fence only (sys/cpu/x86_64/include/cpufunc.h:219-227).
  No crit section, no preemption exclusion, no assertion preventing a thread
  from blocking inside the section.
* `sys/dev/drm/linux_rcu.c:79-105,161-184`: reclamation is a per-CPU ring whose
  entries fire after `delta >= hz` — a *fixed one-second timer*, with no
  coupling to readers whatsoever.

Therefore any read-side critical section that survives longer than the delay
(stalled, preempted, or blocked — all permitted by the shim) has its object
freed underneath it by the shipped `__kfree_rcu()`/`call_rcu()` path.

## Runtime proof (stock /boot/kernel/drm.ko, 6-CPU guest)

Stage B of the harness (writer cpu0 / reader cpu2; `__kfree_rcu` is the REAL
drm.ko symbol; victim allocated/freed with the shim's own `kzalloc`/`kfree`
(M_DRM) so slab zones match):

1. reader: `rcu_read_lock(); v = rcu_dereference(gp); tsleep(2s); read v->magic; rcu_read_unlock();`
2. writer: `rcu_assign_pointer(gp, NULL); __kfree_rcu(v1); tsleep(1.4s); [32-object poison reclaim spray]`
3. The shim's timer (`drm: expand RCU cpu 0 to 16` in dmesg — the real ring)
   frees v1 at ~+1s — well inside its own grace model — while the reader is
   provably still inside its critical section.
4. Reader wakes at +2s, still in-section: reads MAGIC_POISON and calls
   `v->v_fp` — a function pointer that exists only as data written into the
   freed-and-reclaimed object.

Results: 3/3 rounds, every baseline run (runs 1, 2, 3 and the extra trigger
rounds). With `rip_panic=1` the reclaimed fp = 0xffffffff52170000 and the
kernel took `Fatal trap 12: page fault ... instruction pointer = 0xffffffff52170000`
(panic.txt) — arbitrary kernel RIP control from the UAF.

## Distinguishing from neighbors

* DF-5033 (amdgpu_bo_list.c): lockless `idr_find()` vs *synchronous* kfree in
  `idr_grow()` — a different subsystem and an immediate free; that finding
  cites linux_rcu.c:187 only as context. This finding is about the RCU shim's
  own grace-period model (delay line + no-op read side) and is demonstrated
  through the shim's exported `__kfree_rcu`.
* DF-1881 (linux_fence.c/reservation): a specific unsafe refcount helper; not
  the shim's grace model.

## Exploit chain / ceiling

Identical to DF-5125's (same object, same reclaim discipline): blocked/preempted
reader -> `__kfree_rcu` fires at +1s -> reclaim with controlled content ->
reader consumes poisoned fields -> indirect call through reclaimed fp ->
RIP control (fatal trap shown). Real-world ceiling: every drm kfree_rcu/call_rcu
victim reachable from unprivileged GPU clients (fences, bo lists, gem objects,
reservation arrays). This guest has no GPU/render node, so the shipped call
sites cannot be driven end-to-end here — environment blocker, documented; the
primitive (UAF + RIP control via the shipped shim) is fully reproduced.

## Fix validation

`fix.diff` (shared with DF-5125): `rcu_read_lock()`/`rcu_read_unlock()` now
maintain a global nesting counter (`rcu_read_acquire`/`rcu_read_release`);
`rcu_timer()` defers element execution while `rcu_readers != 0`; the blocked
reader therefore holds off the free until after its unlock — exactly the
semantics RCU promises. Post-fix stage B: **0 hits in 6 rounds** (including
`rip_panic=1` trigger rounds), guest healthy. Baseline was 3/3 every run.

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
