]> git.saurik.com Git - apple/libpthread.git/blame - tests/stack_aslr.c
libpthread-330.201.1.tar.gz
[apple/libpthread.git] / tests / stack_aslr.c
CommitLineData
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
25static const int attempts = 128, attempt_rounds = 3;
26
2546420a
A
27static void*
28thread_routine(void *loc)
29{
30 int foo;
31 *(uintptr_t*)loc = (uintptr_t)&foo;
32 return NULL;
33}
34
35static int
36pointer_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
43typedef struct shmem_s {
44 _Atomic int ctr, done;
45 uintptr_t addr_array[attempts];
46} *shmem_t;
47
48static shmem_t
49test_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
64static uintptr_t*
65test_shmem_start(shmem_t shmem)
66{
67 int idx = atomic_fetch_add(&shmem->ctr, 1);
68 return &shmem->addr_array[idx];
69}
70
2546420a 71static void
a0619f9c
A
72test_shmem_end(shmem_t shmem)
73{
74 atomic_fetch_add(&shmem->done, 1);
75}
76
77T_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
90T_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
103static void
104test_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 131again:
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
171timeout:
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
178T_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
184T_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}