# DF-4113 — nge(4): nge_rxeof trusts device-written 16-bit descriptor BUFLEN — unbounded mbuf length on the jumbo cluster

## What this is

`nge_rxeof()` (sys/dev/netif/nge/if_nge.c:1198-1304) reads the received
frame length straight out of the DMA-visible RX descriptor:

```c
total_len = NGE_RXBYTES(cur_rx);   /* if_nge.c:1225 = cur_rx->nge_ctl & 0xFFFF (if_ngereg.h:517,527) */
```

and then, on the live x86-64 path, installs it as the mbuf length with
no clamp:

```c
} else {                                   /* nge_newbuf() succeeded */
        m->m_pkthdr.rcvif = ifp;
        m->m_pkthdr.len = m->m_len = total_len;   /* if_nge.c:1270 */
}
...
ifp->if_input(ifp, m, NULL, -1);           /* if_nge.c:1300 */
```

The RX buffer is one jumbo minicluster: NGE_JLEN = 9024 bytes with 8
consumed by the alignment `m_adj` (if_nge.c:1063-1074), i.e. 9016 usable
— and the descriptor told the chip only 9010 (c->nge_ctl = m->m_len).
Nothing checks `total_len` against any of that.  A descriptor BUFLEN
above 9016 with PKT_OK set produces an `m_len` up to 65535 on a 9 KB
allocation → ether_input and everything above walks past the cluster
(up to ~56 KB OOB read propagated to sockets/BPF = kernel heap info
leak, or page-fault panic).

The fallback copy path is equally unbounded: `m_devget(mtod(m, char *)
- ETHER_ALIGN, total_len + ETHER_ALIGN, 0, ifp)` (if_nge.c:1255-1256)
copies `total_len + 2` bytes *out of* the 9024-byte cluster — the copy
destination is fine (m_devget chunks correctly), the **source** read is
OOB for total_len > 9016.

Note the chip is run with `NGE_RXCFG_RX_GIANTS` (if_ngereg.h:308) and
MTU up to NGE_JUMBO_MTU=9000 (if_nge.c:1994), so oversized frames are
*accepted*, not dropped by config — the only thing standing between a
giant frame and an OOB is the chip's own descriptor-bounds behavior on
a compliant device.  A faulty or hostile DP83820 (or any PCIe peer
writing descriptor memory) bypasses it.

## Threat model

Requires a malicious/malfunctioning NIC or corrupted descriptor DMA —
not triggerable by an unprivileged user on healthy hardware.  Hence
Medium, memcorrupt-bucket (OOB read, no write).

## PoC status — untested (hardware absent)

Guest has `vtnet0 lo0` only — no NS DP83820/83821 (presence_probe.sh).
Source-level certainty.

## Fix

Clamp `total_len` to the usable cluster size and recycle the descriptor
(fix.diff).
