]> git.saurik.com Git - apple/xnu.git/blob - tools/tests/xnu_quick_test/helpers/data_exec.c
xnu-1504.15.3.tar.gz
[apple/xnu.git] / tools / tests / xnu_quick_test / helpers / data_exec.c
1 #include <stdio.h>
2 #include <strings.h>
3 #include <stdlib.h>
4 #include <unistd.h>
5 #include <signal.h>
6 #include <setjmp.h>
7 #include <sys/mman.h>
8
9 int test_func();
10 void catch_segv(int);
11 jmp_buf resume;
12
13 #define func_len 256
14
15 #define ALT_STK_SIZE (MINSIGSTKSZ + pagesize)
16
17 #if __i386__ || __ppc__
18 typedef unsigned int psint_t;
19 #endif
20 #if __x86_64__ || __ppc64__
21 typedef unsigned long long psint_t;
22 #endif
23
24 int verbose = 0;
25
26 #define msg(...) do { if (verbose) printf(__VA_ARGS__); } while (0);
27
28 /*
29 * Test whether the architecture allows execution from the stack and heap data areas. What's
30 * allowed varies by architecture due to backwards compatibility. We also run a separate test
31 * where we turn on PROT_EXEC explicitly which should always allow execution to take place.
32 *
33 * The "expected" array tells us what the result of each test should be based on the architecture.
34 * The code assumes the test numbers in the macros below are consecutive starting from 0.
35 */
36
37 #define HEAP_TEST 0
38 #define HEAP_PROT_EXEC 1
39 #define STACK_TEST 2
40 #define STACK_PROT_EXEC 3
41
42 #define SUCCEED 1
43 #define FAIL -1 /* can't use 0 since setjmp uses that */
44
45 int expected[4] = {
46 #if __i386__
47 SUCCEED, /* execute from heap */
48 SUCCEED, /* exeucte from heap with PROT_EXEC */
49 FAIL, /* execute from stack */
50 SUCCEED, /* exeucte from stack with PROT_EXEC */
51 #endif
52 #if __x86_64__
53 FAIL, /* execute from heap */
54 SUCCEED, /* exeucte from heap with PROT_EXEC */
55 FAIL, /* execute from stack */
56 SUCCEED, /* exeucte from stack with PROT_EXEC */
57 #endif
58 #if __ppc__
59 SUCCEED, /* execute from heap */
60 SUCCEED, /* exeucte from heap with PROT_EXEC */
61 SUCCEED, /* execute from stack */
62 SUCCEED, /* exeucte from stack with PROT_EXEC */
63 #endif
64 #if __ppc64__
65 FAIL, /* execute from heap */
66 SUCCEED, /* exeucte from heap with PROT_EXEC */
67 FAIL, /* execute from stack */
68 SUCCEED, /* exeucte from stack with PROT_EXEC */
69 #endif
70 };
71
72
73 main(int argc, char *argv[])
74 {
75 int (*func)();
76 int result, test;
77 char buf[func_len + 4];
78 psint_t base;
79 unsigned int len;
80 psint_t pagesize;
81 size_t count;
82 stack_t sigstk;
83 struct sigaction sigact;
84 char *cmd_name;
85 int c;
86
87 cmd_name = argv[0];
88
89 while ((c = getopt(argc, argv, "v")) != -1) {
90 switch (c) {
91 case 'v':
92 verbose = 1;
93 break;
94
95 case '?':
96 default:
97 fprintf(stderr, "usage: data_exec [-v]\n");
98 exit(1);
99 }
100 }
101
102 pagesize = getpagesize();
103
104 sigstk.ss_sp = malloc(ALT_STK_SIZE);
105 sigstk.ss_size = ALT_STK_SIZE;
106 sigstk.ss_flags = 0;
107
108 if (sigaltstack(&sigstk, NULL) < 0) {
109 perror("sigaltstack");
110 exit(1);
111 }
112
113 sigact.sa_handler = catch_segv;
114 sigact.sa_flags = SA_ONSTACK;
115 sigemptyset(&sigact.sa_mask);
116
117 if (sigaction(SIGSEGV, &sigact, NULL) == -1) {
118 perror("sigaction SIGSEGV");
119 exit(1);
120 }
121
122 if (sigaction(SIGBUS, &sigact, NULL) == -1) {
123 perror("sigaction SIGBUS");
124 exit(1);
125 }
126
127 test = HEAP_TEST;
128
129 restart:
130
131 if ((result = setjmp(resume)) != 0) {
132 if (result != expected[test]) {
133 printf("%s: test %d failed, expected %d, got %d\n", cmd_name, test, expected[test], result);
134 exit(2);
135 }
136
137 test++;
138 goto restart;
139 }
140
141 switch (test) {
142 case HEAP_TEST:
143 msg("attempting to execute from malloc'ed area..\n");
144
145 func = (void *)malloc(func_len);
146
147 func = (void *)((char *)func + ((psint_t)test_func & 0x3));
148
149 bcopy(test_func, func, func_len);
150
151 result = (*func)();
152 msg("execution suceeded, result is %d\n\n", result);
153 longjmp(resume, SUCCEED);
154
155 case HEAP_PROT_EXEC:
156 msg("attempting to execute from malloc'ed area with PROT_EXEC..\n");
157
158 func = (void *)malloc(func_len);
159
160 func = (void *)((char *)func + ((psint_t)test_func & 0x3));
161 bcopy(test_func, func, func_len);
162
163 base = (psint_t)func & ~(pagesize - 1);
164 len = func_len + (psint_t)func - base;
165
166 if(mprotect((void *)base, len, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
167 perror("mprotect of stack");
168 exit(1);
169 }
170
171 result = (*func)();
172 msg("execution suceeded, result is %d\n\n", result);
173 longjmp(resume, SUCCEED);
174
175 case STACK_TEST:
176 msg("attempting to execute from stack...\n");
177
178 func = (void *)(buf + ((psint_t)test_func & 0x3));
179 bcopy(test_func, func, func_len);
180
181 result = (*func)();
182 msg("stack execution suceeded, result from stack exec is %d\n\n", result);
183 longjmp(resume, SUCCEED);
184
185 case STACK_PROT_EXEC:
186 msg("attempting to execute from stack with PROT_EXEC...\n");
187
188 func = (void *)(buf + ((psint_t)test_func & 0x3));
189 bcopy(test_func, func, func_len);
190
191 base = (psint_t)func & ~(pagesize - 1);
192 len = func_len + (psint_t)func - base;
193
194 if(mprotect((void *)base, len, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
195 perror("mprotect of stack");
196 exit(1);
197 }
198
199 result = (*func)();
200 msg("stack execution suceeded, result from stack exec is %d\n", result);
201 longjmp(resume, SUCCEED);
202 }
203
204 msg("All tests passed.\n");
205 exit(0);
206 }
207
208
209 int
210 test_func()
211 {
212 return 42;
213 }
214
215
216 void
217 catch_segv(int sig)
218 {
219 msg("got sig %d\n\n", sig);
220 longjmp(resume, FAIL);
221 }