57da8bfde60b5e406c99f8c8b20a5411ce464d0e
[cascardo/linux.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
19 #ifndef SS_AUTODISARM
20 #define SS_AUTODISARM  (1 << 4)
21 #endif
22
23 static void *sstack, *ustack;
24 static ucontext_t uc, sc;
25 static const char *msg = "[OK]\tStack preserved";
26 static const char *msg2 = "[FAIL]\tStack corrupted";
27 struct stk_data {
28         char msg[128];
29         int flag;
30 };
31
32 void my_usr1(int sig, siginfo_t *si, void *u)
33 {
34         char *aa;
35         int err;
36         stack_t stk;
37         struct stk_data *p;
38
39         register unsigned long sp asm("sp");
40
41         if (sp < (unsigned long)sstack ||
42                         sp >= (unsigned long)sstack + SIGSTKSZ) {
43                 printf("[FAIL]\tSP is not on sigaltstack\n");
44                 exit(EXIT_FAILURE);
45         }
46         /* put some data on stack. other sighandler will try to overwrite it */
47         aa = alloca(1024);
48         assert(aa);
49         p = (struct stk_data *)(aa + 512);
50         strcpy(p->msg, msg);
51         p->flag = 1;
52         printf("[RUN]\tsignal USR1\n");
53         err = sigaltstack(NULL, &stk);
54         if (err) {
55                 perror("[FAIL]\tsigaltstack()");
56                 exit(EXIT_FAILURE);
57         }
58         if (stk.ss_flags != SS_DISABLE)
59                 printf("[FAIL]\tss_flags=%i, should be SS_DISABLE\n",
60                                 stk.ss_flags);
61         else
62                 printf("[OK]\tsigaltstack is disabled in sighandler\n");
63         swapcontext(&sc, &uc);
64         printf("%s\n", p->msg);
65         if (!p->flag) {
66                 printf("[RUN]\tAborting\n");
67                 exit(EXIT_FAILURE);
68         }
69 }
70
71 void my_usr2(int sig, siginfo_t *si, void *u)
72 {
73         char *aa;
74         struct stk_data *p;
75
76         printf("[RUN]\tsignal USR2\n");
77         aa = alloca(1024);
78         /* dont run valgrind on this */
79         /* try to find the data stored by previous sighandler */
80         p = memmem(aa, 1024, msg, strlen(msg));
81         if (p) {
82                 printf("[FAIL]\tsigaltstack re-used\n");
83                 /* corrupt the data */
84                 strcpy(p->msg, msg2);
85                 /* tell other sighandler that his data is corrupted */
86                 p->flag = 0;
87         }
88 }
89
90 static void switch_fn(void)
91 {
92         printf("[RUN]\tswitched to user ctx\n");
93         raise(SIGUSR2);
94         setcontext(&sc);
95 }
96
97 int main(void)
98 {
99         struct sigaction act;
100         stack_t stk;
101         int err;
102
103         sigemptyset(&act.sa_mask);
104         act.sa_flags = SA_ONSTACK | SA_SIGINFO;
105         act.sa_sigaction = my_usr1;
106         sigaction(SIGUSR1, &act, NULL);
107         act.sa_sigaction = my_usr2;
108         sigaction(SIGUSR2, &act, NULL);
109         sstack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
110                       MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
111         if (sstack == MAP_FAILED) {
112                 perror("mmap()");
113                 return EXIT_FAILURE;
114         }
115         stk.ss_sp = sstack;
116         stk.ss_size = SIGSTKSZ;
117         stk.ss_flags = SS_ONSTACK | SS_AUTODISARM;
118         err = sigaltstack(&stk, NULL);
119         if (err) {
120                 perror("[FAIL]\tsigaltstack(SS_ONSTACK | SS_AUTODISARM)");
121                 stk.ss_flags = SS_ONSTACK;
122         }
123         err = sigaltstack(&stk, NULL);
124         if (err) {
125                 perror("[FAIL]\tsigaltstack(SS_ONSTACK)");
126                 return EXIT_FAILURE;
127         }
128
129         ustack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
130                       MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
131         if (ustack == MAP_FAILED) {
132                 perror("mmap()");
133                 return EXIT_FAILURE;
134         }
135         getcontext(&uc);
136         uc.uc_link = NULL;
137         uc.uc_stack.ss_sp = ustack;
138         uc.uc_stack.ss_size = SIGSTKSZ;
139         makecontext(&uc, switch_fn, 0);
140         raise(SIGUSR1);
141
142         err = sigaltstack(NULL, &stk);
143         if (err) {
144                 perror("[FAIL]\tsigaltstack()");
145                 exit(EXIT_FAILURE);
146         }
147         if (stk.ss_flags != 0) {
148                 printf("[FAIL]\tss_flags=%i, should be 0\n",
149                                 stk.ss_flags);
150                 exit(EXIT_FAILURE);
151         }
152         printf("[OK]\tsigaltstack is enabled after signal\n");
153
154         printf("[OK]\tTest passed\n");
155         return 0;
156 }