diff options
author | Stas Sergeev <stsp@list.ru> | 2016-04-14 16:20:05 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-05-03 02:37:59 -0400 |
commit | 19fd2868e3671b446b13d135a44363182bbd319a (patch) | |
tree | ebacbd848577213edf32798ecdd96c362cf03fa0 | |
parent | 2a74213838104a41588d86fd5e8d344972891ace (diff) |
selftests/sigaltstack: Add new testcase for sigaltstack(SS_ONSTACK|SS_AUTODISARM)
This patch adds the test case for SS_AUTODISARM flag.
The test-case tries to set SS_AUTODISARM flag and checks if
the nested signal corrupts the stack after swapcontext().
Signed-off-by: Stas Sergeev <stsp@list.ru>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Pavel Emelyanov <xemul@parallels.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Shuah Khan <shuahkh@osg.samsung.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: linux-api@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Link: http://lkml.kernel.org/r/1460665206-13646-5-git-send-email-stsp@list.ru
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | tools/testing/selftests/Makefile | 1 | ||||
-rw-r--r-- | tools/testing/selftests/sigaltstack/Makefile | 8 | ||||
-rw-r--r-- | tools/testing/selftests/sigaltstack/sas.c | 156 |
3 files changed, 165 insertions, 0 deletions
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index b04afc3295df..ff9e5f20a5a7 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -19,6 +19,7 @@ TARGETS += powerpc | |||
19 | TARGETS += pstore | 19 | TARGETS += pstore |
20 | TARGETS += ptrace | 20 | TARGETS += ptrace |
21 | TARGETS += seccomp | 21 | TARGETS += seccomp |
22 | TARGETS += sigaltstack | ||
22 | TARGETS += size | 23 | TARGETS += size |
23 | TARGETS += static_keys | 24 | TARGETS += static_keys |
24 | TARGETS += sysctl | 25 | TARGETS += sysctl |
diff --git a/tools/testing/selftests/sigaltstack/Makefile b/tools/testing/selftests/sigaltstack/Makefile new file mode 100644 index 000000000000..56af56eda6fa --- /dev/null +++ b/tools/testing/selftests/sigaltstack/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | CFLAGS = -Wall | ||
2 | BINARIES = sas | ||
3 | all: $(BINARIES) | ||
4 | |||
5 | include ../lib.mk | ||
6 | |||
7 | clean: | ||
8 | rm -rf $(BINARIES) | ||
diff --git a/tools/testing/selftests/sigaltstack/sas.c b/tools/testing/selftests/sigaltstack/sas.c new file mode 100644 index 000000000000..57da8bfde60b --- /dev/null +++ b/tools/testing/selftests/sigaltstack/sas.c | |||
@@ -0,0 +1,156 @@ | |||
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 | } | ||