⬢ DragonFlyBSD Kernel Audit
DF-3377 / verdict.json
← back to finding ↓ download raw
{
 "finding_id": "DF-3377",
 "status": "reproduced",
 "reproduced": 1,
 "impact": "panic",
 "confidence": "certain",
 "verdict": "One unauthenticated IPv6 proto-103 PIM REGISTER packet panics any kernel whose routing daemon has configured a register mif: pim6_input() re-injects the decapsulated packet through if_simloop(multicast_register_if) (ip6_mroute.c:1842) and the fake register ifnet is never if_attach()ed (add_m6if:585-596 sets only if_xname/IFF_LOOPBACK/if_index), so if_simloops IFNET_STAT_INC writes through NULL if_data_pcpu (if_loop.c:284, if_var.h:685-688) -> Fatal trap 12, fault VA 0x0, Stopped at if_simloop+0x112: addq $0x1,(%rax) on stock kernel #0. Two further NULL derefs stack behind it (in6_ifawithifp via ip6_input.c:531-534 over NULL if_addrheads[]; in6_addr2zoneid via ip6_mdq:1420-1421 over NULL scope6_id) - the second was hit on the first fix iteration, the third is guarded the same way the output side already is (ip6_mroute.c:1433-1435). Distinct from DF-0423 (which needs a deleted register mif): this fires during normal RP operation with a valid mif and needs no MFC match. Write primitive is +=1 at VA 0x0 (unmapped, value/address not attacker-controlled) - DoS only, no escalation. Fix (allocate if_data_pcpu + if_addrheads[] in add_m6if, input-side register scope guard in ip6_mdq) validated on rebuilt kernel #1: both scoped variants traverse the full decap->mforward->mdq path (counters incremented), no panic.",
 "exploit_chain": "root daemon: MRT6_INIT(8-byte) -> MRT6_ADD_MIF(0,MIFF_REGISTER) -> MRT6_ADD_MFC(parent=0); attacker: 1x IPv6/PIM REGISTER (ver2 type1, non-null, valid cksum, inner=valid ip6 hdr w/ multicast dst) -> pim6_input -> if_simloop(multicast_register_if) -> IFNET_STAT_INC writes NULL+percpu -> supervisor write VA 0x0 -> panic. No uid0 route: page 0 unmapped, write value fixed +1.",
 "evidence": [
  "run.log (baseline run cut at sendto by the panic)",
  "panic.txt (Fatal trap 12, Stopped at if_simloop+0x112, fault VA 0x0)",
  "panic.2.txt (second-layer crash in6_ifawithifp+0x35 on partial fix)",
  "fix_run.log (kernel #1: both variants forwarded, counters mif0 in=2, sg pkt=1+1, no panic observed)",
  "VERDICT.md (full 3-layer chain with path:line)"
 ],
 "kernel_refs": [
  "sys/netinet6/ip6_mroute.c:1842",
  "sys/netinet6/ip6_mroute.c:585-596",
  "sys/netinet6/ip6_mroute.c:1420-1421",
  "sys/netinet6/ip6_mroute.c:1433-1435",
  "sys/net/if_loop.c:284",
  "sys/net/if_var.h:685-688",
  "sys/net/if.c:550-553",
  "sys/net/if.c:591-593",
  "sys/netinet6/ip6_input.c:531-534",
  "sys/netinet6/scope6.c:278-288"
 ],
 "poc_changes": "v1 did not panic (single uninstrumented variant); v2 added sys/param.h (NBBY), local SIOCGETSGCNT/SIOCGETMIFCNT defines, counter/upcall probes, second scoped variant, hand-computed PIM REGISTER checksum (pseudo-header len=PIM_MINLEN nxt=103), 8-byte MRT6_INIT arg (DF-3378). Crash site moved two layers earlier than the seeds scope6 prediction - documented.",
 "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: Fri Sep 11 20:41:14 UTC 2026 (fix)",
 "runtime_sec": 2820,
 "guest_dirty": 0,
 "build_cmd": "cc -O -Wall -o /tmp/df3377 /root/poc/trigger_pim6_reg.c",
 "run_cmd": "/tmp/df3377",
 "code_hash": "516101d0f0edd47856325848086248ea2663ccb9da3831edb8e5c6e9adf061c3",
 "notes": "Guest left clean via vm.sh reset with-src. v6 file compiled unconditionally with inet6 (sys/conf/files:1850) - no custom kernel needed, stock X86_64_GENERIC. The crash needs no MFC match (re-injection panics before forwarding lookup). pim6_input itself parses lengths correctly (PIM_MINLEN/PIM6_REG_MINLEN checks verified).",
 "recommended_fix": "Allocate if_data_pcpu and if_addrheads[] for multicast_register_if in add_m6if (mirror if_attach) and skip the input-side in6_addr2zoneid for register-parent routes in ip6_mdq (mirror the existing output-side skip).",
 "fix_status": "fixed",
 "fix_kernel_uname": "DragonFly 6.5-DEVELOPMENT #1: Fri Sep 11 20:41:14 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC",
 "fix_baseline_reproduced": 1,
 "fix_patched_reproduced": 0,
 "fix_verdict": "fix.diff applied to guest /usr/src, X86_64_GENERIC rebuilt+installed+rebooted; identical PoC run completes both variants through the full register-decap forwarding path with counters incremented and no panic; baseline panic signature gone. First fix iteration (if_data_pcpu only) still crashed at in6_ifawithifp, proving layer 2 - final diff allocates both arrays.",
 "fix_evidence": "fix_run.log (kernel #1 clean run), fix_build.log (build summary), panic.2.txt (intermediate-layer crash proving the depth of the missing-initialization problem)"
}