DF-3425 / verdict.json
{ "finding_id": "DF-3425", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "Use-after-free panic reproduced on the stock INVARIANTS guest: encap4_input() walks the lock-free global encaptab on netisr0 (ip_encap.c:174-215) while a root thread runs gif_clone_destroy()/gif_set_tunnel() churn, whose encap_detach() does LIST_REMOVE+kfree with no lock (ip_encap.c:411-426) and whose teardown kfrees the gif_softc (if_gif.c:200). The walk fetched ep->arg and called gif_encapcheck() on the freed softc: Fatal trap 12, Stopped at gif_encapcheck+0x5: testb $0x1,0x6c(%rcx), cpuid=0 (netisr0). Free side is root-gated (if.c:2335-2343); the read side is ordinary packet traffic, so the hazard is privileged gif teardown/reconfig under load - panic/DoS demonstrated, code-exec not developed (sub-microsecond chunk-recycle window).", "exploit_chain": "", "evidence": [ "panic.txt: Fatal trap 12: page fault + Stopped at gif_encapcheck+0x5: testb $0x1,0x6c(%rcx) = sc->gif_if.if_flags read (if_gif.c:279) on freed softc, cpuid=0 = the encap4_input netisr0 walk", "gif_race.c: 30 static gifs (walk length), gif50 create/set/destroy bounce, gif51 SIOCSIFPHYADDR reconfig loop, 4 raw IPIP floods to 127.0.0.1", "run.patched.log: identical harness on fix.diff-built kernel completes 300s with no panic" ], "kernel_refs": [ "sys/netinet/ip_encap.c:174", "sys/netinet/ip_encap.c:180", "sys/netinet/ip_encap.c:411", "sys/net/gif/if_gif.c:176", "sys/net/gif/if_gif.c:200", "sys/net/gif/if_gif.c:814", "sys/net/if_clone.c:104" ], "poc_changes": "No seed existed (pass-2 discovery). Harness iterated once for a missing <netinet/in_var.h> include (struct in_aliasreq for SIOCSIFPHYADDR).", "attempts": 1, "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", "runtime_sec": 335, "guest_dirty": 1, "build_cmd": "sh build.sh", "run_cmd": "sh run.sh", "code_hash": "6bfddfda708c215dc0ad85edda8bfb1d7fb3370aa3806f32f64a3fdc28d87680", "notes": "DF-3405/3407/3414 covered the clone-framework TOCTOU family; this is the gif-specific data race on the encaptab global (and gif_set_tunnels crit-only churn). Residual after fix: netisr-queued inner packet carries rcvif=softc past the token drop; full fix needs softc refcounting (cf. FreeBSD if_ref encap rework).", "recommended_fix": "Serialize encaptab walk vs mutators with a dedicated lwkt_token (encap4_input/encap6_input/encap_attach/encap_attach_func/encap_detach); see fix.diff.", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #1: Sat Sep 12 13:26:06 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "Two-iteration validation. Attempt 1 (dedicated lwkt_token taken by walkers AND mutators) was REJECTED: the patched kernel itself panicked (lwkt_reltoken: illegal release) because netisr transport processing already runs under mp_token and a second nested token released there violates LWKT tokref ordering (fix.attempt1.failed.txt). Attempt 2 (final fix.diff: mp_token acquired ONLY in encap_attach/encap_attach_func/encap_detach; the encap4/6_input walks already run under mp_token via transport_processing_oncpu) built clean (0 errors), installed as kernel #1 2026-09-12 13:26:06, and survived the identical harness twice: 300s run (68.5M flood packets, 156,307 destroy cycles, 6.66M reconfig cycles, err=0, done-no-panic, guest up) and a 120s confirmation (25.6M floods, 66.5k cycles). Baseline stock kernel #0 panicked in the first 240s run at gif_encapcheck+0x5 on the freed softc. Statistical caveat noted; the token argument holds by construction.", "fix_evidence": [ "fix.diff", "kbuild.tail.log", "run.patched.log" ] } |