xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/sigaltstack/sas.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Stas Sergeev <stsp@users.sourceforge.net>
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * test sigaltstack(SS_ONSTACK | SS_AUTODISARM)
6*4882a593Smuzhiyun  * If that succeeds, then swapcontext() can be used inside sighandler safely.
7*4882a593Smuzhiyun  *
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #define _GNU_SOURCE
11*4882a593Smuzhiyun #include <signal.h>
12*4882a593Smuzhiyun #include <stdio.h>
13*4882a593Smuzhiyun #include <stdlib.h>
14*4882a593Smuzhiyun #include <sys/mman.h>
15*4882a593Smuzhiyun #include <ucontext.h>
16*4882a593Smuzhiyun #include <alloca.h>
17*4882a593Smuzhiyun #include <string.h>
18*4882a593Smuzhiyun #include <assert.h>
19*4882a593Smuzhiyun #include <errno.h>
20*4882a593Smuzhiyun 
21*4882a593Smuzhiyun #include "../kselftest.h"
22*4882a593Smuzhiyun 
23*4882a593Smuzhiyun #ifndef SS_AUTODISARM
24*4882a593Smuzhiyun #define SS_AUTODISARM  (1U << 31)
25*4882a593Smuzhiyun #endif
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun static void *sstack, *ustack;
28*4882a593Smuzhiyun static ucontext_t uc, sc;
29*4882a593Smuzhiyun static const char *msg = "[OK]\tStack preserved";
30*4882a593Smuzhiyun static const char *msg2 = "[FAIL]\tStack corrupted";
31*4882a593Smuzhiyun struct stk_data {
32*4882a593Smuzhiyun 	char msg[128];
33*4882a593Smuzhiyun 	int flag;
34*4882a593Smuzhiyun };
35*4882a593Smuzhiyun 
my_usr1(int sig,siginfo_t * si,void * u)36*4882a593Smuzhiyun void my_usr1(int sig, siginfo_t *si, void *u)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun 	char *aa;
39*4882a593Smuzhiyun 	int err;
40*4882a593Smuzhiyun 	stack_t stk;
41*4882a593Smuzhiyun 	struct stk_data *p;
42*4882a593Smuzhiyun 
43*4882a593Smuzhiyun #if __s390x__
44*4882a593Smuzhiyun 	register unsigned long sp asm("%15");
45*4882a593Smuzhiyun #else
46*4882a593Smuzhiyun 	register unsigned long sp asm("sp");
47*4882a593Smuzhiyun #endif
48*4882a593Smuzhiyun 
49*4882a593Smuzhiyun 	if (sp < (unsigned long)sstack ||
50*4882a593Smuzhiyun 			sp >= (unsigned long)sstack + SIGSTKSZ) {
51*4882a593Smuzhiyun 		ksft_exit_fail_msg("SP is not on sigaltstack\n");
52*4882a593Smuzhiyun 	}
53*4882a593Smuzhiyun 	/* put some data on stack. other sighandler will try to overwrite it */
54*4882a593Smuzhiyun 	aa = alloca(1024);
55*4882a593Smuzhiyun 	assert(aa);
56*4882a593Smuzhiyun 	p = (struct stk_data *)(aa + 512);
57*4882a593Smuzhiyun 	strcpy(p->msg, msg);
58*4882a593Smuzhiyun 	p->flag = 1;
59*4882a593Smuzhiyun 	ksft_print_msg("[RUN]\tsignal USR1\n");
60*4882a593Smuzhiyun 	err = sigaltstack(NULL, &stk);
61*4882a593Smuzhiyun 	if (err) {
62*4882a593Smuzhiyun 		ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));
63*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
64*4882a593Smuzhiyun 	}
65*4882a593Smuzhiyun 	if (stk.ss_flags != SS_DISABLE)
66*4882a593Smuzhiyun 		ksft_test_result_fail("tss_flags=%x, should be SS_DISABLE\n",
67*4882a593Smuzhiyun 				stk.ss_flags);
68*4882a593Smuzhiyun 	else
69*4882a593Smuzhiyun 		ksft_test_result_pass(
70*4882a593Smuzhiyun 				"sigaltstack is disabled in sighandler\n");
71*4882a593Smuzhiyun 	swapcontext(&sc, &uc);
72*4882a593Smuzhiyun 	ksft_print_msg("%s\n", p->msg);
73*4882a593Smuzhiyun 	if (!p->flag) {
74*4882a593Smuzhiyun 		ksft_exit_fail_msg("[RUN]\tAborting\n");
75*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
76*4882a593Smuzhiyun 	}
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun 
my_usr2(int sig,siginfo_t * si,void * u)79*4882a593Smuzhiyun void my_usr2(int sig, siginfo_t *si, void *u)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun 	char *aa;
82*4882a593Smuzhiyun 	struct stk_data *p;
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	ksft_print_msg("[RUN]\tsignal USR2\n");
85*4882a593Smuzhiyun 	aa = alloca(1024);
86*4882a593Smuzhiyun 	/* dont run valgrind on this */
87*4882a593Smuzhiyun 	/* try to find the data stored by previous sighandler */
88*4882a593Smuzhiyun 	p = memmem(aa, 1024, msg, strlen(msg));
89*4882a593Smuzhiyun 	if (p) {
90*4882a593Smuzhiyun 		ksft_test_result_fail("sigaltstack re-used\n");
91*4882a593Smuzhiyun 		/* corrupt the data */
92*4882a593Smuzhiyun 		strcpy(p->msg, msg2);
93*4882a593Smuzhiyun 		/* tell other sighandler that his data is corrupted */
94*4882a593Smuzhiyun 		p->flag = 0;
95*4882a593Smuzhiyun 	}
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
switch_fn(void)98*4882a593Smuzhiyun static void switch_fn(void)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun 	ksft_print_msg("[RUN]\tswitched to user ctx\n");
101*4882a593Smuzhiyun 	raise(SIGUSR2);
102*4882a593Smuzhiyun 	setcontext(&sc);
103*4882a593Smuzhiyun }
104*4882a593Smuzhiyun 
main(void)105*4882a593Smuzhiyun int main(void)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun 	struct sigaction act;
108*4882a593Smuzhiyun 	stack_t stk;
109*4882a593Smuzhiyun 	int err;
110*4882a593Smuzhiyun 
111*4882a593Smuzhiyun 	ksft_print_header();
112*4882a593Smuzhiyun 	ksft_set_plan(3);
113*4882a593Smuzhiyun 
114*4882a593Smuzhiyun 	sigemptyset(&act.sa_mask);
115*4882a593Smuzhiyun 	act.sa_flags = SA_ONSTACK | SA_SIGINFO;
116*4882a593Smuzhiyun 	act.sa_sigaction = my_usr1;
117*4882a593Smuzhiyun 	sigaction(SIGUSR1, &act, NULL);
118*4882a593Smuzhiyun 	act.sa_sigaction = my_usr2;
119*4882a593Smuzhiyun 	sigaction(SIGUSR2, &act, NULL);
120*4882a593Smuzhiyun 	sstack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
121*4882a593Smuzhiyun 		      MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
122*4882a593Smuzhiyun 	if (sstack == MAP_FAILED) {
123*4882a593Smuzhiyun 		ksft_exit_fail_msg("mmap() - %s\n", strerror(errno));
124*4882a593Smuzhiyun 		return EXIT_FAILURE;
125*4882a593Smuzhiyun 	}
126*4882a593Smuzhiyun 
127*4882a593Smuzhiyun 	err = sigaltstack(NULL, &stk);
128*4882a593Smuzhiyun 	if (err) {
129*4882a593Smuzhiyun 		ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));
130*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
131*4882a593Smuzhiyun 	}
132*4882a593Smuzhiyun 	if (stk.ss_flags == SS_DISABLE) {
133*4882a593Smuzhiyun 		ksft_test_result_pass(
134*4882a593Smuzhiyun 				"Initial sigaltstack state was SS_DISABLE\n");
135*4882a593Smuzhiyun 	} else {
136*4882a593Smuzhiyun 		ksft_exit_fail_msg("Initial sigaltstack state was %x; "
137*4882a593Smuzhiyun 		       "should have been SS_DISABLE\n", stk.ss_flags);
138*4882a593Smuzhiyun 		return EXIT_FAILURE;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun 
141*4882a593Smuzhiyun 	stk.ss_sp = sstack;
142*4882a593Smuzhiyun 	stk.ss_size = SIGSTKSZ;
143*4882a593Smuzhiyun 	stk.ss_flags = SS_ONSTACK | SS_AUTODISARM;
144*4882a593Smuzhiyun 	err = sigaltstack(&stk, NULL);
145*4882a593Smuzhiyun 	if (err) {
146*4882a593Smuzhiyun 		if (errno == EINVAL) {
147*4882a593Smuzhiyun 			ksft_test_result_skip(
148*4882a593Smuzhiyun 				"[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n");
149*4882a593Smuzhiyun 			/*
150*4882a593Smuzhiyun 			 * If test cases for the !SS_AUTODISARM variant were
151*4882a593Smuzhiyun 			 * added, we could still run them.  We don't have any
152*4882a593Smuzhiyun 			 * test cases like that yet, so just exit and report
153*4882a593Smuzhiyun 			 * success.
154*4882a593Smuzhiyun 			 */
155*4882a593Smuzhiyun 			return 0;
156*4882a593Smuzhiyun 		} else {
157*4882a593Smuzhiyun 			ksft_exit_fail_msg(
158*4882a593Smuzhiyun 				"sigaltstack(SS_ONSTACK | SS_AUTODISARM)  %s\n",
159*4882a593Smuzhiyun 					strerror(errno));
160*4882a593Smuzhiyun 			return EXIT_FAILURE;
161*4882a593Smuzhiyun 		}
162*4882a593Smuzhiyun 	}
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun 	ustack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
165*4882a593Smuzhiyun 		      MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
166*4882a593Smuzhiyun 	if (ustack == MAP_FAILED) {
167*4882a593Smuzhiyun 		ksft_exit_fail_msg("mmap() - %s\n", strerror(errno));
168*4882a593Smuzhiyun 		return EXIT_FAILURE;
169*4882a593Smuzhiyun 	}
170*4882a593Smuzhiyun 	getcontext(&uc);
171*4882a593Smuzhiyun 	uc.uc_link = NULL;
172*4882a593Smuzhiyun 	uc.uc_stack.ss_sp = ustack;
173*4882a593Smuzhiyun 	uc.uc_stack.ss_size = SIGSTKSZ;
174*4882a593Smuzhiyun 	makecontext(&uc, switch_fn, 0);
175*4882a593Smuzhiyun 	raise(SIGUSR1);
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	err = sigaltstack(NULL, &stk);
178*4882a593Smuzhiyun 	if (err) {
179*4882a593Smuzhiyun 		ksft_exit_fail_msg("sigaltstack() - %s\n", strerror(errno));
180*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
181*4882a593Smuzhiyun 	}
182*4882a593Smuzhiyun 	if (stk.ss_flags != SS_AUTODISARM) {
183*4882a593Smuzhiyun 		ksft_exit_fail_msg("ss_flags=%x, should be SS_AUTODISARM\n",
184*4882a593Smuzhiyun 				stk.ss_flags);
185*4882a593Smuzhiyun 		exit(EXIT_FAILURE);
186*4882a593Smuzhiyun 	}
187*4882a593Smuzhiyun 	ksft_test_result_pass(
188*4882a593Smuzhiyun 			"sigaltstack is still SS_AUTODISARM after signal\n");
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	ksft_exit_pass();
191*4882a593Smuzhiyun 	return 0;
192*4882a593Smuzhiyun }
193