1*ab12c95dSIlya Leoshkevich/* 2*ab12c95dSIlya Leoshkevich * Common code for arch-specific MMU_INST_FETCH fault testing. 3*ab12c95dSIlya Leoshkevich */ 4*ab12c95dSIlya Leoshkevich 5*ab12c95dSIlya Leoshkevich#define _GNU_SOURCE 6*ab12c95dSIlya Leoshkevich 7*ab12c95dSIlya Leoshkevich#include <assert.h> 8*ab12c95dSIlya Leoshkevich#include <signal.h> 9*ab12c95dSIlya Leoshkevich#include <stdio.h> 10*ab12c95dSIlya Leoshkevich#include <stdlib.h> 11*ab12c95dSIlya Leoshkevich#include <string.h> 12*ab12c95dSIlya Leoshkevich#include <errno.h> 13*ab12c95dSIlya Leoshkevich#include <unistd.h> 14*ab12c95dSIlya Leoshkevich#include <sys/mman.h> 15*ab12c95dSIlya Leoshkevich#include <sys/ucontext.h> 16*ab12c95dSIlya Leoshkevich 17*ab12c95dSIlya Leoshkevich/* Forward declarations. */ 18*ab12c95dSIlya Leoshkevich 19*ab12c95dSIlya Leoshkevichstatic void *arch_mcontext_pc(const mcontext_t *ctx); 20*ab12c95dSIlya Leoshkevichstatic int arch_mcontext_arg(const mcontext_t *ctx); 21*ab12c95dSIlya Leoshkevichstatic void arch_flush(void *p, int len); 22*ab12c95dSIlya Leoshkevich 23*ab12c95dSIlya Leoshkevich/* Testing infrastructure. */ 24*ab12c95dSIlya Leoshkevich 25*ab12c95dSIlya Leoshkevichstruct noexec_test { 26*ab12c95dSIlya Leoshkevich const char *name; 27*ab12c95dSIlya Leoshkevich const char *test_code; 28*ab12c95dSIlya Leoshkevich int test_len; 29*ab12c95dSIlya Leoshkevich int page_ofs; 30*ab12c95dSIlya Leoshkevich int entry_ofs; 31*ab12c95dSIlya Leoshkevich int expected_si_ofs; 32*ab12c95dSIlya Leoshkevich int expected_pc_ofs; 33*ab12c95dSIlya Leoshkevich int expected_arg; 34*ab12c95dSIlya Leoshkevich}; 35*ab12c95dSIlya Leoshkevich 36*ab12c95dSIlya Leoshkevichstatic void *page_base; 37*ab12c95dSIlya Leoshkevichstatic int page_size; 38*ab12c95dSIlya Leoshkevichstatic const struct noexec_test *current_noexec_test; 39*ab12c95dSIlya Leoshkevich 40*ab12c95dSIlya Leoshkevichstatic void handle_err(const char *syscall) 41*ab12c95dSIlya Leoshkevich{ 42*ab12c95dSIlya Leoshkevich printf("[ FAILED ] %s: %s\n", syscall, strerror(errno)); 43*ab12c95dSIlya Leoshkevich exit(EXIT_FAILURE); 44*ab12c95dSIlya Leoshkevich} 45*ab12c95dSIlya Leoshkevich 46*ab12c95dSIlya Leoshkevichstatic void handle_segv(int sig, siginfo_t *info, void *ucontext) 47*ab12c95dSIlya Leoshkevich{ 48*ab12c95dSIlya Leoshkevich const struct noexec_test *test = current_noexec_test; 49*ab12c95dSIlya Leoshkevich const mcontext_t *mc = &((ucontext_t *)ucontext)->uc_mcontext; 50*ab12c95dSIlya Leoshkevich void *expected_si; 51*ab12c95dSIlya Leoshkevich void *expected_pc; 52*ab12c95dSIlya Leoshkevich void *pc; 53*ab12c95dSIlya Leoshkevich int arg; 54*ab12c95dSIlya Leoshkevich 55*ab12c95dSIlya Leoshkevich if (test == NULL) { 56*ab12c95dSIlya Leoshkevich printf("[ FAILED ] unexpected SEGV\n"); 57*ab12c95dSIlya Leoshkevich exit(EXIT_FAILURE); 58*ab12c95dSIlya Leoshkevich } 59*ab12c95dSIlya Leoshkevich current_noexec_test = NULL; 60*ab12c95dSIlya Leoshkevich 61*ab12c95dSIlya Leoshkevich expected_si = page_base + test->expected_si_ofs; 62*ab12c95dSIlya Leoshkevich if (info->si_addr != expected_si) { 63*ab12c95dSIlya Leoshkevich printf("[ FAILED ] wrong si_addr (%p != %p)\n", 64*ab12c95dSIlya Leoshkevich info->si_addr, expected_si); 65*ab12c95dSIlya Leoshkevich exit(EXIT_FAILURE); 66*ab12c95dSIlya Leoshkevich } 67*ab12c95dSIlya Leoshkevich 68*ab12c95dSIlya Leoshkevich pc = arch_mcontext_pc(mc); 69*ab12c95dSIlya Leoshkevich expected_pc = page_base + test->expected_pc_ofs; 70*ab12c95dSIlya Leoshkevich if (pc != expected_pc) { 71*ab12c95dSIlya Leoshkevich printf("[ FAILED ] wrong pc (%p != %p)\n", pc, expected_pc); 72*ab12c95dSIlya Leoshkevich exit(EXIT_FAILURE); 73*ab12c95dSIlya Leoshkevich } 74*ab12c95dSIlya Leoshkevich 75*ab12c95dSIlya Leoshkevich arg = arch_mcontext_arg(mc); 76*ab12c95dSIlya Leoshkevich if (arg != test->expected_arg) { 77*ab12c95dSIlya Leoshkevich printf("[ FAILED ] wrong arg (%d != %d)\n", arg, test->expected_arg); 78*ab12c95dSIlya Leoshkevich exit(EXIT_FAILURE); 79*ab12c95dSIlya Leoshkevich } 80*ab12c95dSIlya Leoshkevich 81*ab12c95dSIlya Leoshkevich if (mprotect(page_base, page_size, 82*ab12c95dSIlya Leoshkevich PROT_READ | PROT_WRITE | PROT_EXEC) < 0) { 83*ab12c95dSIlya Leoshkevich handle_err("mprotect"); 84*ab12c95dSIlya Leoshkevich } 85*ab12c95dSIlya Leoshkevich} 86*ab12c95dSIlya Leoshkevich 87*ab12c95dSIlya Leoshkevichstatic void test_noexec_1(const struct noexec_test *test) 88*ab12c95dSIlya Leoshkevich{ 89*ab12c95dSIlya Leoshkevich void *start = page_base + test->page_ofs; 90*ab12c95dSIlya Leoshkevich void (*fn)(int arg) = page_base + test->entry_ofs; 91*ab12c95dSIlya Leoshkevich 92*ab12c95dSIlya Leoshkevich memcpy(start, test->test_code, test->test_len); 93*ab12c95dSIlya Leoshkevich arch_flush(start, test->test_len); 94*ab12c95dSIlya Leoshkevich 95*ab12c95dSIlya Leoshkevich /* Trigger TB creation in order to test invalidation. */ 96*ab12c95dSIlya Leoshkevich fn(0); 97*ab12c95dSIlya Leoshkevich 98*ab12c95dSIlya Leoshkevich if (mprotect(page_base, page_size, PROT_NONE) < 0) { 99*ab12c95dSIlya Leoshkevich handle_err("mprotect"); 100*ab12c95dSIlya Leoshkevich } 101*ab12c95dSIlya Leoshkevich 102*ab12c95dSIlya Leoshkevich /* Trigger SEGV and check that handle_segv() ran. */ 103*ab12c95dSIlya Leoshkevich current_noexec_test = test; 104*ab12c95dSIlya Leoshkevich fn(0); 105*ab12c95dSIlya Leoshkevich assert(current_noexec_test == NULL); 106*ab12c95dSIlya Leoshkevich} 107*ab12c95dSIlya Leoshkevich 108*ab12c95dSIlya Leoshkevichstatic int test_noexec(struct noexec_test *tests, size_t n_tests) 109*ab12c95dSIlya Leoshkevich{ 110*ab12c95dSIlya Leoshkevich struct sigaction act; 111*ab12c95dSIlya Leoshkevich size_t i; 112*ab12c95dSIlya Leoshkevich 113*ab12c95dSIlya Leoshkevich memset(&act, 0, sizeof(act)); 114*ab12c95dSIlya Leoshkevich act.sa_sigaction = handle_segv; 115*ab12c95dSIlya Leoshkevich act.sa_flags = SA_SIGINFO; 116*ab12c95dSIlya Leoshkevich if (sigaction(SIGSEGV, &act, NULL) < 0) { 117*ab12c95dSIlya Leoshkevich handle_err("sigaction"); 118*ab12c95dSIlya Leoshkevich } 119*ab12c95dSIlya Leoshkevich 120*ab12c95dSIlya Leoshkevich page_size = getpagesize(); 121*ab12c95dSIlya Leoshkevich page_base = mmap(NULL, 2 * page_size, 122*ab12c95dSIlya Leoshkevich PROT_READ | PROT_WRITE | PROT_EXEC, 123*ab12c95dSIlya Leoshkevich MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 124*ab12c95dSIlya Leoshkevich if (page_base == MAP_FAILED) { 125*ab12c95dSIlya Leoshkevich handle_err("mmap"); 126*ab12c95dSIlya Leoshkevich } 127*ab12c95dSIlya Leoshkevich page_base += page_size; 128*ab12c95dSIlya Leoshkevich 129*ab12c95dSIlya Leoshkevich for (i = 0; i < n_tests; i++) { 130*ab12c95dSIlya Leoshkevich struct noexec_test *test = &tests[i]; 131*ab12c95dSIlya Leoshkevich 132*ab12c95dSIlya Leoshkevich printf("[ RUN ] %s\n", test->name); 133*ab12c95dSIlya Leoshkevich test_noexec_1(test); 134*ab12c95dSIlya Leoshkevich printf("[ OK ]\n"); 135*ab12c95dSIlya Leoshkevich } 136*ab12c95dSIlya Leoshkevich 137*ab12c95dSIlya Leoshkevich printf("[ PASSED ]\n"); 138*ab12c95dSIlya Leoshkevich return EXIT_SUCCESS; 139*ab12c95dSIlya Leoshkevich} 140