DragonFlyBSD Kernel Audit
DF-2610 / verdict.json
← back to finding ↓ download raw
{
  "finding_id": "DF-2610",
  "status": "not_reproduced",
  "reproduced": 0,
  "impact": "none",
  "confidence": "likely",
  "verdict": "Source-level defect CONFIRMED verbatim in the current tree (guest /usr/src md5-identical to audit tree): icmp6.c:2160 takes ip6=mtod(m) BEFORE IP6_EXTHDR_CHECK at 2187, and the non-PULLDOWN branch compiles (no PULLDOWN_TEST anywhere in sys/), so nd_rd (2188), redtgt6/reddst6 (2196-2197) and ip6->ip6_hlim (2211) would dangle if the check's m_pullup reallocated the mbuf - violating the file's own invariant at icmp6.c:412. LIVE MANIFESTATION NOT REPRODUCIBLE from userspace on this kernel: (1) the dispatch copy at icmp6.c:787 strips M_LOOP (M_COPYFLAGS, mbuf.h:281-284), so the copy always takes the macro's non-pullup branches (ip6.h:285-297); (2) the M_LOOP original reaches icmp6_redirect_input only if that m_copym fails (cluster exhaustion); (3) the reallocating m_pullup path (uipc_mbuf.c:2125-2135) requires an M_EXT-or-no-room FIRST mbuf with off+icmp6len<=MHLEN, but sosend always sizes the first mbuf to the full send via m_getl (uipc_socket.c:866-887) and rip6_output's M_PREPEND (raw_ip6.c:326) splits off an internal header mbuf - so loopback chains are always [internal-hdr][cluster...] and take the in-place pullup (uipc_mbuf.c:2119-2124) that keeps ip6 valid; want>MCLBYTES makes m_pullup NULL and the macro frees+returns before line 2188. Live evidence: 70+ type-137 redirects of every shape (40..8000 bytes, multi-iov, bursts) traversed the full validation block (dmesg rejection log from icmp6.c:2241-2246; icp6s_inhist[137] 1->71) with zero panics/corruption. Defect is a latent class violation as filed (confidence: speculative); the one-line re-derive fix is warranted.",
  "exploit_chain": "",
  "evidence": "run.log: dmesg line 'ICMP6 redirect rejected; not equal to gw-for-src=::0001 (must be same): (src=fe80:0002::0001 dst=::0001 tgt=fe80:0002::)' (log at icmp6.c:2241-2246, i.e. execution passed the would-be-stale reads at 2196-2197); ic6stat inhist[137] 1->71 across all sends; 'ALIVE_AFTER_SENDS' + uptime after chain/burst shapes; raw137listen confirming wire src=fe80::1 scope=2 hlim=255.",
  "kernel_refs": [
    "sys/netinet6/icmp6.c:2160",
    "sys/netinet6/icmp6.c:2186-2188",
    "sys/netinet6/icmp6.c:2196-2197",
    "sys/netinet6/icmp6.c:2211",
    "sys/netinet6/icmp6.c:412",
    "sys/netinet6/icmp6.c:781-793",
    "sys/netinet/ip6.h:277-306",
    "sys/kern/uipc_mbuf.c:2103-2153",
    "sys/sys/mbuf.h:281-284",
    "sys/kern/uipc_socket.c:866-887",
    "sys/netinet6/raw_ip6.c:326",
    "sys/net/if_loop.c:274"
  ],
  "poc_changes": "Standalone toolkit written from scratch (redir6 sender, ic6stat binary-stats decoder, raw137listen observer). Two material fixes found during verification: (1) sender originally used ICMPv6 type 139 (NI query) instead of 137 (ND_REDIRECT) - corrected after ic6stat inhist and the nodeinfo responder exposed the mix-up; (2) nd_rd_dst pointed at an unroutable address so rtpurelookup returned NULL silently - changed to the queried destination (local host route) to make the gateway-validation log fire as the traversal oracle.",
  "attempts": 5,
  "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": 300,
  "guest_dirty": 0,
  "build_cmd": "cc -O2 -Wall -o redir6 redir6.c && cc -O2 -Wall -o ic6stat ic6stat.c && cc -O2 -Wall -o raw137listen raw137listen.c",
  "run_cmd": "sh run.sh   (as root; net.inet6.icmp6.nd6_debug=1 enables the nd6log traversal oracle)",
  "code_hash": "23905d062baeeb618dee2b847199cdbb15521b3454b8febd5b5ed8a3b4e953c1",
  "notes": "Honest bottom line: the finding's CODE claim is true and verified line-by-line; its own 'not presently reproducible end-to-end' assessment is confirmed and extended with a complete reachability trace of why no userspace producer can build the required [M_EXT short first] chain into icmp6_redirect_input. Any future producer change (LRO/driver loopback chains) plus mbuf pressure would arm it; the 5-line fix removes the class.",
  "recommended_fix": "Re-derive ip6 = mtod(m, struct ip6_hdr *) immediately after IP6_EXTHDR_CHECK in icmp6_redirect_input, mirroring icmp6_input/icmp6_notify_error/icmp6_error (see fix.diff).",
  "fix_status": "not_testable",
  "fix_kernel_uname": "",
  "fix_baseline_reproduced": 0,
  "fix_patched_reproduced": 0,
  "fix_verdict": "Fix kernel not built: the defect never manifests at runtime on this kernel (unreachable mbuf shape), so there is no observable behavioral delta to validate a patched kernel against. fix.diff is a mechanical pointer re-derivation identical in shape to the already-correct sibling functions (icmp6.c:420, 861, 978, 340); compile-correctness follows the same pattern.",
  "fix_evidence": "VERDICT.md reachability trace (uipc_socket.c:866 m_getl, raw_ip6.c:326 M_PREPEND, uipc_mbuf.c:2119-2135 in-place-vs-realloc conditions, mbuf.h:281-284 M_COPYFLAGS) plus run.log survival of all chain shapes."
}