# DF-3933 verdict narrative

## Reproduced?
No (hardware-gated: the audit guest has no Attansic L1 / age(4) NIC).
Source-level certainty: certain — the arithmetic has no runtime dependency.

## Root cause chain (path:line)

1. age_rxeof() takes the frame length from the hardware-written return
   descriptor, unclamped:
   if_age.c:2000  `sc->age_cdata.age_rxlen = AGE_RX_BYTES(le32toh(rxrd->len));`
   — AGE_RX_BYTES is bits 16..31 of the DMA'd word (if_agereg.h:601-602):
   0..65535, fully NIC-controlled.
2. The receive buffers are MCLBYTE clusters with 2 bytes of headroom:
   age_newbuf() if_age.c:2742-2747
   (`m_getcl`, `m_adj(m, ETHER_ALIGN)`) and the per-buffer DMA tag is capped
   at MCLBYTES (if_age.c:1066-1076) — hardware may not write past 2048 bytes,
   and the usable payload region is 2046.
3. Single-segment completion path (count==0==nsegs-1):
   if_age.c:2074-2079
   ```c
   m = sc->age_cdata.age_rxhead;
   m->m_flags |= M_PKTHDR;
   m->m_pkthdr.rcvif = ifp;
   m->m_pkthdr.len = sc->age_cdata.age_rxlen;
   m->m_len = sc->age_cdata.age_rxlen - pktlen;   /* pktlen == 0 here */
   ```
   With `age_rxlen` up to 65535 and the cluster holding at most 2046 valid
   bytes, `m_len`/`m_pkthdr.len` claim up to ~63KB of payload that is not
   there.  `ifp->if_input(ifp, m, NULL, -1)` (if_age.c:2121) then lets
   ether_input, BPF listeners and the IP stack walk that entire span —
   heap over-read; the "packet" payload beyond byte 2046 is whatever sits
   after the cluster in the slab (adjacent mbufs, freed data, pointers).
4. Error-status frames are skipped early (if_age.c:2001-2016) but a clean
   status with a bogus length is not: nothing between :2000 and :2079
   compares `age_rxlen` against the buffer capacity.  (The nsegs-vs-pktlen
   consistency check lives in age_rxintr, if_age.c:2161-2164, and only
   cross-checks nsegs — the length itself is still trusted.)

## Relation to knowns
DF-1292 (known) is the *multi-segment* path: `mp->m_len =
AGE_RX_BYTES(desc->len)` at if_age.c:2037 per chained mbuf.  This finding is
the *single-segment* path assigning the RRD frame length to the one and only
mbuf (:2077-2079) — same trust, different source field and line, explicitly
in scope per pass-2 instruction (a).

## Threat model
Malicious/buggy NIC (DMA-fed descriptor), same boundary as DF-1292/DF-1293.

## Impact
Kernel heap over-read surfaced as packet payload (kernel memory disclosure
to anyone able to receive/bpf the frame) or stack panic on malformed
"headers" — Medium, hardware-gated.

## Fix
Clamp the single-seg length to MCLBYTES - ETHER_ALIGN (fix.diff); a full fix
also validates `age_rxlen >= ETHER_HDR_LEN + ETHER_CRC_LEN`.

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