DF-3370 / verdict.json
{ "finding_id": "DF-3370", "status": "reproduced", "reproduced": 1, "impact": "panic", "confidence": "certain", "verdict": "ip_outputs DF/EMSGSIZE path dereferences ro->ro_rt at sys/netinet/ip_output.c:712 with no NULL check. Reachable with ro_rt==NULL via the multicast IP_MULTICAST_IF branch (:309-317) which selects ifp from imo without any route lookup: raw socket (privileged; DFly has no unprivileged IP_DONTFRAG, in.h:405) + IP_HDRINCL + IP_MULTICAST_IF(vtnet0) + 2000-byte IP_DF packet to 224.0.0.5. Reproduced deterministically on the stock INVARIANTS kernel: Fatal trap 12, fault VA 0x70 (= offsetof(rtentry, rt_flags)), Stopped at ip_output+0x5ee: testb $0x5,0x70(%rax). Severity Low only because the trigger requires privilege on this system; the v6 twin guards the analogous path (ip6_output.c:1059-1064). Fix validated by full kernel rebuild: patched kernel #2 returns EMSGSIZE, no panic.", "exploit_chain": "root: socket(SOCK_RAW, IPPROTO_RAW) -> IP_HDRINCL + IP_MULTICAST_IF(vtnet0 idx) -> sendto(2000B, dst 224.0.0.5, ip_off=IP_DF) -> ip_output multicast branch leaves ro_rt NULL -> ip_len>mtu with DF -> NULL+0x70 read -> kernel panic. Unprivileged trigger not available on this system (no IP_DONTFRAG; raw gated by SYSCAP_NONET_RAW); TCP DF always has a route.", "evidence": "panic.txt: Fatal trap 12 ... fault virtual address = 0x70 Stopped at ip_output+0x5ee: testb $0x5,0x70(%rax) on stock kernel #0; run.fixed.log: sendto returned -1 errno=40 (Message too long) on patched kernel #2 (fix.diff, make nativekernel), guest alive.", "kernel_refs": [ "sys/netinet/ip_output.c:712-715", "sys/netinet/ip_output.c:309-317", "sys/netinet/ip_output.c:345-455", "sys/netinet/ip_output.c:655-658", "sys/netinet/ip_output.c:703-719", "sys/netinet6/ip6_output.c:1059-1064", "sys/netinet/raw_ip.c:473", "sys/netinet/raw_ip.c:220-290", "sys/netinet/in.h:405" ], "poc_changes": "authored this pass; userland ip_mreqn comes from guest netinet/in.h (removed local def), IP header version/IHL set via raw byte 0x45 (userland struct ip has no ip_vhl).", "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 (baseline); #2: Fri Sep 11 14:47:59 UTC 2026 (fix validation)", "runtime_sec": 2400, "guest_dirty": 0, "build_cmd": "cc -O -Wall -o rawdf rawdf.c (fix validation: cd /usr/src && make -j6 nativekernel && make nativekernel installkernel)", "run_cmd": "/root/rawdf/rawdf", "code_hash": "1ea281a78193653b6d57070432ee0ae222a4afa6c62c120bb4c6f0ae6ade406e", "notes": "Fix validated by full in-guest kernel rebuild (kernel #2) + re-run of the exact PoC: EMSGSIZE, no panic. Guest reset to clean-source snapshot after validation.", "recommended_fix": "Add ro->ro_rt != NULL && guard before the rt_flags/rt_rmx dereference at ip_output.c:712 (see fix.diff).", "fix_status": "fixed", "fix_kernel_uname": "DragonFly dfbsd 6.5-DEVELOPMENT DragonFly 6.5-DEVELOPMENT #2: Fri Sep 11 14:47:59 UTC 2026 root@dfbsd:/usr/obj/usr/src/sys/X86_64_GENERIC x86_64", "fix_baseline_reproduced": 1, "fix_patched_reproduced": 0, "fix_verdict": "fix.diff (one-line NULL guard) applied to guest /usr/src, kernel rebuilt with make -j6 nativekernel and installed (kernel #2, 2026-09-11 14:47:59). Exact baseline PoC re-run: sendto() returns -1 EMSGSIZE (errno 40), no panic, guest remains up - the panic is gone and the correct error is delivered.", "fix_evidence": "run.fixed.log; build.log (kernel build + install completion lines); env.txt (patched uname #2)." } |