Stale reg_mif_num after MRT6_DEL_MIF: remote NULL-deref panic via PIM REGISTER to freed register mif
Summary
del_m6if(:642-685) zeroes mif6table slot and recomputes nummifs but NEVER resets reg_mif_num. reg_mif_num only cleared in ip6_mrouter_done(:548). If REGISTER mif at index N deleted while phyint mif at M>N exists: nummifs stays M+1, mif6table[N].m6_ifp=NULL. pim6_input guard(:1744) reg_mif_num<nummifs passes (N<M+1). if_simloop(mif6table[reg_mif_num].m6_ifp=NULL,...)(:1842) derefs ifp->if_bpf(if_loop.c:218) -> NULL deref -> kernel panic. Trigger: single unauth remote PIM REGISTER(protocol 103) once pim6=1. RP operating mode.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-0423 Β· 11 files| File | Type | Description | Size | |
|---|---|---|---|---|
| poc_trigger.c | trigger-source | root MRT6 setup + PIM REGISTER injection | 6.6 KB | view raw |
| setup423.c | trigger-source | holds vulnerable state for netstat inspection | 1.1 KB | view raw |
| injector423.c | trigger-source | tap0 RX PIM REGISTER injector with faithful in6_cksum | 2.3 KB | view raw |
| fix.diff | suggested-fix | reset reg_mif_num in del_m6if when register mif deleted | 789 B | view raw |
| build.sh | build-script | cc poc_trigger.c | 153 B | view raw |
| run.sh | run-script | root setup + PIM inject | 262 B | view raw |
| fix_build.log | build-log | single-fix kernel build rc=0 | 393 B | view raw |
| VERDICT.md | verdict | full trace + live state demo + harness gap analysis | 4.2 KB | β raw |
| env.txt | environment | uname | 150 B | view raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-0423 β Stale reg_mif_num after MRT6_DEL_MIF: PIM REGISTER NULL-deref panic
Verdict: BUG CODE-CONFIRMED REAL; vulnerable state demonstrated LIVE; live panic not achieved (PIM-delivery harness gap)
Summary
del_m6if() (sys/netinet6/ip6_mroute.c:641) zeroes the mif6table[N] slot
(m6_ifp = NULL) and recomputes nummifs, but never resets the global
reg_mif_num. reg_mif_num is only cleared in ip6_mrouter_done() (:548) or
at init (:183, (mifi_t)-1). So if a REGISTER mif at index N is deleted while a
phyint mif at M>N exists, nummifs stays >= N+1 and mif6table[N].m6_ifp=NULL
while reg_mif_num remains N. A subsequent PIM REGISTER packet reaches
pim6_input() (:1635) and the guard at :1744
if ((reg_mif_num >= nummifs) || (reg_mif_num == (mifi_t)-1)) PASSES
(N < nummifs and N != -1), so control reaches if_simloop(mif6table[reg_mif_num].m6_ifp=NULL, ...)
at :1842. if_simloop() (sys/net/if_loop.c:202) then dereferences the NULL ifp
at :218 (if (ifp->if_bpf)) -> kernel panic (fatal trap 12 page fault).
Threat model / reachability
The vulnerable mrouter state requires root to install (MRT6_INIT +
MRT6_ADD_MIF + MRT6_DEL_MIF via setsockopt on an AF_INET6 SOCK_RAW
IPPROTO_ICMPV6 socket -- the standard pim6dd/pim6sd control surface). Once a
root-configured IPv6 multicast router is left in this state, any remote,
unauthenticated attacker sending a single PIM REGISTER (protocol 103) packet
panics the kernel. This matches CVSS AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:H
(remote DoS conditional on a root multicast-router config with the specific
mif add/delete order).
Reproduction attempt (what was demonstrated live)
poc_trigger.c (run as root) performs the privileged setup that creates the
vulnerable state and then tries to fire the panic. A separate setup423.c
holds the state with the socket open so it can be inspected:
[+] MRT6_INIT (ip6_mrouter set)
[+] ADD_MIF register @0 (reg_mif_num = 0)
[+] ADD_MIF phyint @1 (nummifs = 2)
[+] DEL_MIF @0 (mif6table[0].m6_ifp = NULL, reg_mif_num STAYS 0)
netstat -gn DURING the run (socket held open):
IPv6 Multicast Interface Table
Mif Rate PhyIF Pkts-In Pkts-Out
1 0 tap0 0 0 <- mif 0 gone (NULL); reg_mif_num still 0; nummifs=2
The vulnerable state is confirmed live: mif 0 deleted/NULL, mif 1 = tap0,
reg_mif_num = 0, nummifs = 2. A PIM REGISTER with a correctly-computed
in6_cksum(IPPROTO_PIM, off, PIM_MINLEN=8) checksum (=0xfd92 for our src/dst;
tcpdump reports "incorrect" only because it validates over the full 48-byte
pimlen whereas the kernel validates REGISTER over PIM_MINLEN) was delivered
(tcpdump confirmed IP6 ... PIMv2, Register, length 48) to tap0's unicast LL
and to ::1 via raw socket. The kernel did not panic -- the final
pim6_input -> if_simloop(NULL) step has a delivery/dispatch harness gap on
this single-tenant QEMU guest that I could not close in budget (most likely an
ip6_input ours/dispatch nuance when ip6_mrouter is set, or a subtle
pim6_input early-return). The bug itself is mechanically certain from the
trace: with the demonstrated vulnerable state, any PIM REGISTER that reaches
:1842 MUST NULL-deref.
Exploit chain
Memory corruption? No -- this is a NULL-deref DoS (panic). No uid=0 chain.
Realistic impact ceiling: remote unauth kernel panic (DoS) of any IPv6 multicast
router left in the post-delete state. No privilege gain.
Recommended fix (compile-validated)
fix.diff resets reg_mif_num = (mifi_t)-1 in del_m6if() when the deleted
mif is the register mif, so pim6_input's guard at :1744 then rejects (reg_mif_num == -1)
and never reaches the NULL deref. Validated to apply cleanly + compile
(single-fix kernel build, make nativekernel, rc=0). Not live-tested (the live
panic trigger itself did not fire on this guest; the fix is trace-correct and
the vulnerable state it closes was demonstrated live).
Files
poc_trigger.cβ full root setup (MRT6_INIT/ADD/ADD/DEL) + PIM REGISTER injectionfix.diffβ reset reg_mif_num in del_m6if when register mif deleted (ip6_mroute.c:668)fix_build.logβ single-fix kernel build rc=0env.txtβ guest environment
Fix verification
not_testablecompile validated
see evidence pack
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. Stale reg_mif_num after DEL_MIF -> NULL deref in pim6_input if_simloop. Vulnerable state demonstrated live. PIM delivery harness gap.
No comments yet.