]> git.saurik.com Git - apple/xnu.git/blobdiff - tools/tests/xnu_quick_test/helpers/data_exec.c
xnu-1456.1.26.tar.gz
[apple/xnu.git] / tools / tests / xnu_quick_test / helpers / data_exec.c
diff --git a/tools/tests/xnu_quick_test/helpers/data_exec.c b/tools/tests/xnu_quick_test/helpers/data_exec.c
new file mode 100644 (file)
index 0000000..f8b353c
--- /dev/null
@@ -0,0 +1,221 @@
+#include <stdio.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/mman.h>
+
+int test_func();
+void   catch_segv(int);
+jmp_buf resume;
+
+#define func_len       256
+
+#define ALT_STK_SIZE   (MINSIGSTKSZ + pagesize)
+
+#if __i386__ || __ppc__
+typedef        unsigned int            psint_t;
+#endif
+#if __x86_64__ || __ppc64__
+typedef unsigned long long     psint_t;
+#endif
+
+int verbose = 0;
+
+#define msg(...)       do { if (verbose) printf(__VA_ARGS__); } while (0);
+
+/*
+ * Test whether the architecture allows execution from the stack and heap data areas.  What's
+ * allowed varies by architecture due to backwards compatibility.  We also run a separate test
+ * where we turn on PROT_EXEC explicitly which should always allow execution to take place.
+ *
+ * The "expected" array tells us what the result of each test should be based on the architecture.
+ * The code assumes the test numbers in the macros below are consecutive starting from 0.
+ */
+
+#define HEAP_TEST      0
+#define HEAP_PROT_EXEC 1
+#define STACK_TEST     2
+#define STACK_PROT_EXEC        3
+
+#define        SUCCEED  1
+#define FAIL   -1      /* can't use 0 since setjmp uses that */
+
+int expected[4] = {
+#if __i386__
+       SUCCEED,                /* execute from heap */
+       SUCCEED,                /* exeucte from heap with PROT_EXEC */
+       FAIL,                   /* execute from stack */
+       SUCCEED,                /* exeucte from stack with PROT_EXEC */
+#endif
+#if __x86_64__
+       FAIL,                   /* execute from heap */
+       SUCCEED,                /* exeucte from heap with PROT_EXEC */
+       FAIL,                   /* execute from stack */
+       SUCCEED,                /* exeucte from stack with PROT_EXEC */
+#endif
+#if __ppc__
+       SUCCEED,                /* execute from heap */
+       SUCCEED,                /* exeucte from heap with PROT_EXEC */
+       SUCCEED,                /* execute from stack */
+       SUCCEED,                /* exeucte from stack with PROT_EXEC */
+#endif
+#if __ppc64__
+       FAIL,                   /* execute from heap */
+       SUCCEED,                /* exeucte from heap with PROT_EXEC */
+       FAIL,                   /* execute from stack */
+       SUCCEED,                /* exeucte from stack with PROT_EXEC */
+#endif
+};
+
+
+main(int argc, char *argv[])
+{
+       int (*func)();
+       int result, test;
+       char buf[func_len + 4];
+       psint_t base;
+       unsigned int len;
+       psint_t pagesize;
+       size_t  count;
+       stack_t sigstk;
+       struct sigaction sigact;
+       char *cmd_name;
+       int c;
+
+       cmd_name = argv[0];
+
+       while ((c = getopt(argc, argv, "v")) != -1) {
+               switch (c) {
+               case 'v':
+                       verbose = 1;
+                       break;
+
+               case '?':
+               default:
+                       fprintf(stderr, "usage: data_exec [-v]\n");
+                       exit(1);
+               }
+       }
+
+       pagesize = getpagesize();
+
+       sigstk.ss_sp = malloc(ALT_STK_SIZE);
+       sigstk.ss_size = ALT_STK_SIZE;
+       sigstk.ss_flags = 0;
+
+       if (sigaltstack(&sigstk, NULL) < 0) {
+               perror("sigaltstack");
+               exit(1);
+       }
+
+       sigact.sa_handler = catch_segv;
+       sigact.sa_flags = SA_ONSTACK;
+       sigemptyset(&sigact.sa_mask);
+
+       if (sigaction(SIGSEGV, &sigact, NULL) == -1) {
+               perror("sigaction SIGSEGV");
+               exit(1);
+       }
+
+        if (sigaction(SIGBUS, &sigact, NULL) == -1) {
+                perror("sigaction SIGBUS");
+                exit(1);
+        }
+
+       test = HEAP_TEST;
+
+restart:
+
+       if ((result = setjmp(resume)) != 0) {
+               if (result != expected[test]) {
+                       printf("%s: test %d failed, expected %d, got %d\n", cmd_name, test, expected[test], result);
+                       exit(2);
+               }
+
+               test++;
+               goto restart;
+       }
+
+       switch (test) {
+       case HEAP_TEST:
+               msg("attempting to execute from malloc'ed area..\n");
+
+               func = (void *)malloc(func_len);
+       
+               func = (void *)((char *)func + ((psint_t)test_func & 0x3));
+       
+               bcopy(test_func, func, func_len);
+       
+               result = (*func)();
+               msg("execution suceeded, result is %d\n\n", result);
+               longjmp(resume, SUCCEED);
+
+       case HEAP_PROT_EXEC:
+               msg("attempting to execute from malloc'ed area with PROT_EXEC..\n");
+
+               func = (void *)malloc(func_len);
+       
+               func = (void *)((char *)func + ((psint_t)test_func & 0x3));
+               bcopy(test_func, func, func_len);
+
+               base = (psint_t)func & ~(pagesize - 1);
+               len  = func_len + (psint_t)func - base;
+
+               if(mprotect((void *)base, len, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
+                       perror("mprotect of stack");
+                       exit(1);
+               }
+
+               result = (*func)();
+               msg("execution suceeded, result is %d\n\n", result);
+               longjmp(resume, SUCCEED);
+
+       case STACK_TEST:
+               msg("attempting to execute from stack...\n");
+
+               func = (void *)(buf + ((psint_t)test_func & 0x3));
+               bcopy(test_func, func, func_len);
+       
+               result = (*func)();
+               msg("stack execution suceeded, result from stack exec is %d\n\n", result);
+               longjmp(resume, SUCCEED);
+
+       case STACK_PROT_EXEC:
+               msg("attempting to execute from stack with PROT_EXEC...\n");
+
+               func = (void *)(buf + ((psint_t)test_func & 0x3));
+               bcopy(test_func, func, func_len);
+       
+               base = (psint_t)func & ~(pagesize - 1);
+               len  = func_len + (psint_t)func - base;
+       
+               if(mprotect((void *)base, len, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
+                       perror("mprotect of stack");
+                       exit(1);
+               }
+       
+               result = (*func)();
+               msg("stack execution suceeded, result from stack exec is %d\n", result);
+               longjmp(resume, SUCCEED);
+       }
+
+       msg("All tests passed.\n");
+       exit(0);
+}
+
+
+int
+test_func()
+{
+       return 42;
+}
+
+
+void 
+catch_segv(int sig)
+{
+       msg("got sig %d\n\n", sig);
+       longjmp(resume, FAIL);
+}