]>
Commit | Line | Data |
---|---|---|
2546420a A |
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> | |
a0619f9c | 7 | #include <stdatomic.h> |
2546420a | 8 | |
a0619f9c A |
9 | #include "darwintest_defaults.h" |
10 | #include <darwintest_multiprocess.h> | |
11 | #include <darwintest_utils.h> | |
2546420a A |
12 | |
13 | #define T_LOG_VERBOSE(...) | |
14 | ||
a0619f9c A |
15 | #ifndef T_MAYFAIL_WITH_REASON |
16 | #define T_MAYFAIL_WITH_REASON(x) T_MAYFAIL | |
17 | #endif | |
18 | ||
2546420a A |
19 | #ifdef __LP64__ |
20 | #define STACK_LOCATIONS 16 | |
21 | #else | |
22 | #define STACK_LOCATIONS 8 | |
23 | #endif | |
24 | ||
a0619f9c A |
25 | static const int attempts = 128, attempt_rounds = 3; |
26 | ||
2546420a A |
27 | static void* |
28 | thread_routine(void *loc) | |
29 | { | |
30 | int foo; | |
31 | *(uintptr_t*)loc = (uintptr_t)&foo; | |
32 | return NULL; | |
33 | } | |
34 | ||
35 | static int | |
36 | pointer_compare(const void *ap, const void *bp) | |
37 | { | |
38 | uintptr_t a = *(const uintptr_t*)ap; | |
39 | uintptr_t b = *(const uintptr_t*)bp; | |
40 | return a > b ? 1 : a < b ? -1 : 0; | |
41 | } | |
42 | ||
a0619f9c A |
43 | typedef struct shmem_s { |
44 | _Atomic int ctr, done; | |
45 | uintptr_t addr_array[attempts]; | |
46 | } *shmem_t; | |
47 | ||
48 | static shmem_t | |
49 | test_shmem_open(const char* shmem_name, int creatflags) | |
50 | { | |
51 | int fd = open(shmem_name, O_RDWR | creatflags, 0600); | |
52 | T_QUIET; T_ASSERT_POSIX_SUCCESS(fd, "open temp file"); | |
53 | if (creatflags) { | |
54 | T_QUIET; T_ASSERT_POSIX_SUCCESS(ftruncate(fd, | |
55 | sizeof(struct shmem_s)), "resize temp file"); | |
56 | } | |
57 | shmem_t shmem = mmap(NULL, sizeof(struct shmem_s), | |
58 | PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); | |
59 | T_QUIET; T_ASSERT_NOTNULL(shmem, "mmap shmem"); | |
60 | T_QUIET; T_ASSERT_POSIX_SUCCESS(close(fd), "close temp file"); | |
61 | return shmem; | |
62 | } | |
63 | ||
64 | static uintptr_t* | |
65 | test_shmem_start(shmem_t shmem) | |
66 | { | |
67 | int idx = atomic_fetch_add(&shmem->ctr, 1); | |
68 | return &shmem->addr_array[idx]; | |
69 | } | |
70 | ||
2546420a | 71 | static void |
a0619f9c A |
72 | test_shmem_end(shmem_t shmem) |
73 | { | |
74 | atomic_fetch_add(&shmem->done, 1); | |
75 | } | |
76 | ||
77 | T_HELPER_DECL(wq_stack_aslr_helper, | |
78 | "Confirm that workqueue stacks are ASLRed (Helper)") | |
2546420a | 79 | { |
a0619f9c A |
80 | shmem_t shmem = test_shmem_open(argv[0], 0); |
81 | uintptr_t *addr = test_shmem_start(shmem); | |
82 | dispatch_group_t g = dispatch_group_create(); | |
83 | dispatch_group_async_f(g, dispatch_get_global_queue(0,0), addr, | |
84 | (dispatch_function_t)thread_routine); | |
85 | dispatch_group_wait(g, DISPATCH_TIME_FOREVER); | |
86 | dispatch_release(g); | |
87 | test_shmem_end(shmem); | |
88 | } | |
2546420a | 89 | |
a0619f9c A |
90 | T_HELPER_DECL(pthread_stack_aslr_helper, |
91 | "Confirm that stacks are ASLRed (Helper)") | |
92 | { | |
93 | shmem_t shmem = test_shmem_open(argv[0], 0); | |
94 | uintptr_t *addr = test_shmem_start(shmem); | |
95 | pthread_t th; | |
96 | int ret = pthread_create(&th, NULL, thread_routine, addr); | |
97 | assert(ret == 0); | |
98 | ret = pthread_join(th, NULL); | |
99 | assert(ret == 0); | |
100 | test_shmem_end(shmem); | |
101 | } | |
2546420a | 102 | |
a0619f9c A |
103 | static void |
104 | test_stack_aslr(bool workqueue_thread) | |
105 | { | |
106 | const char *tmpdir = dt_tmpdir(); | |
107 | char *tmp; | |
108 | asprintf(&tmp, "%s/pthread_stack_aslr_XXXXX", tmpdir); | |
109 | T_QUIET; T_ASSERT_NOTNULL(mkdtemp(tmp), "mkdtemp"); | |
110 | ||
111 | char *shmem_name; | |
112 | asprintf(&shmem_name, "%s/shmem", tmp); | |
113 | shmem_t shmem = test_shmem_open(shmem_name, O_CREAT|O_EXCL); | |
114 | uintptr_t *addr_array = shmem->addr_array; | |
115 | ||
116 | dt_helper_t helpers[attempts * attempt_rounds]; | |
117 | const char* helper = workqueue_thread ? "wq_stack_aslr_helper" : | |
118 | "pthread_stack_aslr_helper"; | |
119 | char *helper_args[] = {shmem_name, NULL}; | |
120 | size_t helper_idx = 0; | |
121 | ||
122 | struct rlimit l; | |
123 | if (!getrlimit(RLIMIT_NOFILE, &l)) { | |
124 | l.rlim_cur += 3 * attempts * attempt_rounds; // 3 fifos per helper | |
125 | T_QUIET; T_ASSERT_POSIX_SUCCESS(setrlimit(RLIMIT_NOFILE, &l), | |
126 | "setrlimit"); | |
127 | } | |
128 | signal(SIGCHLD, SIG_IGN); | |
129 | ||
130 | int attempt_round = attempt_rounds; | |
2546420a | 131 | again: |
a0619f9c | 132 | bzero(shmem, sizeof(struct shmem_s)); |
2546420a A |
133 | |
134 | for (int i = 0; i < attempts; i++) { | |
a0619f9c | 135 | char *t; |
214d78a2 | 136 | asprintf(&t, "%s/%d", tmp, i); |
a0619f9c A |
137 | T_QUIET; T_ASSERT_POSIX_SUCCESS(mkdir(t, 0700), "mkdir"); |
138 | setenv("BATS_TMP_DIR", t, 1); // hack to workaround rdar://33443485 | |
139 | free(t); | |
140 | helpers[helper_idx++] = dt_child_helper_args(helper, helper_args); | |
141 | int w = 100; | |
142 | do { | |
143 | if (!w--) { | |
144 | T_QUIET; T_FAIL("Helper should complete in <.1s"); | |
145 | goto timeout; | |
146 | } | |
214d78a2 | 147 | usleep(1000 * 100); |
a0619f9c | 148 | } while (shmem->done <= i); |
2546420a | 149 | } |
a0619f9c | 150 | setenv("BATS_TMP_DIR", tmpdir, 1); |
2546420a A |
151 | |
152 | qsort(addr_array, attempts, sizeof(uintptr_t), pointer_compare); | |
a0619f9c A |
153 | T_LOG("Stack address range: %p - %p (+%lx)", (void*)addr_array[0], |
154 | (void*)addr_array[attempts-1], | |
2546420a A |
155 | addr_array[attempts-1] - addr_array[0]); |
156 | ||
157 | int unique_values = 0; | |
158 | T_LOG_VERBOSE("[%p]", (void*)addr_array[0]); | |
159 | for (int i = 1; i < attempts; i++) { | |
160 | T_LOG_VERBOSE("[%p]", (void*)addr_array[i]); | |
161 | if (addr_array[i-1] != addr_array[i]) { | |
162 | unique_values++; | |
163 | } | |
164 | } | |
165 | ||
a0619f9c A |
166 | if (--attempt_round) T_MAYFAIL_WITH_REASON("ASLR"); |
167 | T_EXPECT_GE(unique_values, STACK_LOCATIONS, | |
168 | "Should have more than %d unique stack locations", STACK_LOCATIONS); | |
169 | if (attempt_round && unique_values < STACK_LOCATIONS) goto again; | |
170 | ||
171 | timeout: | |
172 | T_QUIET; T_EXPECT_POSIX_SUCCESS(unlink(shmem_name), "unlink temp file"); | |
173 | free(shmem_name); | |
174 | free(tmp); | |
175 | dt_run_helpers(helpers, helper_idx, 5); | |
2546420a A |
176 | } |
177 | ||
a0619f9c A |
178 | T_DECL(pthread_stack_aslr, "Confirm that stacks are ASLRed", |
179 | T_META_CHECK_LEAKS(NO), T_META_ALL_VALID_ARCHS(YES)) | |
2546420a A |
180 | { |
181 | test_stack_aslr(false); | |
182 | } | |
183 | ||
a0619f9c A |
184 | T_DECL(wq_stack_aslr, "Confirm that workqueue stacks are ASLRed", |
185 | T_META_CHECK_LEAKS(NO), T_META_ALL_VALID_ARCHS(YES)) | |
2546420a A |
186 | { |
187 | test_stack_aslr(true); | |
188 | } |