{
  "finding_id": "DF-3450",
  "status": "reproduced",
  "reproduced": 1,
  "impact": "panic",
  "confidence": "certain",
  "verdict": "Race reproduced 2/2 baseline runs on the stock INVARIANTS guest with both fault variants: encap4_input (ip_encap.c:231-235) reads the ipip_input hook unlocked and twice (test, then call); ip_mroutes MOD_UNLOAD NULLs it under mroute_token (which the netisr reader never takes) and performs no netisr drain before the linker unmaps the module text. Run 1: RIP=0x0 (call-NULL variant). Run 2 (23 s): RIP=0xffffffff82600275 inside the unloaded module text (execute-after-unmap variant); both in netisr0/Idle context while a root kldload/kldunload loop raced a proto-4 packet spray (any local user or on-link peer can be the packet source). Root-gated setup, race winnable in seconds. Two-sided fix validated: reader-side single-read snapshot (kernel rebuilt, #1 Sep 12 23:27:53) + unload-side netmsg_service_sync (module rebuilt) survived 480 s / 115,650 load-unload cycles / 16.8 M packets with no crash; a single-sided fix attempt (unload drain only) still panicked at 89 s with RIP=0x0, documenting that both hunks are required.",
  "exploit_chain": "root: sh racer.sh (kldload/kldunload ip_mroute loop); unpriv/remote: proto-4 packet stream to a local address (sprayer). netisr0 encap4_input reads ipip_input non-NULL, unload NULLs+unmaps concurrently -> indirect call to 0x0 (observed) or into unmapped-but-predictable module text (observed at module_base+0x275). Escalation ceiling: with a KLD reloaded into the freed VA before a late readers call, the diverted call executes chosen module code - root-gated setup caps honest impact at panic/DoS.",
  "evidence": [
    "panic.txt: run 1 - fault virtual address 0x0, instruction pointer 0x8:0x0, supervisor read instruction page not present, current process Idle",
    "run.2.log: run 2 - instruction pointer 0x8:0xffffffff82600275 (former ip_mroute.ko text, base 0xffffffff82600000), current process Idle",
    "fixattempt1_single_sided.log: single-sided fix still panics RIP=0x0 at 89s (proves reader double-read independently fatal)",
    "fix.diff: two-sided fix (ip_encap.c snapshot + ip_mroute.c netmsg_service_sync)",
    "env.txt + validation narrative in VERDICT.md: 480s/115650 cycles/16.8M packets no-crash on rebuilt kernel #1"
  ],
  "kernel_refs": [
    "sys/netinet/ip_encap.c:231",
    "sys/netinet/ip_encap.c:107",
    "sys/net/ip_mroute/ip_mroute.c:3266",
    "sys/net/ip_mroute/ip_mroute.c:3281",
    "sys/net/ip_mroute/ip_mroute.c:3285",
    "sys/netinet/ip_demux.c:315"
  ],
  "poc_changes": "Harness written from scratch (no runnable seed existed): raw-socket proto-4 sprayer with hand-built IP header + checksum (non-TCP/UDP hashes to netisr0 per ip_demux.c), 96 fan-out raw sockets to prove X_ipip_input delivery and widen the in-module window, kldload/kldunload racer loop. First single-sided fix attempt failed; fix.diff extended to the two-sided version with a kernel rebuild.",
  "attempts": 3,
  "guest_uname": "baseline: DragonFly dfbsd 6.5-DEVELOPMENT #0: Thu Jul  2 06:02:54 UTC 2026; fix validation: #1: Sat Sep 12 23:27:53 UTC 2026 (rebuilt X86_64_GENERIC with ip_encap.c hunk)",
  "runtime_sec": 2410,
  "guest_dirty": 1,
  "build_cmd": "(cd /usr/src/sys/net/ip_mroute && make obj && make); cc -O2 -o sprayer sprayer.c; [fix] make -j24 nativekernel KERNCONF=X86_64_GENERIC && make installkernel KERNCONF=X86_64_GENERIC",
  "run_cmd": "(./sprayer 96 &) ; (sh racer.sh &) ; watch dfbsd-qemu/vm.sh log",
  "code_hash": "63b1e963dbcef6494c0d83c6b0d4655d52263759b480908e05f724b2b9447bc7",
  "notes": "Not DF-0689 (encaptab list) and not covered by the validated DF-3425/DF-3433 mp_token fix - different global (ipip_input), different mechanism (function-pointer hook vs list walk), different fix surface. Cross-ref: DF-0689s validated fix.diff (findings/poc/DF-3425, DF-3433) adds mp_token to encap_attach/attach_func/detach only.",
  "recommended_fix": "Two-sided: snapshot ipip_input once into a local in encap4_input before the test+call, and make ip_mroute MOD_UNLOAD call netmsg_service_sync() after clearing the hooks so netisr drains before the module text is unmapped.",
  "fix_status": "fixed",
  "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT #1: Sat Sep 12 23:27:53 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (reader hunk compiled in; unloader hunk in rebuilt ip_mroute.ko)",
  "fix_baseline_reproduced": 1,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Baseline: panic in 23-89 s (RIP=0x0 and RIP=unmapped-module-text variants). Single-sided fix (unload drain only): still panicked at 89 s, RIP=0x0 - the readers double read is independently fatal, both hunks required. Two-sided fix on rebuilt kernel #1 + rebuilt module: 480 s continuous race, 115,650 kldload/kldunload cycles, 16.8 M sprayed proto-4 packets, zero panics, guest alive and responsive.",
  "fix_evidence": [
    "fix.diff (ip_encap.c + ip_mroute.c hunks)",
    "fixattempt1_single_sided.log (failed single-sided attempt, RIP=0x0)",
    "VERDICT.md validation section (480 s / 115,650 cycles / no crash)",
    "panic.txt, run.2.log (baseline faults)"
  ]
}