# DF-3370 — VERDICT

**Status: reproduced** (deterministic kernel NULL-deref panic on the stock
INVARIANTS kernel; one-line fix validated on a rebuilt kernel).

## What was proven, on the guest

Baseline (stock kernel #0, Thu Jul  2 06:02:54 UTC 2026), as root:

```
/root/rawdf/rawdf     # raw socket + IP_HDRINCL + IP_MULTICAST_IF(vtnet0)
                      # 2000-byte IP_DF packet to 224.0.0.5
→ ssh session never returns; serial console:
  Fatal trap 12: page fault while in kernel mode
  fault virtual address = 0x70
  Stopped at ip_output+0x5ee: testb $0x5,0x70(%rax)
```

`0x70` is `offsetof(struct rtentry, rt_flags)`; `testb $0x5, 0x70(%rax)` is
the compile of `ro->ro_rt->rt_flags & (RTF_UP | RTF_HOST)` at
sys/netinet/ip_output.c:712 with `ro->ro_rt == NULL`. Deterministic,
reproduced on first send, no race.

## Reachability trace (why ro_rt is NULL)

1. raw socket (IPPROTO_RAW, IP_HDRINCL) — privileged (raw_ip.c:473
   `SYSCAP_NONET_RAW`), DFly has no unprivileged IP_DONTFRAG
   (netinet/in.h:405 commented out; udp never sets IP_DF — verified by grep:
   only tcp_output.c:1245, tcp_syncache.c:1236, ip_carp.c:1380 set IP_DF,
   all unicast-with-route or kernel-internal).
2. `IP_MULTICAST_IF` (index form) → `imo->imo_multicast_ifp = vtnet0`
   (ip_output.c:1494-1558 via rip_ctloutput → ip_ctloutput → ip_setmoptions).
3. sendto 2000 B to 224.0.0.5 → `ip_output` (rip_output passes
   `&inp->inp_route`, ro_rt NULL on first send):
   - ip_output.c:309-317: `IN_MULTICAST && imo && imo->imo_multicast_ifp`
     branch selects ifp **without any route lookup** — ro_rt stays NULL;
   - :345-455: multicast glue (TTL, src) → `goto sendit`;
   - :655: `ip_len(2000) > if_mtu(1500)`; not TSO/CSUM_FRAGMENT;
   - :703: `ip->ip_off & htons(IP_DF)` → :712 `ro->ro_rt->rt_flags` → panic.

Severity stays **Low** because the trigger needs privilege on this system;
the missing NULL check is nonetheless a real defect (the v6 twin guards the
equivalent path: ip6_output.c:1059-1064), and any future DF-setter reachable
unprivileged would promote this to an unprivileged panic.

## Fix validation (full kernel rebuild)

`fix.diff` (one hunk: `ro->ro_rt != NULL &&` guard at ip_output.c:712):
applied to the guest's /usr/src, `make -j6 nativekernel && make nativekernel
installkernel`, rebooted into kernel #2 (Fri Sep 11 14:47:59 UTC 2026).
Re-running the **exact** PoC:

```
DF-3370: sendto returned -1 errno=40 (Message too long)
DF-3370: EMSGSIZE — patched behaviour, no panic
```

Guest alive, correct EMSGSIZE error returned to the socket. Baseline panic
vs patched clean-return recorded in panic.txt / run.fixed.log.

**Kernel refs:** sys/netinet/ip_output.c:712-715 (missing NULL check),
:309-317 (route-less multicast branch), :345-455, :655-658, :703-719;
sys/netinet6/ip6_output.c:1059-1064 (guarded twin);
sys/netinet/raw_ip.c:473 (SYSCAP_NONET_RAW), :220-290 (rip_output),
:606-633 (rip_send); sys/netinet/in.h:405 (no IP_DONTFRAG).

## Fix status (batch validation)
Applied with the 36 sibling fix.diffs of this batch in findings/poc/_batch41/all_fixes.patch; single in-guest `make -j6 nativekernel KERNCONF=X86_64_GENERIC` completed RC=0 with zero errors under -Werror (full log: findings/poc/_batch41/fix_build8.log). Behavior A/B intentionally skipped for this Info-tier item.
