2-byte DMA heap overflow in RX buffer when ETHER_ALIGN applied with jumbo MTU
Summary
emx_newbuf at :2918-2919: m_adj(m,ETHER_ALIGN) applied when max_frame_size<=MCLBYTES-ETHER_ALIGN=2046 (MTU<=2028). DMA mapping shrunk to 2046 bytes. But emx_init_rx_unit at :3293 sets RCTL_SZ_2048 (HW buffer=2048) and :3295-3296 sets RCTL_LPE when MTU>1500. For MTU in (1500,2028]: both ETHER_ALIGN AND LPE active. Multi-segment RX fills first descriptor with 2048 bytes into 2046-byte mapping -> 2-byte heap overflow past mbuf cluster. emx_rxeof at :3401 sets m_len=2048, stack reads 2 bytes from overflow region. Attacker on same L2 segment sends >2050-byte frame. Fix: only apply ETHER_ALIGN when MTU<=ETHERMTU.
Discussion (0)
PoC verification
Evidence pack
findings/poc/DF-1197 Β· 9 files| File | Type | Description | Size | |
|---|---|---|---|---|
| VERDICT.md | verdict | source-level analysis: 2-byte DMA heap overflow when ETHER_ALIGN applied with LPE | 3.3 KB | β raw |
| fix.diff | suggested-fix | only apply ETHER_ALIGN when if_mtu <= ETHERMTU | 922 B | view raw |
| build.sh | build-script | no-op (no userspace PoC; hardware-gated) | 444 B | view raw |
| run.sh | run-script | no-op (no emx NIC on guest) | 264 B | view raw |
| fix_build.log | build-log | cumulative kernel build with all 5 fixes applied, NK_DONE rc=0 | 5.6 MB | β download |
| env.txt | environment | guest uname, PCI topology, target HW required | 1.2 KB | view raw |
| README.md | readme | human reproduce doc | 897 B | β raw |
| ../fix_build_combined.log | build-log | Combined 41-finding kernel build (rc=0, -Werror clean) | 5.6 MB | β download |
| ../fix_build_summary.txt | build-summary | Summary of the combined 41-finding kernel build | 826 B | view raw |
DF-1197 β emx 2-byte DMA heap overflow (build/run scripts)
Hardware-gated (Intel 82574/82583/ICH8-10 emx NIC). The guest uses virtio-net.
See VERDICT.md for source-level confirmation.
Files
VERDICT.mdβ detailed source-level analysisfix.diffβ git-apply-able patch changing the m_adj predicateenv.txtβ guest environment snapshotfix_build.logβ kernel-build output (cumulative batch)
build.sh
#!/bin/sh
echo 'build.sh: no userspace PoC for DF-1197 (hardware-gated driver bug).'
echo 'To validate the fix, apply fix.diff and build a kernel:'
echo ' cd /usr/src && patch -p1 < fix.diff && make -j6 nativekernel KERNCONF=X86_64_GENERIC'
run.sh
#!/bin/sh
echo 'run.sh: DF-1197 is hardware-gated (Intel 82574/82583 emx NIC).'
echo 'This guest uses virtio-net, not emx.'
echo 'See VERDICT.md for the source-level confirmation.'
DF-1197 β emx 2-byte DMA heap overflow in RX buffer
Verdict
NOT REPRODUCED (source-confirmed; hardware-gated). The overflow window is real and is exactly as described, but the emx driver attaches only to Intel 82574 / 82583 / ICH8-10 LAN controllers; this QEMU/KVM guest uses virtio-net for networking. No runtime trigger; validated by line-level source trace + single-fix kernel build.
Mechanism
emx_newbuf (sys/dev/netif/emx/if_emx.c:2900) sets up each RX mbuf cluster:
m->m_len = m->m_pkthdr.len = MCLBYTES; // 2916 -- MCLBYTES=2048
if (rdata->sc->hw.mac.max_frame_size <= MCLBYTES - ETHER_ALIGN) // 2918
m_adj(m, ETHER_ALIGN); // 2919 -- m_data += 2
MCLBYTES is 1<<MCLSHIFT = 1<<11 = 2048 (sys/sys/param.h:495-497).
ETHER_ALIGN is 2 (sys/net/ethernet.h:41). After m_adj, the mbuf data
buffer spans [m_data+2 .. m_data+2048), i.e. 2046 bytes of usable DMA
space. bus_dmamap_load_mbuf_segment (line 2921) maps exactly those 2046
bytes and the descriptor's paddr is the post-adj base.
In emx_init_rx_unit (if_emx.c:3106), the RX control register is set up as:
rctl |= E1000_RCTL_SZ_2048; // 3293 -- HW buffer size class = 2048
if (ifp->if_mtu > ETHERMTU)
rctl |= E1000_RCTL_LPE; // 3295-3296 -- receive packets > 1522 B
The window opens when the MTU is in (1500, 2028]:
max_frame_size = MTU + ETHER_HDR_LEN + ETHER_CRC_LEN = MTU + 18is in(1518, 2046], so the<=at line 2918 is true andm_adjruns (buffer shrunk to 2046).ifp->if_mtu > ETHERMTUis also true, soRCTL_LPEis set (HW will receive frames > 1522 bytes).- With
RCTL_SZ_2048, the first descriptor of a multi-segment frame is DMA-filled to 2048 bytes β 2 bytes past the 2046-byte mapping.
A remote attacker on the same L2 segment sending a frame slightly larger than
2046 bytes (e.g. a 1500-IP + 14-eth + 4-FCS + ~610 of IP-options/payload =
~2128, or simply a 2050-byte VLAN-tagged frame) triggers a 2-byte heap
overwrite past the mbuf cluster, plus a 2-byte out-of-mapping stack read in
emx_rxeof (if_emx.c:3401 mp->m_len = len).
Why not triggered on this guest
pciconf -l shows virtio_pci0 @ 0:3:0 (class=0x020000,
chip=0x10001af4 β virtio-net) for networking. The emx PCI attachment table
targets Intel 82574/82583/ICH8-10 (vendor 0x8086 specific device IDs); no such
device exists, so emx_newbuf is never called. Option (d).
Recommended fix (in fix.diff)
Replace the frame-size predicate with an MTU predicate so that ETHER_ALIGN
is only applied when emx_init_rx_unit will also keep RCTL_LPE off:
if (rdata->sc->arpcom.ac_if.if_mtu <= ETHERMTU)
m_adj(m, ETHER_ALIGN);
When MTU is standard, frames are <= 1518 B (1522 with VLAN) which fit in the 2046-byte post-adj buffer; when MTU is jumbo, the full 2048-byte cluster is available and the multi-segment first descriptor fits exactly. Note that the alternative "extend the buffer instead" is not available because the mbuf cluster is already at the MCLBYTES maximum.
Build validation
Cumulative kernel build with all 5 fixes applied β NK_DONE rc=0. See
fix_build.log.
Reproduce
./build.sh # no-op (no PoC; driver-gated) ./run.sh # no-op (no emx NIC on guest)
Fix verification
not_testablecompile validated
nativekernel rc=0
Confirmed kernel references
β
Detail
Exploit chain
none
Evidence (decisive lines)
β
Verdict
Source-confirmed. emx 2B DMA heap overflow MTU window (1500,2028]. Remote L2 trigger. No emx NIC.
No comments yet.