]> git.saurik.com Git - apple/libpthread.git/blob - tests/stack_aslr.c
libpthread-218.30.1.tar.gz
[apple/libpthread.git] / tests / stack_aslr.c
1 #include <assert.h>
2 #include <stdlib.h>
3 #include <pthread.h>
4 #include <unistd.h>
5 #include <dispatch/dispatch.h>
6 #include <sys/mman.h>
7
8 #include <darwintest.h>
9
10 #define T_LOG_VERBOSE(...)
11
12 #ifdef __LP64__
13 #define STACK_LOCATIONS 16
14 #else
15 #define STACK_LOCATIONS 8
16 #endif
17
18 static void*
19 thread_routine(void *loc)
20 {
21 int foo;
22 *(uintptr_t*)loc = (uintptr_t)&foo;
23 return NULL;
24 }
25
26 static int
27 pointer_compare(const void *ap, const void *bp)
28 {
29 uintptr_t a = *(const uintptr_t*)ap;
30 uintptr_t b = *(const uintptr_t*)bp;
31 return a > b ? 1 : a < b ? -1 : 0;
32 }
33
34 static void
35 test_stack_aslr(bool workqueue_thread)
36 {
37 const int attempts = 128;
38 int attempt_round = 0;
39
40 uintptr_t *addr_array = mmap(NULL, sizeof(uintptr_t) * attempts,
41 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANON, -1, 0);
42 T_QUIET; T_ASSERT_NOTNULL(addr_array, NULL);
43
44 again:
45 bzero(addr_array, sizeof(uintptr_t) * attempts);
46
47 for (int i = 0; i < attempts; i++) {
48 pid_t pid = fork();
49 T_QUIET; T_ASSERT_POSIX_SUCCESS(pid, "[%d] fork()", i);
50
51 if (pid) { // parent
52 pid = waitpid(pid, NULL, 0);
53 T_QUIET; T_ASSERT_POSIX_SUCCESS(pid, "[%d] waitpid()", i);
54 } else if (workqueue_thread) { // child
55 dispatch_async(dispatch_get_global_queue(0,0), ^{
56 int foo;
57 addr_array[i] = (uintptr_t)&foo;
58 exit(0);
59 });
60 while (true) sleep(1);
61 } else { // child
62 pthread_t th;
63 int ret = pthread_create(&th, NULL, thread_routine, &addr_array[i]);
64 assert(ret == 0);
65 ret = pthread_join(th, NULL);
66 assert(ret == 0);
67 exit(0);
68 }
69 }
70
71 qsort(addr_array, attempts, sizeof(uintptr_t), pointer_compare);
72
73 T_LOG("Stack address range: %p - %p (+%lx)", (void*)addr_array[0], (void*)addr_array[attempts-1],
74 addr_array[attempts-1] - addr_array[0]);
75
76 int unique_values = 0;
77 T_LOG_VERBOSE("[%p]", (void*)addr_array[0]);
78 for (int i = 1; i < attempts; i++) {
79 T_LOG_VERBOSE("[%p]", (void*)addr_array[i]);
80 if (addr_array[i-1] != addr_array[i]) {
81 unique_values++;
82 }
83 }
84
85 if (attempt_round < 3) T_MAYFAIL;
86 T_EXPECT_GE(unique_values, STACK_LOCATIONS, "Should have more than %d unique stack locations", STACK_LOCATIONS);
87 if (attempt_round++ < 3 && unique_values < STACK_LOCATIONS) goto again;
88 }
89
90 T_DECL(pthread_stack_aslr, "Confirm that stacks are ASLRed", T_META_CHECK_LEAKS(NO),
91 T_META_ALL_VALID_ARCHS(YES))
92 {
93 test_stack_aslr(false);
94 }
95
96 T_DECL(wq_stack_aslr, "Confirm that workqueue stacks are ASLRed", T_META_CHECK_LEAKS(NO),
97 T_META_ALL_VALID_ARCHS(YES))
98 {
99 test_stack_aslr(true);
100 }