# DF-5125 VERDICT — `synchronize_rcu()` empty macro

## Status: REPRODUCED (UAF + kernel RIP control; fix validated)

## Root cause (source-certain)

The DragonFly drm LinuxKPI implements Linux RCU as a per-CPU delay line
(`sys/dev/drm/linux_rcu.c`): `call_rcu()`/`__kfree_rcu()` queue elements that
`rcu_timer()` executes after `delta >= hz` (linux_rcu.c:81-83). There is **no
`synchronize_rcu()` implementation anywhere in `linux_rcu.c`**; instead the
header defines it away:

```c
sys/dev/drm/include/linux/rcupdate.h:94:
#define synchronize_rcu()
```

`rcu_read_lock()`/`rcu_read_unlock()` are `preempt_disable()`/`preempt_enable()`
(rcupdate.h:46-56) which are `cpu_ccfence()` — a **compiler fence with no
runtime semantics** (`sys/dev/drm/include/linux/preempt.h:37-38`,
`sys/cpu/x86_64/include/cpufunc.h:219-227`).

Consequence: the canonical Linux teardown contract — "after
`synchronize_rcu()` returns, no pre-existing reader can still hold the old
pointer" — is vacuously violated: the call returns *instantly* and the caller
typically kfrees the old object on the next line, racing every reader on every
other CPU that is mid-critical-section. In-tree callers of the broken macro:
`sys/dev/drm/i915/i915_gem.c:3713` and `:3731` (the shim's
`get_state_synchronize_rcu()/cond_synchronize_rcu()` pair used by
`i915_request.c:761` is likewise a no-op/mfence).

## Mechanical proof

The harness ships a witness function `df_sync_witness(void){ synchronize_rcu();
kfree((void*)0); }`. Compiled against the shipped headers it is a **single
`retq`** (build.log, objdump):

```
0000000000000970 <df_sync_witness>:
 970:   c3                      retq
```

After `fix.diff` it contains a real call (`jmpq` to the external
`synchronize_rcu`).

## Runtime proof (stock `/boot/kernel/drm.ko`, guest 6.5-DEVELOPMENT, 6 CPUs)

Stage A (DF-5125 contract test): reader thread pinned to CPU2 runs the exact
canonical read-side pattern; handshake proves it holds the pointer inside its
critical section; writer on CPU0 then runs `rcu_assign_pointer(gp,v2);
synchronize_rcu(); kfree(v1);` and reclaims v1's slot with poisoned content.
All RCU primitives are the *shipped shim's* (headers + drm.ko symbols
`__kfree_rcu`/`call_rcu`); only the loops are local.

Results (3 full runs + extra rounds):

| run | stageA uaf hits | stageB uaf hits | poison reads | canary fp-calls |
|-----|-----------------|-----------------|--------------|-----------------|
| 1   | 4/5             | 3/3             | 3            | 3               |
| 2   | 5/5             | 3/3             | 3            | 3               |
| 3   | 5/5 (8-spray)   | 3/3             | 4            | 4               |
| extra rounds | 10/10     | —               | —            | —               |

The reader observed the freed object's contents change *while provably inside
its read-side critical section* in every single round.

## Impact demonstration — kernel RIP control through the freed object

With `rcu_race.rip_panic=1` the reclaimed content sets the freed object's
function pointer to `0xffffffff52170000` (canonical, unmapped). The reader's
`v->v_fp(v)` — the drm idiom (e.g. fence release paths) — jumped there:

```
Fatal trap 12: page fault while in kernel mode
cpuid = 2; lapic id = 2
fault virtual address = 0xffffffff52170000
instruction pointer     = 0x8:0xffffffff52170000
fault code              = supervisor read instruction, page not present
panic: page fault
--- trap 000000000000000c, rip = ffffffff52170000 ---
```

That is arbitrary kernel instruction-pointer control from the UAF: the kernel
executed an address that existed only as data written into reclaimed freed
memory.

## Exploit chain / ceiling

Demonstrated chain: reader in CS -> zero-instruction `synchronize_rcu()` ->
immediate `kfree` under reader -> slab reclaim with controlled content ->
reader dereference (info read) and indirect call (RIP control). With a real
DRM victim object (the pattern is used by i915/amdgpu/scheduler/reservation
code compiled into the shipped drm.ko and the gpu driver modules) and
user-controlled reclamation content this is the classic path to uid=0. On
*this* QEMU guest there is no GPU and no render node, so the shipped call
sites are unreachable end-to-end; that is a hard environment blocker
(documented), not a mitigation — the primitive itself (UAF + RIP control with
the shipped shim) is fully reproduced here.

## Fix validation

`fix.diff` (in this pack): declares `extern void synchronize_rcu(void)` in
rcupdate.h, implements it in linux_rcu.c (waits >= 2 delay periods AND until
`rcu_readers == 0`), counts read-side critical sections
(`rcu_read_acquire/rcu_read_release` wired into `rcu_read_lock/unlock`), and
makes `rcu_timer()` defer reclamation while any reader is in flight.

Applied to the guest's `/usr/src`, `drm.ko` rebuilt
(`/usr/src/sys/dev/drm/drm`), harness rebuilt against the fixed headers, exact
same PoC re-run:

| | baseline (stock) | patched (fix.diff) |
|---|---|---|
| stageA uaf | 4-5/5 (10/10 extra) | **0** (10 rounds) |
| stageB uaf | 3/3 | **0** (6 rounds) |
| canary / RIP control | 3-4 (fp-call), fatal trap | **0**, guest stays up under `rip_panic=1` |

Bad behavior gone; fix validated.

## Harness notes / honest caveats

* Two earlier harness iterations produced null/false results (a
  `DECLARE_MODULE` misuse panicking `module_register`'s strcmp; same-CPU
  pinning + spin handshake starving the reader). Both were harness bugs,
  diagnosed from the DDB backtrace and fixed; the final harness (this pack)
  pins writer=cpu0/reader=cpu2 and tsleep-polls handshakes.
* Stage A's exact-poison reclaim is probabilistic (~1/5 with 1 block, ~4/5
  with 8-spray); stage B's is deterministic (3/3 in every run). UAF *detection*
  (contents changed under the reader) was 100% in runs 2 and 3.

## 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.
