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