129 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2 3#define _GNU_SOURCE4#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 204819 20#ifndef AT_MINSIGSTKSZ21# define AT_MINSIGSTKSZ 5122#endif23 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}129