]>
Commit | Line | Data |
---|---|---|
b0d623f7 A |
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 | ||
6d2010ae | 17 | #if __i386__ |
b0d623f7 A |
18 | typedef unsigned int psint_t; |
19 | #endif | |
6d2010ae | 20 | #if __x86_64__ |
b0d623f7 A |
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] = { | |
6d2010ae | 46 | #if NXDATA32TESTNONX |
b0d623f7 A |
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 */ | |
6d2010ae A |
51 | #elif __i386__ |
52 | FAIL, /* execute from heap */ | |
b0d623f7 A |
53 | SUCCEED, /* exeucte from heap with PROT_EXEC */ |
54 | FAIL, /* execute from stack */ | |
55 | SUCCEED, /* exeucte from stack with PROT_EXEC */ | |
56 | #endif | |
6d2010ae | 57 | #if __x86_64__ |
b0d623f7 A |
58 | FAIL, /* execute from heap */ |
59 | SUCCEED, /* exeucte from heap with PROT_EXEC */ | |
60 | FAIL, /* execute from stack */ | |
61 | SUCCEED, /* exeucte from stack with PROT_EXEC */ | |
62 | #endif | |
63 | }; | |
64 | ||
65 | ||
66 | main(int argc, char *argv[]) | |
67 | { | |
68 | int (*func)(); | |
69 | int result, test; | |
70 | char buf[func_len + 4]; | |
71 | psint_t base; | |
72 | unsigned int len; | |
73 | psint_t pagesize; | |
74 | size_t count; | |
75 | stack_t sigstk; | |
76 | struct sigaction sigact; | |
77 | char *cmd_name; | |
78 | int c; | |
79 | ||
80 | cmd_name = argv[0]; | |
81 | ||
82 | while ((c = getopt(argc, argv, "v")) != -1) { | |
83 | switch (c) { | |
84 | case 'v': | |
85 | verbose = 1; | |
86 | break; | |
87 | ||
88 | case '?': | |
89 | default: | |
90 | fprintf(stderr, "usage: data_exec [-v]\n"); | |
91 | exit(1); | |
92 | } | |
93 | } | |
94 | ||
95 | pagesize = getpagesize(); | |
96 | ||
97 | sigstk.ss_sp = malloc(ALT_STK_SIZE); | |
98 | sigstk.ss_size = ALT_STK_SIZE; | |
99 | sigstk.ss_flags = 0; | |
100 | ||
101 | if (sigaltstack(&sigstk, NULL) < 0) { | |
102 | perror("sigaltstack"); | |
103 | exit(1); | |
104 | } | |
105 | ||
106 | sigact.sa_handler = catch_segv; | |
107 | sigact.sa_flags = SA_ONSTACK; | |
108 | sigemptyset(&sigact.sa_mask); | |
109 | ||
110 | if (sigaction(SIGSEGV, &sigact, NULL) == -1) { | |
111 | perror("sigaction SIGSEGV"); | |
112 | exit(1); | |
113 | } | |
114 | ||
115 | if (sigaction(SIGBUS, &sigact, NULL) == -1) { | |
116 | perror("sigaction SIGBUS"); | |
117 | exit(1); | |
118 | } | |
119 | ||
120 | test = HEAP_TEST; | |
121 | ||
122 | restart: | |
123 | ||
124 | if ((result = setjmp(resume)) != 0) { | |
125 | if (result != expected[test]) { | |
126 | printf("%s: test %d failed, expected %d, got %d\n", cmd_name, test, expected[test], result); | |
127 | exit(2); | |
128 | } | |
129 | ||
130 | test++; | |
131 | goto restart; | |
132 | } | |
133 | ||
134 | switch (test) { | |
135 | case HEAP_TEST: | |
136 | msg("attempting to execute from malloc'ed area..\n"); | |
137 | ||
138 | func = (void *)malloc(func_len); | |
139 | ||
140 | func = (void *)((char *)func + ((psint_t)test_func & 0x3)); | |
141 | ||
142 | bcopy(test_func, func, func_len); | |
143 | ||
144 | result = (*func)(); | |
145 | msg("execution suceeded, result is %d\n\n", result); | |
146 | longjmp(resume, SUCCEED); | |
147 | ||
148 | case HEAP_PROT_EXEC: | |
149 | msg("attempting to execute from malloc'ed area with PROT_EXEC..\n"); | |
150 | ||
151 | func = (void *)malloc(func_len); | |
152 | ||
153 | func = (void *)((char *)func + ((psint_t)test_func & 0x3)); | |
154 | bcopy(test_func, func, func_len); | |
155 | ||
156 | base = (psint_t)func & ~(pagesize - 1); | |
157 | len = func_len + (psint_t)func - base; | |
158 | ||
159 | if(mprotect((void *)base, len, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { | |
160 | perror("mprotect of stack"); | |
161 | exit(1); | |
162 | } | |
163 | ||
164 | result = (*func)(); | |
165 | msg("execution suceeded, result is %d\n\n", result); | |
166 | longjmp(resume, SUCCEED); | |
167 | ||
168 | case STACK_TEST: | |
169 | msg("attempting to execute from stack...\n"); | |
170 | ||
171 | func = (void *)(buf + ((psint_t)test_func & 0x3)); | |
172 | bcopy(test_func, func, func_len); | |
173 | ||
174 | result = (*func)(); | |
175 | msg("stack execution suceeded, result from stack exec is %d\n\n", result); | |
176 | longjmp(resume, SUCCEED); | |
177 | ||
178 | case STACK_PROT_EXEC: | |
179 | msg("attempting to execute from stack with PROT_EXEC...\n"); | |
180 | ||
181 | func = (void *)(buf + ((psint_t)test_func & 0x3)); | |
182 | bcopy(test_func, func, func_len); | |
183 | ||
184 | base = (psint_t)func & ~(pagesize - 1); | |
185 | len = func_len + (psint_t)func - base; | |
186 | ||
187 | if(mprotect((void *)base, len, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { | |
188 | perror("mprotect of stack"); | |
189 | exit(1); | |
190 | } | |
191 | ||
192 | result = (*func)(); | |
193 | msg("stack execution suceeded, result from stack exec is %d\n", result); | |
194 | longjmp(resume, SUCCEED); | |
195 | } | |
196 | ||
197 | msg("All tests passed.\n"); | |
198 | exit(0); | |
199 | } | |
200 | ||
201 | ||
202 | int | |
203 | test_func() | |
204 | { | |
205 | return 42; | |
206 | } | |
207 | ||
208 | ||
209 | void | |
210 | catch_segv(int sig) | |
211 | { | |
212 | msg("got sig %d\n\n", sig); | |
213 | longjmp(resume, FAIL); | |
214 | } |