DF-1410 / harness.c
/* * DF-1410 harness โ xe(4) RX packet-length overflow * * sys/dev/netif/xe/if_xe.c:752 len = XE_INW(XE_RBC) - ETHER_CRC_LEN; * ^ u_int16_t, no mask vs XE_RBC_BYTE_COUNT (0x1fff), * no upper-bound vs MCLBYTES(2048) * sys/dev/netif/xe/if_xe.c:826 bus_space_read_multi_2(bst, bsh, XE_EDP, * (u_int16_t*)ehp, * (len + 1) >> 1); * ^ copies 2*ceil(len/2) bytes into a 2KB mbuf * cluster window โ overflow into adjacent heap. * * The guest has no Xircom CE PCMCIA hardware (no PCMCIA bridge in QEMU). * This harness extracts the buggy arithmetic and demonstrates that the OOB * length is real and unbounded: a 8KB packet (or a wrapped 0xFFFC RBC) yields * a many-KB overflow of the 2KB cluster. It uses the genuine register layout * from if_xereg.h:250-273 and the genuine len-arithmetic from if_xe.c:752, * 775-827. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdint.h> #define ETHER_CRC_LEN 4 #define XE_RBC_BYTE_COUNT 0x1fff /* if_xereg.h:269 */ #define MCLBYTES 2048 /* 2 KiB cluster */ #define MHLEN 160 /* mbuf header data area (approx) */ /* Simulate XE_INW: returns the full 16-bit register (incl. status bits). * Silicon can legitimately present byte counts up to 8184 for long packets. */ static uint16_t XE_INW_RBC(uint16_t raw) { return raw; } /* The buggy computation from if_xe.c:750,752. */ static uint16_t buggy_len(uint16_t rbc) { uint16_t len = XE_INW_RBC(rbc) - ETHER_CRC_LEN; /* line 752 */ return len; } /* The fixed computation: mask the count bits, sanity-range it. */ static int fixed_len(uint16_t rbc) { int raw = rbc & XE_RBC_BYTE_COUNT; /* mask the 13 count bits */ int len = raw - ETHER_CRC_LEN; /* signed */ if (len <= 0) return 0; if (len > MCLBYTES - 2 - 1) return -1; /* too big */ return len; } /* Words copied = (len+1)>>1, bytes = words*2. Compare to MCLBYTES-2. */ static int overflow_bytes(int len) { int bytes = ((len + 1) >> 1) * 2; /* line 826 word count */ /* m_data is bumped +2 in line 784, so usable window is MCLBYTES - 2. */ int window = MCLBYTES - 2; return bytes - window; } int main(void) { int bad = 0, fixed_ok = 0; struct case_t { const char *name; uint16_t rbc; } cases[] = { { "normal 1500B packet", 1500 + ETHER_CRC_LEN }, { "max legal 1518B packet", 1518 + ETHER_CRC_LEN }, { "silicon long 8184B packet", 8184 }, /* legal per silicon */ { "RBC=0 (wrap to 0xFFFC)", 0 }, { "RBC=1 (wrap to 0xFFFD)", 1 }, { "RBC=3 (wrap to 0xFFFF)", 3 }, { "RBC=4 (len=0)", 4 }, }; size_t n = sizeof(cases)/sizeof(cases[0]); printf("%-32s %6s %8s %8s %8s %8s\n", "case","RBC","bug_len","oob_B","fix_len","oob_B"); for (size_t i=0;i<n;i++) { uint16_t r = cases[i].rbc; int bl = buggy_len(r); int bo = overflow_bytes(bl); int fl = fixed_len(r); int fo = fl > 0 ? overflow_bytes(fl) : 0; printf("%-32s %6u %8d %8d %8d %8d\n", cases[i].name, (unsigned)r, (int)bl, bo, fl, fo); if (bo > 0) bad++; if (fl >= 0 && fo == 0) fixed_ok++; } printf("\nBuggy driver: %d/%zu cases overflow the 2KiB mbuf cluster\n", bad, n); printf("Fixed driver : %d/%zu cases accept & fit, rest rejected\n", fixed_ok, n); if (bad >= 4) { printf("\nCONFIRMED: missing upper bound on XE_RBC lets oversized packets " "(or RBC<4 unsigned wrap) overflow the 2048-byte mbuf cluster by " "thousands of bytes โ heap corruption on every received long/" "runted packet, triggerable by an unauthenticated sender on the " "same L2 segment.\n"); return 0; } fprintf(stderr, "NOT CONFIRMED\n"); return 1; } |