]>
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> | |
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 | } |