DF-1124 / harness.c
/* * DF-1124 userspace harness — iwn5000_rx_calib_results signed-int underflow + * unbounded heap-copy primitive. * * The kernel bug (sys/dev/netif/iwn/if_iwn.c:3364-3405): * len = (le32toh(desc->len) & 0x3fff) - 4; * - signed int. If (desc->len & 0x3fff) < 4, len underflows to a huge * negative; kmalloc(len) promotes to size_t -> huge alloc -> ENOMEM * (caught at :3396) -- benign for tiny masked lens. * - But if firmware reports e.g. masked len = 16380, len becomes 16376; * kmalloc(16376) succeeds, then `memcpy(buf, calib, len)` at :3405 reads * 16376 bytes starting at `calib = desc + 1` which lives inside a 4 KiB * RX mbuf cluster -> reads up to ~12 KiB past the mbuf -> kernel OOB read * (info leak / panic). The calibcmd buffer is later replayed to runtime * firmware via iwn5000_send_calibration -> data exfiltration path. * * Reachability: requires Intel WiFi (iwn) adapter + malicious/compromised * firmware or DMA injection. Not present on this audit guest. * * Build: cc -O2 -o harness harness.c * Run: ./harness * Expected: demonstrates the underflow AND the OOB read length. */ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #define IWN_RBUF_SIZE 4096 /* RX mbuf cluster size (4 KiB) */ #define IWN_CALIB_OFF 8 /* calib = desc + 1, desc is 8 bytes */ /* mimic iwn_rx_desc tail */ struct desc { uint32_t len; uint8_t pad[4]; }; static void test(unsigned masked_len) { /* desc->len already on the wire; we mask in the handler */ int len = (int)(masked_len & 0x3fff) - 4; printf("masked desc->len & 0x3fff = %u\n", masked_len & 0x3fff); printf("len = masked - 4 = %d\n", len); if (len < 0) { printf(" -> signed UNDERFLOW. kmalloc((size_t)%d) = kmalloc(%zu)\n", len, (size_t)len); printf(" -> kmalloc fails (ENOMEM), no further damage on this path.\n\n"); return; } /* positive len: is it within the RX mbuf cluster? */ int avail = IWN_RBUF_SIZE - IWN_CALIB_OFF; printf(" memcpy(calibcmd.buf, calib, %d) from offset %d in %d-byte mbuf\n", len, IWN_CALIB_OFF, IWN_RBUF_SIZE); if (len > avail) { printf(" -> OOB READ of %d bytes past mbuf cluster boundary " "(info leak / panic source)\n\n", len - avail); } else { printf(" -> within mbuf, benign.\n\n"); } } int main(void) { printf("=== DF-1124 iwn5000_rx_calib_results primitive demo ===\n\n"); printf("[case 1] firmware reports masked len = 0 (underflow)\n"); test(0); printf("[case 2] firmware reports masked len = 3 (underflow)\n"); test(3); printf("[case 3] firmware reports masked len = 16380 (OOB read)\n"); test(16380); printf("[case 4] firmware reports masked len = 200 (benign)\n"); test(200); printf("Conclusion: no clamp on len -> both underflow and over-read are\n"); printf("reachable from a buggy/compromised firmware or DMA injection.\n"); return 0; } |