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 9int test_func(); 10void catch_segv(int); 11jmp_buf resume; 12 13#define func_len 256 14 15#define ALT_STK_SIZE (MINSIGSTKSZ + pagesize) 16 17#if __i386__ 18typedef unsigned int psint_t; 19#endif 20#if __x86_64__ 21typedef unsigned long long psint_t; 22#endif 23 24int 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 45int expected[4] = { 46#if NXDATA32TESTNONX 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#elif __i386__ 52 FAIL, /* execute from heap */ 53 SUCCEED, /* exeucte from heap with PROT_EXEC */ 54 FAIL, /* execute from stack */ 55 SUCCEED, /* exeucte from stack with PROT_EXEC */ 56#endif 57#if __x86_64__ 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 66int 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 122restart: 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 202int 203test_func() 204{ 205 return 42; 206} 207 208 209void 210catch_segv(int sig) 211{ 212 msg("got sig %d\n\n", sig); 213 longjmp(resume, FAIL); 214} 215