xref: /xnu-10002.41.9/tests/fd_aio_fsync_uaf.c (revision 699cd48037512bf4380799317ca44ca453c82f57)
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)25 attempt(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