# DF-0597 — PoC: ng_pptpgre (netgraph7) disconnect-vs-timer UAF race

Privileged local race. `ng_pptpgre_disconnect` frees the per-session `hpriv`
unconditionally after `ng_pptpgre_reset`, but `ng_uncallout` does not
dequeue already-dispatched timer trampolines — the queued WRITER item for
`ng_pptpgre_recv_ack_timeout` (or `_send_ack_timeout`) remains on the
msgport and runs against the freed `hpriv`, performing 5 reads+writes on
freed memory.

## Files

- `race.c` — sketch driver (arm rackTimer via upper/session data send, then
  race `ngctl rmhook session_XXXX` against the in-flight timer trampoline).
- (added by per-PoC verifier) full `race.c` rewrite, `build.sh`, `run.sh`,
  `build.log`, `run.log`, `VERDICT.md`, `manifest.json`, `fix.diff`.

## Build & run

```
cc -O2 -o race race.c
sudo ./race          # root required for ngctl
```

The driver should:
1. Create a pptpgre netgraph7 node with ksocket lower and a session hook.
2. Configure via `setconfig` (enabled, windowing, delayed ack, small
   `peerPpd`).
3. Send a data frame on the upper/session hook to start `hpriv->rackTimer`
   via `ng_pptpgre_start_recv_ack_timer`.
4. In a tight loop: wait until rackTimer is ~1 tick from firing, then call
   `ngctl rmhook pptp0: session_0001` from a separate thread.
5. Re-create the session hook and repeat to widen the race window.

## Expected first outcome

On a successful race, the freed `hpriv` is reused by another slab allocation
before the timer callback runs. The timer callback's 5 writes corrupt the
new object — kernel panic from corrupted function pointer / next-pointer:

```
Fatal trap 12: page fault while in kernel mode
fault virtual address = 0x...
backtrace:
    ng_pptpgre_recv_ack_timeout+0x...
    ng_apply_item+0x...
```

Or, on a quiescent system, the UAF access hits stale-but-valid memory with
no visible effect (silent corruption).

## Notes for the per-PoC verifier

- The race window is narrow: the timer trampoline must dispatch on a softint
  just before the disconnect WRITER item is enqueued, with disconnect
  enqueued first (FIFO race between `lwkt_sendmsg` calls from different
  CPUs). Use the per-CPU msgport affinity of netgraph7 items to maximize
  overlap.
- Heap grooming of `sizeof(struct ng_pptpgre_sess)` (~200+ bytes) slabs is
  required for reliable code-exec from the 5 integer writes; otherwise the
  demonstrated impact is potential memory corruption / panic. Document the
  chosen victim object in `VERDICT.md` if escalation is developed.
- Verify the fix with `git apply findings/poc/DF-0597/fix.diff` (the
  deferred-free via `ng_send_fn(node, NULL, ng_pptpgre_free_session, hpriv,
  0)` patch in the finding markdown); after the fix the UAF should no
  longer fire.
- Compare with the legacy `sys/netgraph/ng_pptpgre.c` deferred-free pattern
  (lines 800-850) — the reference correct implementation.
