# DF-3663 VERDICT — bge_rxeof trusts NIC-DMA'd return-ring bge_len

**Status: INCONCLUSIVE at runtime (no bge hardware on the audit guest);
source-level CERTAIN.**

## Root cause (path:line, audited tree == guest /usr/src, md5-verified)

`sys/dev/netif/bge/if_bge.c:3144`:

```c
m->m_pkthdr.len = m->m_len = cur_rx->bge_len - ETHER_CRC_LEN;
```

`cur_rx` is a `struct bge_rx_bd` in the **host-memory RX return ring**
(`sc->bge_ldata.bge_rx_return_ring[sc->bge_rx_saved_considx]`,
if_bge.c:3058-3059) — memory the NIC fills in by DMA. `bge_len` is a
plain `uint16_t` (`sys/dev/netif/bge/if_bgereg.h:2327-2331`); nothing on
the path bounds it by the buffer that was actually posted to the device:

- **std ring**: `bge_newbuf_std()` (if_bge.c:1016-1057) posts an
  `m_getcl()` cluster — MCLBYTES = 2048 — with `m_adj(ETHER_ALIGN)`
  (if_bge.c:1027-1030) leaving 2046 usable bytes; the producer BD length
  is `rc->bge_mbuf->m_len` (if_bge.c:1070).
- **jumbo ring** (bge supports jumbo, unlike the bnx sibling DF-3639):
  `bge_newbuf_jumbo()` (if_bge.c:1079-1123) attaches a driver-pool slot
  of `BGE_JUMBO_FRAMELEN` = 9018 bytes (if_bgevar.h:56) with
  `m_adj(ETHER_ALIGN)` → 9016 usable; the 384 slots are carved from one
  contiguous `BGE_JMEM` DMA block (if_bge.c:910-921), so an oversized
  `bge_len` on the **last** slot reads past the entire allocation.

A faulty or malicious device that writes `bge_len = 65535` (error flags
clear) makes the driver hand the stack an mbuf describing 65531 bytes
inside the 2046/9016-byte buffer.

## Sinks

1. `ifp->if_input(ifp, m, NULL, -1)` (if_bge.c:3170) → `ether_input()`
   runs `ETHER_BPF_MTAP(ifp, m)` (sys/net/if_ethersubr.c:1512) **before**
   any protocol validation — the bpf tap copies `m_pkthdr.len` bytes out
   of the cluster to every capturing socket ⇒ **kernel heap OOB read /
   info disclosure of up to ~63.5 KB** (std) per frame.
2. IP/ARP/VLAN parsing and socket copies walk the same OOB range
   (further leak; fault/panic when crossing an unmapped page).
3. **i386-only write variant (CWE-787)**: with `BGE_FLAG_RX_ALIGNBUG`
   (BCM5701 PCI-X, if_bge.c:2206-2208), `#if !defined(__x86_64__)`
   code at if_bge.c:3138-3141 executes
   `bcopy(m->m_data, m->m_data + ETHER_ALIGN, cur_rx->bge_len)` — the
   same untrusted length used as a **copy size into the 2048-byte
   cluster ⇒ heap OOB write**. Compiled out of x86_64 kernels (the
   audit guest's platform).

## Non-issues checked (so the finding is exactly scoped)

- `bge_len < ETHER_HDR_LEN + ETHER_CRC_LEN` (18) ⇒ negative `m_len`,
  harmlessly dropped at sys/net/if_ethersubr.c:1502-1506
  (`m_len < sizeof(struct ether_header)`) — no bce/DF-3604-style
  unsigned-underflow panic here.
- The producer-side BD length, `BGE_RX_MTU` register (if_bge.c:3769)
  and RCB max-frame (if_bge.c:1575) are all device-side limits a
  *healthy* NIC enforces; the defecting device this check guards
  against is precisely the one that ignores them.
- The unvalidated `bge_idx` index issue is **DF-1159** (pass 1) and is
  not re-reported here; this finding is the independent *length* trust.

## Why inconclusive at runtime

The audit QEMU guest has virtio-net only:
`pciconf -l | grep -i -E "bge|broadcom|14e4"` ⇒ `NO_BROADCOM_DEVICE`,
`ifconfig -l` ⇒ `vtnet0 lo0`, `sysctl hw.bge` ⇒ unknown oid
(run.log). `pci/if_bge` **is** compiled into the running kernel
(`kldstat -v` id 59), and the guest's `/usr/src/sys/dev/netif/bge/`
md5-matches the audited tree, so the code is present and identical —
only the device (and therefore `bge_attach` → `bge_rxeof`) is
unreachable. No emulation of a BCM57xx RX engine exists in the harness.
Same classification as the bnx/bce siblings DF-3639/DF-3604.

## Fix validation

`fix.diff` clamps the frame to the posted buffer (`m->m_len`) and drops
it (ierrors++, m_freem, continue) when `bge_len` is outside
`[ETHER_HDR_LEN + ETHER_CRC_LEN, m->m_len + ETHER_CRC_LEN]`, placed
**before** the `#if !defined(__x86_64__)` block so the i386 ALIGNBUG
bcopy is covered too. `git apply --check` passes against the pristine
tree. Runtime baseline-vs-patched comparison is impossible for the same
hardware reason (fix_status: not_testable).

## Exploitability ceiling

Local info-leak class (kernleak): unprivileged user + bpf listener reads
adjacent kernel heap (adjacent mbuf clusters, potentially pointers/data).
Not a write primitive on x86_64; on i386 with a BCM5701 PCI-X part it is
additionally a NIC-directed heap overwrite. Requires a misbehaving
device (malicious peripheral / firmware compromise / DMA attack), hence
AC:H and Medium severity, matching the calibrated sibling findings.

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