# DF-3450 — encap4_input's ipip_input hook: unsynchronized test-then-call races ip_mroute KLD unload → NULL-call / execute-after-unmap

## Files
- `sprayer.c` — floods proto-4 (IPIP) packets to 127.0.0.1 (all non-TCP/UDP
  hashes are 0 → every packet is dispatched to netisr0 where encap4_input's
  `IN_NETISR(0)` path runs); the 96 extra raw IPPROTO_IPV4 sockets both
  prove X_ipip_input→rip_input delivery and widen the in-module window.
- `racer.sh` — tight `kldload`/`kldunload ip_mroute` loop.
- `panic.txt` — run 1 fault (RIP = 0x0, call-NULL variant).
- `run.2.log` / `console_run2.txt` — run 2 fault (RIP = 0xffffffff82600275,
  execute-in-unmapped-module-text variant; module base 0xffffffff82600000).
- `fixattempt1_single_sided.log` — single-sided fix attempt (unload-side
  netmsg_service_sync only): STILL panics (RIP=0x0) — proves the reader's
  double-read is independently fatal.
- `fix.diff` — two-sided fix: single-read snapshot in encap4_input +
  netmsg_service_sync in ip_mroute MOD_UNLOAD.
- `console_fixrun.txt`-era validation: 480 s race with the two-sided fix,
  115,650 load/unload cycles, 16.8 M sprayed packets, no crash.

## Build (guest, root)
```sh
(cd /usr/src/sys/net/ip_mroute && make obj && make)   # ip_mroute.ko
cc -O2 -o /root/sprayer /root/sprayer.c
```

## Run (baseline)
```sh
(/root/sprayer 96 > /root/sprayer.log 2>&1 &)
(sh /root/racer.sh   > /root/racer.log 2>&1 &)
# within ~25-100 s:
#   Fatal trap 12: page fault while in kernel mode
#   fault virtual address = 0x0 | 0xffffffff82600xxx
#   fault code = supervisor read instruction, page not present
#   instruction pointer = 0x8:0x0 | 0x8:0xffffffff82600275
#   current process = Idle (netisr0)
```

## Fix validation
Apply `fix.diff` in /usr/src; `make -j24 nativekernel KERNCONF=X86_64_GENERIC
&& make installkernel`; reboot; rebuild ip_mroute.ko; rerun the same race:
no crash after 480 s (baseline crashed in 23–89 s), guest alive, racer
logged 115,650 load/unload cycles.
