# DF-3679 VERDICT — igb_rxeof unvalidated descriptor length

## Status: inconclusive on guest (no igb hardware) — source-certain

## Root cause (path:line)
`igb_rxeof()` (`sys/dev/netif/igb/if_igb.c:2712-2838`):

```c
2744:  len = le16toh(cur->wb.upper.length);      /* NIC DMA write-back, untrusted */
...
2763:  if (igb_newbuf(rxr, i, FALSE) != 0) { ... }
2768:  mp->m_len = len;                          /* NO bound vs posted buffer */
2769:  if (rxr->fmp == NULL) {
2770:      mp->m_pkthdr.len = len;
...
2776:      rxr->fmp->m_pkthdr.len += len;        /* unbounded accumulation */
```

The posted buffer is one `MCLBYTES` cluster (`igb_newbuf:2423-2434`):
`m_getcl()` → 2048-byte cluster; `m_adj(m, ETHER_ALIGN)` front-trims 2 bytes
whenever `max_frame_size <= MCLBYTES - ETHER_ALIGN` (`:2433`), so effective
capacity is 2046 (MTU <= 2028) or 2048 (jumbo). The RX DMA map is loaded with
the *post-trim* length (`:2436-2437`), i.e. exactly the usable region.

Legitimate lengths are bounded by hardware configuration only:
- `igb_init_rx_unit` programs `SRRCTL.BSIZEPKT = 2048` (`:2537,:2542`) and
  `RLPML = max_frame_size + VLAN_TAG_SIZE` (`igb_set_vlan:2870-2871`);
  RLPML counts the VLAN tag and FCS, both stripped before the buffer write,
  so the largest legit single-descriptor write is `max_frame_size` bytes.
- NOTHING in the driver validates the write-back value.

Therefore any value in `[max_frame_size+1 .. 65535]` written by the device
(descriptor corruption, device fault, erratum, or a malicious DMA source such
as a VF assigned to an untrusted guest) propagates straight into
`m_len`/`m_pkthdr.len`, and `ifp->if_input(ifp, m, pi, cpuid)` (`:2820`) hands
the oversized mbuf to `ether_input`/IP parsing, which reads past the cluster
(heap OOB read, up to 63,487 bytes past a 2048-byte cluster). INVARIANTS
builds may catch some walks (`m_length` assertions elsewhere), production
builds leak/panic non-deterministically.

This is exactly the DF-3604/DF-3639/DF-3663/DF-3667 family; ix(4) shares the
identical pattern (`sys/dev/netif/ix/if_ix.c:3031` `mp->m_len = len;`), i.e.
the family defect is systemic across e1000-class drivers in this tree.

## Why not reproduced on the guest
The audit guest (DragonFly 6.5-DEVELOPMENT x86_64, QEMU/KVM) has no igb
device: `pciconf` shows no Intel 82575/82576/82580/I210/I350 class device and
`ifconfig -a` lists only `vtnet0` (virtio) + `lo0`. The driver is compiled
into the kernel (`kldload if_igb` → "module already loaded or in kernel";
`/boot/kernel/if_igb.ko` present). With no device, `igb_attach()` never runs,
so `igb_rxeof()` cannot be exercised. See `run.log`.

## Exploitability
Attacker model: the value is NIC-controlled DMA, not directly writable by an
unprivileged local user or a remote peer. Realistic sources: descriptor
corruption after device fault/erratum, PCIe device attacked/firmware-compromised,
or SR-IOV VF passthrough to an untrusted guest (the igb driver explicitly
supports VF device IDs, `igb_devices[]`, `sc->vf_ifp`). Impact ceiling: kernel
heap info leak via OOB-read packet data reaching user-visible paths, or panic.
Medium severity, consistent with the family findings.

## Fix
Clamp/discard before assigning to the mbuf (`fix.diff`, bound is dynamic
because jumbo mode legitimately posts 2048-byte descriptors while aligned
mode posts 2046):

```c
if (len > (rxr->sc->max_frame_size <= MCLBYTES - ETHER_ALIGN ?
           MCLBYTES - ETHER_ALIGN : MCLBYTES)) {
        IFNET_STAT_INC(ifp, ierrors, 1);
        goto discard;
}
```

Fix not validated on guest (no hardware): `fix_status = not_testable`.

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