# DF-0429 — Verdict: NOT REPRODUCED (FALSE POSITIVE — dead code)

## One-line verdict
DF-0429 claims an unauthenticated `PFSYNC_ACT_UREQ` packet with
`id==0 && creatorid==0` (`sys/net/pf/if_pfsync.c:916`) forces the victim to
multicast its entire pf state table. **This code path is unreachable**: it
lives inside `pfsync_input()`, which is **dead code** on the default kernel.
The same root cause already proven for the sibling finding **DF-0428** applies
verbatim here.

## What the finding cited (and where it lives)
- `sys/net/pf/if_pfsync.c:900-949` — the `case PFSYNC_ACT_UREQ:` arm of the
  giant `switch (action)` block inside **`pfsync_input()`**.
- The exact trigger line: `if_pfsync.c:916  if (id_key.id == 0 && id_key.creatorid == 0)`
  → seeds `sc->sc_bulk_send_next`, sends `PFSYNC_BUS_START`, and
  `pfsync_bulk_update()` (`:1545-1613`) later streams the whole table as
  `PFSYNC_ACT_UPD` multicast packets.

**Critical structural fact:** `pfsync_input()` is ONE function spanning
`sys/net/pf/if_pfsync.c:462-1006` (the `done:` label is at `:1003`, closing
brace at `:1006`). The `switch (action)` begins at `:541`. DF-0428's cited
range `462-541` is just the entry-validation prefix of that same function;
the `case PFSYNC_ACT_UREQ:` at `:900` is the 7th arm of the very same switch.
So DF-0429 is the **same dead function** as DF-0428 — not a separate sink.

## Why it is a false positive (dead code — inherited from DF-0428)
`pfsync_input` is registered as the `IPPROTO_PFSYNC` (240) input handler in
exactly one place, and that place is compiled out:

```c
sys/netinet/in_proto.c:281:#ifdef NPFSYNC
sys/netinet/in_proto.c:288:	.pr_input = pfsync_input,
sys/netinet/in_proto.c:296:#endif	/* NPFSYNC */
```

`NPFSYNC` is **never defined anywhere** in `sys/` — exhaustive grep returns
only the two gate lines (`in_proto.c:281` and `:296`). No `#define NPFSYNC`,
no `options NPFSYNC` in `sys/conf/options`, no option in any kernel config.
→ The `.pr_input = pfsync_input` protosw entry is **compiled out of the static
kernel**. With no protosw carrying `pr_protocol=240`, `ip_init`
(`sys/netinet/ip_input.c:343-351`) leaves `ip_protox[240]` pointing at the
IPPROTO_RAW wildcard, so any proto-240 packet is dispatched to `rip_input`
(`ip_input.c:409-415`) — **never to `pfsync_input`**. `pf.ko` does not
dynamically register a handler either (it exports `pfsync_input`/`pfsyncattach`
as symbols but references neither `inetsw` nor `protosw`).

The honest comment at `if_pfsync.c:486` — *"This function is not yet called
from anywhere"* — is accurate.

## Definitive evidence (re-confirmed on this run, #0 with-src unpatched)
1. **Static kernel symbol:** `nm /boot/kernel/kernel.debug | grep -w pfsync_input`
   → **ABSENT**. The function is not even linked into the running kernel.
2. **Module symbol, unreferenced:** `nm /boot/kernel/pf.ko | grep pfsync_input`
   → `0000000000003040 T pfsync_input`; `grep inetsw|protosw` → none. The
   module carries the code but never registers it.
3. **No pfsync protocol registered:** `netstat -sp pfsync` → empty (no
   pfsyncstats block at all) even with `pf.ko` loaded + `pfctl -e` +
   `pfsync0` present.
4. **Live injection, zero effect:** injecting the exact `PFSYNC_ACT_UREQ`
   (`id=0, creatorid=0`) packet DF-0429 describes (`./inject_ureq 10.0.2.99
   224.0.0.240`) produced **no** `PFSYNC_BUS_START`, **no** bulk state-table
   dump, **no** `pfsyncs_ipackets` increment, and **no** pf-state change.
   See `run.log`.

## Impact of this false positive
None. The "single ~40-byte packet → full state-table disclosure" primitive
DF-0429 describes is not reachable. `pfsync_input` is dormant; the UREQ arm
is unreachable code inside a dead function. (DragonFly's in-kernel pfsync
*receiver* was never finished/wired up — only the *sender* side
`pfsync_sendout` is functional.)

## Build / run (reproduce the negative result)
```
./build.sh        # cc -o inject_ureq inject_ureq.c   (unprivileged build OK)
# (root on guest): kldload pf.ko; pfctl -e
./run.sh          # injects the UREQ bulk-dump trigger; expects NO effect
```

## PoC changes
- `inject_ureq.c` — NEW. Crafts a raw `ip_p=240`, `ip_ttl=255` packet carrying
  `pfsync_header{action=PFSYNC_ACT_UREQ}` + `pfsync_state_upd_req{id=0,
  creatorid=0}` — the exact trigger cited at `if_pfsync.c:916`. (Note:
  `struct pfsync_state_upd_req.id` is `u_int32_t id[2]`, so id is left as the
  memset zero rather than a scalar assignment.)
- No `exploit.c` — there is no memory-corruption primitive; this is an
  auth/DoS claim whose entire surface is dead code.

## Recommended fix
**No code change needed: false-positive.** The cited `case PFSYNC_ACT_UREQ:`
arm (`if_pfsync.c:900-949`) is inside `pfsync_input()`, which is unreachable
on the default kernel and on `pf.ko`-loaded kernels because the
`#ifdef NPFSYNC` registration block in `in_proto.c:281-296` is compiled out
(`NPFSYNC` is never defined) and `pf.ko` does not register a handler.
If the project ever wires up the pfsync *receiver* (defines `NPFSYNC`,
finishes the integration), then the missing-source-authentication concern
becomes real; but that is gated on first making the code reachable, which is
not the case today. (Matches the conclusion of sibling DF-0428.)
