# DF-4024 — re_rxeof trusts the NIC-DMA'd 14-bit GFRAGLEN with no bound vs MCLBYTES: heap OOB read up to ~14.3 KB past the 2 KB RX cluster into delivered frames (kernel heap info leak), and m_pkthdr.len beyond the fragment chain → panic

**File:** `sys/dev/netif/re/if_re.c` (pass 2)
**Class:** CWE-125 out-of-bounds read (kernel heap info leak / panic)
**Family:** DF-3604 (bce) / DF-3759 (alc) / DF-3933 (age) / DF-3989 (ale) —
this is the `re(4)` instance; pass 1 filed only DF-1336 (the exact-MCLBYTES
truncation bug, opposite direction, latent behind RE_JUMBO) against this
file. The device-fed-length trust documented here is live on the default
driver (RE_JUMBO is not defined anywhere in the tree; `RE_C_CONTIGRX` /
`RE_F_USE_JPOOL` are never set — the jumbo path is dead code and the active
RX path is `re_newbuf_std` + MCLBYTES clusters).
**Threat model:** faulty or malicious RTL8169SC/8168/8101E/8125 NIC DMA'ing
crafted completion descriptors (PCIe device trust — same model the family
uses). Not remotely triggerable on a correctly functioning NIC.
**Status:** source-level certain; runtime hardware-gated (guest is virtio-net
only — `env.txt`), `inconclusive` per family convention.

## Root cause

`re_rxeof()` reads the frame length straight out of the descriptor the NIC
owns:

```c
total_len = RE_RXBYTES(cur_rx);      /* if_re.c:1142 */
                                     /* if_revar.h:54: cmdstat & 0x3FFF */
                                     /* if_rereg.h:139: 14-bit GFRAGLEN */
```

`total_len` is a 14-bit device-fed value (0..16383). The error-summary
filter (`RE_RDESC_STAT_RXERRSUM`, :1187) is itself device-fed and bounds
nothing. The value is then applied with no validation against the buffer
geometry:

* **single-fragment EOF** (:1227-1229):
  `m->m_pkthdr.len = m->m_len = (total_len - ETHER_CRC_LEN);`
  on an mbuf whose cluster is MCLBYTES = 2048 (`re_newbuf_std`, :964-975,
  `m_getcl` + `m->m_len = MCLBYTES`). A descriptor claiming 16383 yields
  `m_len = 16379` — a 14,331-byte lie. Every consumer that trusts
  `m_len`/`m_pkthdr.len` (`ETHER_BPF_MTAP` in `ether_input`, header
  `mtod`/pullups past the first 2 KB, `m_copydata` bcopy of
  `min(m->m_len - off, len)` bytes) reads **adjacent kernel heap**, which
  is then delivered in packet payloads to sockets/BPF (info leak), or
  faults (panic) when the cluster ends a mapping.

* **multi-fragment EOF** (:1208-1226):
  `m_pkthdr.len = total_len - ETHER_CRC_LEN` may exceed the accumulated
  chain (k × 2048 + last-frag bytes); `m_copydata` then walks `m_next`
  past NULL — KASSERT panic on INVARIANTS, `NULL->m_len` page fault on
  GENERIC (sys/kern/uipc_mbuf.c `m_copydata`, KASSERTs compiled out).

* `total_len < ETHER_CRC_LEN` (device claims 0..3) is **safe**: the
  negative `m_len` is dropped by `ether_input`'s
  `m->m_len < sizeof(struct ether_header)` guard (sys/net/if_ethersubr.c,
  `ether_input`) — same benign sub-case as ale's `m_devget tot<=0`.

Legit frames are capped by `RE_RxMaxSize` programmed to
`sc->re_rxbuf_size` (MCLBYTES, :850; and re.c:1103-1105 programs
MTU+22 ≈ 1522), so any `total_len > 2048` on a single descriptor — or a
total exceeding the accumulated chain — is a device lie faithfully applied.

## Impact

On real re(4) hardware with a lying device: kernel heap contents delivered
into received frames (readable by any local user with a socket on the
interface — the leaked bytes ride in packet payloads), or kernel panic.
Inbound-only: no write primitive.

## Verification

`trigger.c` (build/run logs in this pack) prints the exact OOB extents from
the masks/geometry: 16379-2048 = **14,331 bytes** past the cluster for the
single-frag lie; the multi-frag table shows the chain-walk overshoot.
Hardware absence on the guest documented in `env.txt`.

## Fix

Validate `total_len` at the EOF descriptor against
`sc->re_rxbuf_size + accumulated chain bytes`, drop (ierrors + free chain +
re-arm descriptor) otherwise; track the chain length in a new
`sc->re_rxchain_len`. See `fix.diff` (applies clean; keeps the driver's own
error-drop idiom).

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