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 #include "helpers.h" 18 19 /* sigaltstack()-enforced minimum stack */ 20 #define ENFORCED_MINSIGSTKSZ 2048 21 22 #ifndef AT_MINSIGSTKSZ 23 # define AT_MINSIGSTKSZ 51 24 #endif 25 26 static int nerrs; 27 28 static bool sigalrm_expected; 29 30 static unsigned long at_minstack_size; 31 32 static int setup_altstack(void *start, unsigned long size) 33 { 34 stack_t ss; 35 36 memset(&ss, 0, sizeof(ss)); 37 ss.ss_size = size; 38 ss.ss_sp = start; 39 40 return sigaltstack(&ss, NULL); 41 } 42 43 static jmp_buf jmpbuf; 44 45 static void sigsegv(int sig, siginfo_t *info, void *ctx_void) 46 { 47 if (sigalrm_expected) { 48 printf("[FAIL]\tWrong signal delivered: SIGSEGV (expected SIGALRM)."); 49 nerrs++; 50 } else { 51 printf("[OK]\tSIGSEGV signal delivered.\n"); 52 } 53 54 siglongjmp(jmpbuf, 1); 55 } 56 57 static void sigalrm(int sig, siginfo_t *info, void *ctx_void) 58 { 59 if (!sigalrm_expected) { 60 printf("[FAIL]\tWrong signal delivered: SIGALRM (expected SIGSEGV)."); 61 nerrs++; 62 } else { 63 printf("[OK]\tSIGALRM signal delivered.\n"); 64 } 65 } 66 67 static void test_sigaltstack(void *altstack, unsigned long size) 68 { 69 if (setup_altstack(altstack, size)) 70 err(1, "sigaltstack()"); 71 72 sigalrm_expected = (size > at_minstack_size) ? true : false; 73 74 sethandler(SIGSEGV, sigsegv, 0); 75 sethandler(SIGALRM, sigalrm, SA_ONSTACK); 76 77 if (!sigsetjmp(jmpbuf, 1)) { 78 printf("[RUN]\tTest an alternate signal stack of %ssufficient size.\n", 79 sigalrm_expected ? "" : "in"); 80 printf("\tRaise SIGALRM. %s is expected to be delivered.\n", 81 sigalrm_expected ? "It" : "SIGSEGV"); 82 raise(SIGALRM); 83 } 84 85 clearhandler(SIGALRM); 86 clearhandler(SIGSEGV); 87 } 88 89 int main(void) 90 { 91 void *altstack; 92 93 at_minstack_size = getauxval(AT_MINSIGSTKSZ); 94 95 altstack = mmap(NULL, at_minstack_size + SIGSTKSZ, PROT_READ | PROT_WRITE, 96 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); 97 if (altstack == MAP_FAILED) 98 err(1, "mmap()"); 99 100 if ((ENFORCED_MINSIGSTKSZ + 1) < at_minstack_size) 101 test_sigaltstack(altstack, ENFORCED_MINSIGSTKSZ + 1); 102 103 test_sigaltstack(altstack, at_minstack_size + SIGSTKSZ); 104 105 return nerrs == 0 ? 0 : 1; 106 } 107