0001
0002
0003 #define _GNU_SOURCE
0004 #include <signal.h>
0005 #include <stdio.h>
0006 #include <stdbool.h>
0007 #include <string.h>
0008 #include <err.h>
0009 #include <errno.h>
0010 #include <limits.h>
0011 #include <sys/mman.h>
0012 #include <sys/auxv.h>
0013 #include <sys/prctl.h>
0014 #include <sys/resource.h>
0015 #include <setjmp.h>
0016
0017
0018 #define ENFORCED_MINSIGSTKSZ 2048
0019
0020 #ifndef AT_MINSIGSTKSZ
0021 # define AT_MINSIGSTKSZ 51
0022 #endif
0023
0024 static int nerrs;
0025
0026 static bool sigalrm_expected;
0027
0028 static unsigned long at_minstack_size;
0029
0030 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
0031 int flags)
0032 {
0033 struct sigaction sa;
0034
0035 memset(&sa, 0, sizeof(sa));
0036 sa.sa_sigaction = handler;
0037 sa.sa_flags = SA_SIGINFO | flags;
0038 sigemptyset(&sa.sa_mask);
0039 if (sigaction(sig, &sa, 0))
0040 err(1, "sigaction");
0041 }
0042
0043 static void clearhandler(int sig)
0044 {
0045 struct sigaction sa;
0046
0047 memset(&sa, 0, sizeof(sa));
0048 sa.sa_handler = SIG_DFL;
0049 sigemptyset(&sa.sa_mask);
0050 if (sigaction(sig, &sa, 0))
0051 err(1, "sigaction");
0052 }
0053
0054 static int setup_altstack(void *start, unsigned long size)
0055 {
0056 stack_t ss;
0057
0058 memset(&ss, 0, sizeof(ss));
0059 ss.ss_size = size;
0060 ss.ss_sp = start;
0061
0062 return sigaltstack(&ss, NULL);
0063 }
0064
0065 static jmp_buf jmpbuf;
0066
0067 static void sigsegv(int sig, siginfo_t *info, void *ctx_void)
0068 {
0069 if (sigalrm_expected) {
0070 printf("[FAIL]\tWrong signal delivered: SIGSEGV (expected SIGALRM).");
0071 nerrs++;
0072 } else {
0073 printf("[OK]\tSIGSEGV signal delivered.\n");
0074 }
0075
0076 siglongjmp(jmpbuf, 1);
0077 }
0078
0079 static void sigalrm(int sig, siginfo_t *info, void *ctx_void)
0080 {
0081 if (!sigalrm_expected) {
0082 printf("[FAIL]\tWrong signal delivered: SIGALRM (expected SIGSEGV).");
0083 nerrs++;
0084 } else {
0085 printf("[OK]\tSIGALRM signal delivered.\n");
0086 }
0087 }
0088
0089 static void test_sigaltstack(void *altstack, unsigned long size)
0090 {
0091 if (setup_altstack(altstack, size))
0092 err(1, "sigaltstack()");
0093
0094 sigalrm_expected = (size > at_minstack_size) ? true : false;
0095
0096 sethandler(SIGSEGV, sigsegv, 0);
0097 sethandler(SIGALRM, sigalrm, SA_ONSTACK);
0098
0099 if (!sigsetjmp(jmpbuf, 1)) {
0100 printf("[RUN]\tTest an alternate signal stack of %ssufficient size.\n",
0101 sigalrm_expected ? "" : "in");
0102 printf("\tRaise SIGALRM. %s is expected to be delivered.\n",
0103 sigalrm_expected ? "It" : "SIGSEGV");
0104 raise(SIGALRM);
0105 }
0106
0107 clearhandler(SIGALRM);
0108 clearhandler(SIGSEGV);
0109 }
0110
0111 int main(void)
0112 {
0113 void *altstack;
0114
0115 at_minstack_size = getauxval(AT_MINSIGSTKSZ);
0116
0117 altstack = mmap(NULL, at_minstack_size + SIGSTKSZ, PROT_READ | PROT_WRITE,
0118 MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
0119 if (altstack == MAP_FAILED)
0120 err(1, "mmap()");
0121
0122 if ((ENFORCED_MINSIGSTKSZ + 1) < at_minstack_size)
0123 test_sigaltstack(altstack, ENFORCED_MINSIGSTKSZ + 1);
0124
0125 test_sigaltstack(altstack, at_minstack_size + SIGSTKSZ);
0126
0127 return nerrs == 0 ? 0 : 1;
0128 }