DF-3639 / trigger.c
/* * DF-3639 โ bnx(4) RX path trusts NIC-DMA'd return-ring bge_len * * Trigger (HARDWARE REQUIRED โ cannot run on the audit guest): * * The BCM5717/5718/5719/5720/577xx (bnx) RX completion path receives * `struct bge_rx_bd` entries in the host-memory return ring that the * NIC fills in via DMA. sys/dev/netif/bnx/if_bnx.c: * * 2810: cur_rx = &ret->bnx_rx_ret_ring[ret->bnx_rx_saved_considx]; * 2812: rxidx = cur_rx->bge_idx; <- NIC-written (DF-1148) * 2842: if (bnx_newbuf_std(ret, rxidx, 0)) ... <- swaps in a fresh * 2048-byte cluster * 2848: m->m_pkthdr.len = m->m_len = cur_rx->bge_len - ETHER_CRC_LEN; * ^^^^^^ NIC-written uint16_t, * NO MCLBYTES bound * * The receiving cluster is m_getcl() (MCLBYTES == 2048) with * m_adj(ETHER_ALIGN) => 2046 bytes usable (if_bnx.c:816-822). * * A faulty or malicious NIC (firmware compromise, PCIe DMA attack, * silicon erratum) that writes bge_len > 2050 into the return-ring BD * makes the driver hand the network stack an mbuf describing up to * 65531 bytes inside a 2048-byte cluster: * * - ether_input (sys/net/if_ethersubr.c:1512) runs ETHER_BPF_MTAP() * on it => the bpf(4) tap copies up to ~63.5 KB of kernel heap * PAST the cluster out to the capturing socket (kernel heap info * disclosure); * - IP-stack header validation and socket copies read the same OOB * range (further leak / fault when the walk crosses an unmapped * page => panic). * * bge_len < ETHER_HDR_LEN + ETHER_CRC_LEN (18) yields a negative * m_len which DragonFly's ether_input discards at * sys/net/if_ethersubr.c:1499-1503 (`m_len < sizeof(ether_header)') * => benign drop (no underflow panic on this path โ unlike the bce * sibling DF-3604, where the length is unsigned). * * Hardware-layer bounds that a *healthy* NIC enforces (and which this * bug removes as the last line of defense): * - std producer BD len is 2046 (if_bnx.c:843,871), * - MAC max RX frame BGE_RX_MTU = mtu+14+4+4 = 1522 (if_bnx.c:3620), * - std RCB max frame 1536 for 57765+ (if_bnx.c:1348-1349). * * On real hardware the reproduction is: * 1. Attach a BCM5717/5719/5720/5778x based NIC (bnx0). * 2. Have the device DMA a return-ring BD with bge_len = 65535 and * clear error flags (modified firmware / malicious peripheral / * erratum). * 3. `tcpdump -i bnx0 -w out.pcap` (or any bpf listener) captures * up to 65531 bytes per frame => adjacent kernel heap disclosed. * * The audit QEMU guest has virtio-net only (run.log: NO_BROADCOM_ * DEVICE); the bnx attach path is unreachable there, so this trigger * CANNOT be exercised on it. See VERDICT.md for the source-level * proof and the guest evidence. */ #include <sys/types.h> #include <stdio.h> int main(void) { fprintf(stderr, "DF-3639: this trigger requires bnx(4) hardware " "(BCM5717/5718/5719/5720/577xx).\n" "On such a system: configure the NIC, force the device to write\n" "bge_len > 2050 (or < 18) into an RX return-ring BD, then capture\n" "the handed-up frame (tcpdump -i bnx0 -w out.pcap) and verify the\n" "captured frame length exceeds MCLBYTES - ETHER_ALIGN (2046).\n"); return 0; } |