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