{
 "finding_id": "DF-3457",
 "status": "reproduced",
 "reproduced": 1,
 "impact": "panic",
 "confidence": "certain",
 "verdict": "gif_clone_destroy() (SIOCIFDESTROY, ifconfig destroy) tears down gif softc state with no gif ifnet serializer held, while in-flight gif_output()/in_gif_output() in any sender thread (holding only that serializer) dereferences the same fields. Reproduced as a fatal trap 12 in gif_output+0x128 (movzbl 0x1(%rax)) after ~75s of unprivileged flood + root destroy-churn: gif_delete_tunnel() NULLed gif_psrc between if_gif.c:346s guard and :373s deref. Other interleavings read the kfreed (0xdeadc0de-poisoned) sockaddr or the freed softc; ip_output() can write ro->ro_rt into the freed softc. Local DoS/panic with root-configured gif tunnels under churn; escalation bounded by the root-side destroy requirement.",
 "exploit_chain": "root: gif0 configured and being destroyed in a loop (dynamic-VPN churn) -> unprivileged local user floods UDP through gif0 route -> sender-thread gif_output_serialized passes psrc NULL-guard, destroy thread kfrees/NULLs gif_psrc concurrently -> sender derefs NULL/freed pointer -> kernel page fault panic. Grooming the 16-byte M_IFADDR-size slab zone (any user sockaddr kmalloc) between free and re-read would give attacker-chosen 16 bytes as the outer src/dst sockaddr (address injection); not needed for the panic proof.",
 "evidence": [
  "panic.txt: fault virtual address = 0x1 + Stopped at gif_output+0x128: movzbl 0x1(%rax),%eax - the sa_family read (offset 1) of a NULLed/freed gif_psrc",
  "run.log: control run 1.26M packets zero errors on stable gif0; race run panicked ~75s in",
  "fix_run.log: patched kernel (#1) survived 600s / 2860 churn cycles, 0 panics, EAFNOSUPPORT=0",
  "fix.diff: ifnet_serialize_all/deserialize_all around gif_clone_destroys softc teardown"
 ],
 "kernel_refs": [
  "sys/net/gif/if_gif.c:176-203",
  "sys/net/gif/if_gif.c:345-350",
  "sys/net/gif/if_gif.c:373",
  "sys/net/gif/if_gif.c:814-843",
  "sys/netinet/in_gif.c:101-110",
  "sys/netinet/in_gif.c:156-163",
  "sys/netinet/in_gif.c:183-216",
  "sys/netinet6/in6_gif.c:102-113",
  "sys/netinet6/in6_gif.c:172-201",
  "sys/net/if.c:2012-2016",
  "sys/net/if.c:2350-2352",
  "sys/net/if.c:642",
  "sys/net/if_clone.c:126-132"
 ],
 "poc_changes": "Seed had no runnable PoC. Wrote flood.c (unprivileged UDP flooder with errno classification: EAFNOSUPPORT return from a configured gif0 is only reachable via the freed-poisoned gif_psrc/gif_pdst family check) and churn.sh (root create/tunnel/addr/route/destroy loop). Design constraints learned: outer tunnel dst must be a blackhole (127.0.0.99) or the decap feedback loop exhausts mbufs and livelocks the box; flood must be paced (~25k pps aggregate) or netisr0 saturation wedges the guest; the gif route must be added after gif0 has an inet address or rt_ifa is AF_LINK and ip_output fails EADDRNOTAVAIL.",
 "attempts": 3,
 "guest_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #0: Thu Jul 2 06:02:54 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64 (baseline); #1: Sun Sep 13 06:15:53 UTC 2026 (patched)",
 "runtime_sec": 435,
 "guest_dirty": 0,
 "build_cmd": "cc -O2 -o /tmp/df3457/floodi /tmp/df3457/flood.c (in-guest, unprivileged)",
 "run_cmd": "user: /tmp/df3457/floodi 6 10.99.0.1 ; root: /tmp/df3457/churn.sh 300",
 "code_hash": "9454a5bed37968d2e093ce2f564781e2e3819c01e0e931073da4948b670a441e",
 "notes": "attempt 1/2 were harness-calibration (mbuf livelock from decap echo chamber; then 300s low-rate run establishing the zero-error control). The known finding DF-3425 (encaptab walk vs encap_detach, if_gif.c, pass 1) is the *input-walk* half of the same unserialized destroy; this finding is the *output-path* half with its own deref sites (in_gif.c/in6_gif.c) and its own reproduced signature; fix.diff serializes the softc teardown which fixes this half.",
 "recommended_fix": "Wrap gif_clone_destroy()s softc teardown (gif_delete_tunnel + LIST_REMOVE + encap detaches + gif_clear_cache) in ifnet_serialize_all()/ifnet_deserialize_all(), the same serializer gif_output() and the gif ioctl paths use (fix.diff, validated in-guest: 600s/2860 cycles, 0 panics vs 75s-to-panic baseline).",
 "fix_status": "fixed",
 "fix_kernel_uname": "DragonFly 6.5-DEVELOPMENT #1: Sun Sep 13 06:15:53 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64",
 "fix_baseline_reproduced": 1,
 "fix_patched_reproduced": 0,
 "fix_verdict": "Rebuilt X86_64_GENERIC with fix.diff via make nativekernel (BUILD_RC=0), installed, rebooted, reran the exact PoC for 600s (2x+ the baseline time-to-crash): 2860 destroy/recreate cycles, zero panics (dmesg fatal-trap count 0), flooders error-free with EAFNOSUPPORT=0. Bad behavior gone; no functional regression (1.3M+ successful sends between destroys).",
 "fix_evidence": "fix_run.log (full patched-run record); baseline in run.log + panic.txt"
}