xref: /aosp_15_r20/external/linux-kselftest/tools/testing/selftests/x86/sigaltstack.c (revision 053f45be4e351dfd5e965df293cd45b779f579ee)
1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-only
2*053f45beSAndroid Build Coastguard Worker 
3*053f45beSAndroid Build Coastguard Worker #define _GNU_SOURCE
4*053f45beSAndroid Build Coastguard Worker #include <signal.h>
5*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
6*053f45beSAndroid Build Coastguard Worker #include <stdbool.h>
7*053f45beSAndroid Build Coastguard Worker #include <string.h>
8*053f45beSAndroid Build Coastguard Worker #include <err.h>
9*053f45beSAndroid Build Coastguard Worker #include <errno.h>
10*053f45beSAndroid Build Coastguard Worker #include <limits.h>
11*053f45beSAndroid Build Coastguard Worker #include <sys/mman.h>
12*053f45beSAndroid Build Coastguard Worker #include <sys/auxv.h>
13*053f45beSAndroid Build Coastguard Worker #include <sys/prctl.h>
14*053f45beSAndroid Build Coastguard Worker #include <sys/resource.h>
15*053f45beSAndroid Build Coastguard Worker #include <setjmp.h>
16*053f45beSAndroid Build Coastguard Worker 
17*053f45beSAndroid Build Coastguard Worker /* sigaltstack()-enforced minimum stack */
18*053f45beSAndroid Build Coastguard Worker #define ENFORCED_MINSIGSTKSZ	2048
19*053f45beSAndroid Build Coastguard Worker 
20*053f45beSAndroid Build Coastguard Worker #ifndef AT_MINSIGSTKSZ
21*053f45beSAndroid Build Coastguard Worker #  define AT_MINSIGSTKSZ	51
22*053f45beSAndroid Build Coastguard Worker #endif
23*053f45beSAndroid Build Coastguard Worker 
24*053f45beSAndroid Build Coastguard Worker static int nerrs;
25*053f45beSAndroid Build Coastguard Worker 
26*053f45beSAndroid Build Coastguard Worker static bool sigalrm_expected;
27*053f45beSAndroid Build Coastguard Worker 
28*053f45beSAndroid Build Coastguard Worker static unsigned long at_minstack_size;
29*053f45beSAndroid Build Coastguard Worker 
sethandler(int sig,void (* handler)(int,siginfo_t *,void *),int flags)30*053f45beSAndroid Build Coastguard Worker static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
31*053f45beSAndroid Build Coastguard Worker 		       int flags)
32*053f45beSAndroid Build Coastguard Worker {
33*053f45beSAndroid Build Coastguard Worker 	struct sigaction sa;
34*053f45beSAndroid Build Coastguard Worker 
35*053f45beSAndroid Build Coastguard Worker 	memset(&sa, 0, sizeof(sa));
36*053f45beSAndroid Build Coastguard Worker 	sa.sa_sigaction = handler;
37*053f45beSAndroid Build Coastguard Worker 	sa.sa_flags = SA_SIGINFO | flags;
38*053f45beSAndroid Build Coastguard Worker 	sigemptyset(&sa.sa_mask);
39*053f45beSAndroid Build Coastguard Worker 	if (sigaction(sig, &sa, 0))
40*053f45beSAndroid Build Coastguard Worker 		err(1, "sigaction");
41*053f45beSAndroid Build Coastguard Worker }
42*053f45beSAndroid Build Coastguard Worker 
clearhandler(int sig)43*053f45beSAndroid Build Coastguard Worker static void clearhandler(int sig)
44*053f45beSAndroid Build Coastguard Worker {
45*053f45beSAndroid Build Coastguard Worker 	struct sigaction sa;
46*053f45beSAndroid Build Coastguard Worker 
47*053f45beSAndroid Build Coastguard Worker 	memset(&sa, 0, sizeof(sa));
48*053f45beSAndroid Build Coastguard Worker 	sa.sa_handler = SIG_DFL;
49*053f45beSAndroid Build Coastguard Worker 	sigemptyset(&sa.sa_mask);
50*053f45beSAndroid Build Coastguard Worker 	if (sigaction(sig, &sa, 0))
51*053f45beSAndroid Build Coastguard Worker 		err(1, "sigaction");
52*053f45beSAndroid Build Coastguard Worker }
53*053f45beSAndroid Build Coastguard Worker 
setup_altstack(void * start,unsigned long size)54*053f45beSAndroid Build Coastguard Worker static int setup_altstack(void *start, unsigned long size)
55*053f45beSAndroid Build Coastguard Worker {
56*053f45beSAndroid Build Coastguard Worker 	stack_t ss;
57*053f45beSAndroid Build Coastguard Worker 
58*053f45beSAndroid Build Coastguard Worker 	memset(&ss, 0, sizeof(ss));
59*053f45beSAndroid Build Coastguard Worker 	ss.ss_size = size;
60*053f45beSAndroid Build Coastguard Worker 	ss.ss_sp = start;
61*053f45beSAndroid Build Coastguard Worker 
62*053f45beSAndroid Build Coastguard Worker 	return sigaltstack(&ss, NULL);
63*053f45beSAndroid Build Coastguard Worker }
64*053f45beSAndroid Build Coastguard Worker 
65*053f45beSAndroid Build Coastguard Worker static jmp_buf jmpbuf;
66*053f45beSAndroid Build Coastguard Worker 
sigsegv(int sig,siginfo_t * info,void * ctx_void)67*053f45beSAndroid Build Coastguard Worker static void sigsegv(int sig, siginfo_t *info, void *ctx_void)
68*053f45beSAndroid Build Coastguard Worker {
69*053f45beSAndroid Build Coastguard Worker 	if (sigalrm_expected) {
70*053f45beSAndroid Build Coastguard Worker 		printf("[FAIL]\tWrong signal delivered: SIGSEGV (expected SIGALRM).");
71*053f45beSAndroid Build Coastguard Worker 		nerrs++;
72*053f45beSAndroid Build Coastguard Worker 	} else {
73*053f45beSAndroid Build Coastguard Worker 		printf("[OK]\tSIGSEGV signal delivered.\n");
74*053f45beSAndroid Build Coastguard Worker 	}
75*053f45beSAndroid Build Coastguard Worker 
76*053f45beSAndroid Build Coastguard Worker 	siglongjmp(jmpbuf, 1);
77*053f45beSAndroid Build Coastguard Worker }
78*053f45beSAndroid Build Coastguard Worker 
sigalrm(int sig,siginfo_t * info,void * ctx_void)79*053f45beSAndroid Build Coastguard Worker static void sigalrm(int sig, siginfo_t *info, void *ctx_void)
80*053f45beSAndroid Build Coastguard Worker {
81*053f45beSAndroid Build Coastguard Worker 	if (!sigalrm_expected) {
82*053f45beSAndroid Build Coastguard Worker 		printf("[FAIL]\tWrong signal delivered: SIGALRM (expected SIGSEGV).");
83*053f45beSAndroid Build Coastguard Worker 		nerrs++;
84*053f45beSAndroid Build Coastguard Worker 	} else {
85*053f45beSAndroid Build Coastguard Worker 		printf("[OK]\tSIGALRM signal delivered.\n");
86*053f45beSAndroid Build Coastguard Worker 	}
87*053f45beSAndroid Build Coastguard Worker }
88*053f45beSAndroid Build Coastguard Worker 
test_sigaltstack(void * altstack,unsigned long size)89*053f45beSAndroid Build Coastguard Worker static void test_sigaltstack(void *altstack, unsigned long size)
90*053f45beSAndroid Build Coastguard Worker {
91*053f45beSAndroid Build Coastguard Worker 	if (setup_altstack(altstack, size))
92*053f45beSAndroid Build Coastguard Worker 		err(1, "sigaltstack()");
93*053f45beSAndroid Build Coastguard Worker 
94*053f45beSAndroid Build Coastguard Worker 	sigalrm_expected = (size > at_minstack_size) ? true : false;
95*053f45beSAndroid Build Coastguard Worker 
96*053f45beSAndroid Build Coastguard Worker 	sethandler(SIGSEGV, sigsegv, 0);
97*053f45beSAndroid Build Coastguard Worker 	sethandler(SIGALRM, sigalrm, SA_ONSTACK);
98*053f45beSAndroid Build Coastguard Worker 
99*053f45beSAndroid Build Coastguard Worker 	if (!sigsetjmp(jmpbuf, 1)) {
100*053f45beSAndroid Build Coastguard Worker 		printf("[RUN]\tTest an alternate signal stack of %ssufficient size.\n",
101*053f45beSAndroid Build Coastguard Worker 		       sigalrm_expected ? "" : "in");
102*053f45beSAndroid Build Coastguard Worker 		printf("\tRaise SIGALRM. %s is expected to be delivered.\n",
103*053f45beSAndroid Build Coastguard Worker 		       sigalrm_expected ? "It" : "SIGSEGV");
104*053f45beSAndroid Build Coastguard Worker 		raise(SIGALRM);
105*053f45beSAndroid Build Coastguard Worker 	}
106*053f45beSAndroid Build Coastguard Worker 
107*053f45beSAndroid Build Coastguard Worker 	clearhandler(SIGALRM);
108*053f45beSAndroid Build Coastguard Worker 	clearhandler(SIGSEGV);
109*053f45beSAndroid Build Coastguard Worker }
110*053f45beSAndroid Build Coastguard Worker 
main(void)111*053f45beSAndroid Build Coastguard Worker int main(void)
112*053f45beSAndroid Build Coastguard Worker {
113*053f45beSAndroid Build Coastguard Worker 	void *altstack;
114*053f45beSAndroid Build Coastguard Worker 
115*053f45beSAndroid Build Coastguard Worker 	at_minstack_size = getauxval(AT_MINSIGSTKSZ);
116*053f45beSAndroid Build Coastguard Worker 
117*053f45beSAndroid Build Coastguard Worker 	altstack = mmap(NULL, at_minstack_size + SIGSTKSZ, PROT_READ | PROT_WRITE,
118*053f45beSAndroid Build Coastguard Worker 			MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
119*053f45beSAndroid Build Coastguard Worker 	if (altstack == MAP_FAILED)
120*053f45beSAndroid Build Coastguard Worker 		err(1, "mmap()");
121*053f45beSAndroid Build Coastguard Worker 
122*053f45beSAndroid Build Coastguard Worker 	if ((ENFORCED_MINSIGSTKSZ + 1) < at_minstack_size)
123*053f45beSAndroid Build Coastguard Worker 		test_sigaltstack(altstack, ENFORCED_MINSIGSTKSZ + 1);
124*053f45beSAndroid Build Coastguard Worker 
125*053f45beSAndroid Build Coastguard Worker 	test_sigaltstack(altstack, at_minstack_size + SIGSTKSZ);
126*053f45beSAndroid Build Coastguard Worker 
127*053f45beSAndroid Build Coastguard Worker 	return nerrs == 0 ? 0 : 1;
128*053f45beSAndroid Build Coastguard Worker }
129