sigaltstack.c (2789B)
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 24static int nerrs; 25 26static bool sigalrm_expected; 27 28static unsigned long at_minstack_size; 29 30static 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 43static 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 54static 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 65static jmp_buf jmpbuf; 66 67static 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 79static 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 89static 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 111int 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}