# DF-4110 — tl(4): tl_intvec_rxeof trusts device-written tlist_frsize — unbounded mbuf length on an MCLBYTES cluster

## What this is

`tl_intvec_rxeof()` (sys/dev/netif/tl/if_tl.c:1386-1441) reads the
received frame length straight out of the DMA-visible RX list header:

```c
total_len = cur_rx->tl_ptr->tlist_frsize;   /* if_tl.c:1405, u_int16_t, chip-written */
...
m->m_pkthdr.len = m->m_len = total_len;     /* if_tl.c:1422 */
ifp->if_input(ifp, m, NULL, -1);            /* if_tl.c:1437 */
```

The RX buffer is a single `m_getcl()` cluster — MCLBYTES = 2048 bytes
(if_tl.c:1347, tl_newbuf).  The only bound the driver programs is the
TL_MAXRX register (if_tl.c:1941, `tl_dio_write16(sc, TL_MAXRX,
MCLBYTES)`) — a *hint to a correctly-functioning chip*, not a kernel-side
check.  Nothing clamps `total_len` against MCLBYTES before it becomes the
mbuf length, so a device that writes a `tlist_frsize` of up to 65535 with
TL_CSTAT_FRAMECMP set hands the network stack an `m_len`/`m_pkthdr.len`
of up to 65535 on a 2048-byte allocation.  ether_input and everything
above it (VLAN unwrap, IP demux, BPF taps, socket copies) walks that mbuf
linearly → up to ~63 KB out-of-bounds *read* whose contents are
propagated to userland (kernel heap info leak) or crash the kernel on
unmapped pages.

Sibling of the well-known device-length-trust family (the reason many
BSD drivers gained `if (total_len > MCLBYTES) drop` guards).

## Threat model

Requires a malicious, compromised, or malfunctioning ThunderLAN NIC (or
any PCIe device able to DMA into the RX lists — e.g. faulty DMA engine
writing stale/garbage descriptor state).  Not triggerable by an
unprivileged local user on a healthy NIC; a remote peer cannot exceed
TL_MAXRX on a compliant chip.  Genuinely hardware-gated, hence severity
Medium rather than High.

## PoC status — untested (hardware absent)

The audit guest has `vtnet0 lo0` only — no ThunderLAN PCI device
(presence_probe.sh).  The OOB read cannot be entered on the guest, so no
PoC run was attempted; the finding is certain at source level.

## Fix

Clamp `tlist_frsize` to MCLBYTES and recycle the descriptor (same shape
as the existing ENOBUFS path) — see fix.diff.
