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