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