# VERDICT — DF-3461

**Status:** untested at kernel level (by design — Info/unreachable finding);
arithmetic mirror reproduced on guest toolchain.
**Impact:** none (hardening).
**Confidence:** certain (code behavior); reachability from any in-tree caller:
none.

## Root cause

`sys/netinet6/in6_cksum.c:116`:

```c
if (m->m_pkthdr.len < off + len) {
        panic("in6_cksum: mbuf len (%d) < off+len (%d+%d)", ...);
}
```

`off` and `len` are `u_int32_t` (`in6_cksum.c:91`). `off + len` is computed in
unsigned 32-bit; values near 2^32 wrap to small numbers, the comparison then
passes, and the intended "should never happen" panic is skipped. The mbuf walk
(`:150-156`) then consumes the whole chain while `off` remains huge, exits with
`m == NULL`, and `:157-158`

```c
w = (u_int16_t *)(mtod(m, u_char *) + off);
mlen = m->m_len - off;
```

read `m->m_data` through the NULL pointer → low-page fault panic (uncontrolled,
not the intended message). A wrapping `len` alone (with small `off`) instead
drains the chain in the final loop and hits the `panic("out of data")` at
`:285-286` — also bypassing the intended first panic, same root cause.

## Reachability analysis (why Info)

Caller matrix (every `in6_cksum()` call site), pass-2 verified:

| Caller | off/len derivation | bounded? |
|---|---|---|
| `icmp6.c:404,440` | `icmp6len = m->m_pkthdr.len - *offp`, `icmp6len >= 4` checked | yes |
| `icmp6.c:2093,2612` | self-built packets, `plen == m_pkthdr.len - 40` | yes |
| `udp6_usrreq.c:146-169` | `plen = ntohs(ip6_plen) - off + 40`, `ulen == plen` required; `IP6_EXTHDR_CHECK(m, off, 8)` first | yes |
| `tcp_input.c:655,695` (via `tcp6_input` `tcp_input.c:629-634` which pulls up ≥ `sizeof(struct tcphdr)`) | `tlen = 40 + plen - off0`; ip6_input clamped `pkthdr.len == 40 + plen` | yes |
| `raw_ip6.c:151` | `len = m->m_pkthdr.len - *offp` | yes |
| `raw_ip6.c:418`, `udp6_output.c:249`, `tcp_output.c:1072`, `tcp_subr.c:676`, `tcp_syncache.c:1308`, `mld6.c:468`, `nd6_nbr.c:580,1043` | locally-built mbufs, consistent by construction | yes |
| `ip6_mroute.c:1705` (PIM, mrouter only) | `cksumlen ∈ {8, pimlen}` after `IP6_EXTHDR_CHECK(m, off, minlen)`; pimlen ≤ clamped payload | yes |

The clamp that anchors everything: `ip6_input.c:628-638` — packets shorter
than `40 + ip6_plen` are dropped; longer ones are trimmed to exactly
`40 + ip6_plen`. Largest possible `len` is therefore ~64 KiB — a wrap needs
`off + len ≥ 2^32`, impossible from any caller.

The mirror `wrap_demo.c` (built with the guest toolchain, `run.log`) shows the
bypass arithmetic exactly; a KLD calling `in6_cksum(m, nxt, 0xFFFFFFFF, 41)`
would convert this into a guest panic, but that only demonstrates what the
mirror already proves and would dirty an otherwise clean guest for an Info
finding — deliberately not done.

## Fix

Overflow-safe re-statement of the same invariant (see `fix.diff`):

```c
if (len > (u_int32_t)m->m_pkthdr.len ||
    off > (u_int32_t)m->m_pkthdr.len - len)
        panic(...);
```

`fix.diff` authored against the read-only `sys/` tree; not applied, not kernel-
built (Info finding — fix validation not applicable; `fix_status:
not_testable`).

## 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.
