5 #include <dispatch/dispatch.h>
9 #include "darwintest_defaults.h"
10 #include <darwintest_multiprocess.h>
11 #include <darwintest_utils.h>
13 #define T_LOG_VERBOSE(...)
15 #ifndef T_MAYFAIL_WITH_REASON
16 #define T_MAYFAIL_WITH_REASON(x) T_MAYFAIL
20 #define STACK_LOCATIONS 16
22 #define STACK_LOCATIONS 8
25 static const int attempts
= 128, attempt_rounds
= 3;
28 thread_routine(void *loc
)
31 *(uintptr_t*)loc
= (uintptr_t)&foo
;
36 pointer_compare(const void *ap
, const void *bp
)
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;
43 typedef struct shmem_s
{
44 _Atomic
int ctr
, done
;
45 uintptr_t addr_array
[attempts
];
49 test_shmem_open(const char* shmem_name
, int creatflags
)
51 int fd
= open(shmem_name
, O_RDWR
| creatflags
, 0600);
52 T_QUIET
; T_ASSERT_POSIX_SUCCESS(fd
, "open temp file");
54 T_QUIET
; T_ASSERT_POSIX_SUCCESS(ftruncate(fd
,
55 sizeof(struct shmem_s
)), "resize temp file");
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");
65 test_shmem_start(shmem_t shmem
)
67 int idx
= atomic_fetch_add(&shmem
->ctr
, 1);
68 return &shmem
->addr_array
[idx
];
72 test_shmem_end(shmem_t shmem
)
74 atomic_fetch_add(&shmem
->done
, 1);
77 T_HELPER_DECL(wq_stack_aslr_helper
,
78 "Confirm that workqueue stacks are ASLRed (Helper)")
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
);
87 test_shmem_end(shmem
);
90 T_HELPER_DECL(pthread_stack_aslr_helper
,
91 "Confirm that stacks are ASLRed (Helper)")
93 shmem_t shmem
= test_shmem_open(argv
[0], 0);
94 uintptr_t *addr
= test_shmem_start(shmem
);
96 int ret
= pthread_create(&th
, NULL
, thread_routine
, addr
);
98 ret
= pthread_join(th
, NULL
);
100 test_shmem_end(shmem
);
104 test_stack_aslr(bool workqueue_thread
)
106 const char *tmpdir
= dt_tmpdir();
108 asprintf(&tmp
, "%s/pthread_stack_aslr_XXXXX", tmpdir
);
109 T_QUIET
; T_ASSERT_NOTNULL(mkdtemp(tmp
), "mkdtemp");
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
;
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;
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
),
128 signal(SIGCHLD
, SIG_IGN
);
130 int attempt_round
= attempt_rounds
;
132 bzero(shmem
, sizeof(struct shmem_s
));
134 for (int i
= 0; i
< attempts
; i
++) {
136 asprintf(&t
, "%s/%zd", tmp
, i
);
137 T_QUIET
; T_ASSERT_POSIX_SUCCESS(mkdir(t
, 0700), "mkdir");
138 setenv("BATS_TMP_DIR", t
, 1); // hack to workaround rdar://33443485
140 helpers
[helper_idx
++] = dt_child_helper_args(helper
, helper_args
);
144 T_QUIET
; T_FAIL("Helper should complete in <.1s");
148 } while (shmem
->done
<= i
);
150 setenv("BATS_TMP_DIR", tmpdir
, 1);
152 qsort(addr_array
, attempts
, sizeof(uintptr_t), pointer_compare
);
153 T_LOG("Stack address range: %p - %p (+%lx)", (void*)addr_array
[0],
154 (void*)addr_array
[attempts
-1],
155 addr_array
[attempts
-1] - addr_array
[0]);
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
]) {
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
;
172 T_QUIET
; T_EXPECT_POSIX_SUCCESS(unlink(shmem_name
), "unlink temp file");
175 dt_run_helpers(helpers
, helper_idx
, 5);
178 T_DECL(pthread_stack_aslr
, "Confirm that stacks are ASLRed",
179 T_META_CHECK_LEAKS(NO
), T_META_ALL_VALID_ARCHS(YES
))
181 test_stack_aslr(false);
184 T_DECL(wq_stack_aslr
, "Confirm that workqueue stacks are ASLRed",
185 T_META_CHECK_LEAKS(NO
), T_META_ALL_VALID_ARCHS(YES
))
187 test_stack_aslr(true);