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
setup_altstack(void * start,unsigned long size)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
sigsegv(int sig,siginfo_t * info,void * ctx_void)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
sigalrm(int sig,siginfo_t * info,void * ctx_void)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
test_sigaltstack(void * altstack,unsigned long size)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
main(void)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