1 // SPDX-License-Identifier: GPL-2.0-only 2 3 #define _GNU_SOURCE 4 #include <signal.h> 5 #include <stdio.h> 6 #include <stdbool.h> 7 #include <string.h> 8 #include <err.h> 9 #include <errno.h> 10 #include <limits.h> 11 #include <sys/mman.h> 12 #include <sys/auxv.h> 13 #include <sys/prctl.h> 14 #include <sys/resource.h> 15 #include <setjmp.h> 16 17 /* sigaltstack()-enforced minimum stack */ 18 #define ENFORCED_MINSIGSTKSZ 2048 19 20 #ifndef AT_MINSIGSTKSZ 21 # define AT_MINSIGSTKSZ 51 22 #endif 23 24 static int nerrs; 25 26 static bool sigalrm_expected; 27 28 static unsigned long at_minstack_size; 29 30 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), 31 int flags) 32 { 33 struct sigaction sa; 34 35 memset(&sa, 0, sizeof(sa)); 36 sa.sa_sigaction = handler; 37 sa.sa_flags = SA_SIGINFO | flags; 38 sigemptyset(&sa.sa_mask); 39 if (sigaction(sig, &sa, 0)) 40 err(1, "sigaction"); 41 } 42 43 static void clearhandler(int sig) 44 { 45 struct sigaction sa; 46 47 memset(&sa, 0, sizeof(sa)); 48 sa.sa_handler = SIG_DFL; 49 sigemptyset(&sa.sa_mask); 50 if (sigaction(sig, &sa, 0)) 51 err(1, "sigaction"); 52 } 53 54 static int setup_altstack(void *start, unsigned long size) 55 { 56 stack_t ss; 57 58 memset(&ss, 0, sizeof(ss)); 59 ss.ss_size = size; 60 ss.ss_sp = start; 61 62 return sigaltstack(&ss, NULL); 63 } 64 65 static jmp_buf jmpbuf; 66 67 static void sigsegv(int sig, siginfo_t *info, void *ctx_void) 68 { 69 if (sigalrm_expected) { 70 printf("[FAIL]\tWrong signal delivered: SIGSEGV (expected SIGALRM)."); 71 nerrs++; 72 } else { 73 printf("[OK]\tSIGSEGV signal delivered.\n"); 74 } 75 76 siglongjmp(jmpbuf, 1); 77 } 78 79 static void sigalrm(int sig, siginfo_t *info, void *ctx_void) 80 { 81 if (!sigalrm_expected) { 82 printf("[FAIL]\tWrong signal delivered: SIGALRM (expected SIGSEGV)."); 83 nerrs++; 84 } else { 85 printf("[OK]\tSIGALRM signal delivered.\n"); 86 } 87 } 88 89 static void test_sigaltstack(void *altstack, unsigned long size) 90 { 91 if (setup_altstack(altstack, size)) 92 err(1, "sigaltstack()"); 93 94 sigalrm_expected = (size > at_minstack_size) ? true : false; 95 96 sethandler(SIGSEGV, sigsegv, 0); 97 sethandler(SIGALRM, sigalrm, SA_ONSTACK); 98 99 if (!sigsetjmp(jmpbuf, 1)) { 100 printf("[RUN]\tTest an alternate signal stack of %ssufficient size.\n", 101 sigalrm_expected ? "" : "in"); 102 printf("\tRaise SIGALRM. %s is expected to be delivered.\n", 103 sigalrm_expected ? "It" : "SIGSEGV"); 104 raise(SIGALRM); 105 } 106 107 clearhandler(SIGALRM); 108 clearhandler(SIGSEGV); 109 } 110 111 int main(void) 112 { 113 void *altstack; 114 115 at_minstack_size = getauxval(AT_MINSIGSTKSZ); 116 117 altstack = mmap(NULL, at_minstack_size + SIGSTKSZ, PROT_READ | PROT_WRITE, 118 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 119 if (altstack == MAP_FAILED) 120 err(1, "mmap()"); 121 122 if ((ENFORCED_MINSIGSTKSZ + 1) < at_minstack_size) 123 test_sigaltstack(altstack, ENFORCED_MINSIGSTKSZ + 1); 124 125 test_sigaltstack(altstack, at_minstack_size + SIGSTKSZ); 126 127 return nerrs == 0 ? 0 : 1; 128 } 129