t_sig_backtrace.c revision 1.5 1 /* $NetBSD: t_sig_backtrace.c,v 1.5 2022/07/25 22:37:37 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2021 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: t_sig_backtrace.c,v 1.5 2022/07/25 22:37:37 riastradh Exp $");
34
35 #include <sys/mman.h>
36 #include <execinfo.h>
37 #include <setjmp.h>
38 #include <stdbool.h>
39 #include <signal.h>
40 #include <stdio.h>
41 #include <stddef.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45
46 #include <atf-c.h>
47
48 stack_t sig_stack;
49
50 char *foo;
51 char *(*bar)(void);
52
53 static int the_loop_deref(int);
54 static int the_loop_jump(int);
55
56 #ifdef NOINLINE_HACK
57 volatile int noinline;
58 #endif
59
60 static int __noinline
61 func1(int i)
62 {
63 if (i > 100) {
64 return the_loop_deref(i);
65 }
66 return i + 1;
67 }
68
69 static int __noinline
70 func2(int i)
71 {
72 return func1(i) << 1;
73 }
74
75 static int __noinline
76 func3(int i)
77 {
78 if (func1(i) < 10) {
79 return func2(i);
80 } else {
81 return func1(i);
82 }
83 }
84
85 static int __noinline
86 the_loop_deref(int i)
87 {
88 while (*foo != 0) {
89 i = func3(i);
90 i = func1(i);
91 i = func2(i);
92 }
93
94 #ifdef NOINLINE_HACK
95 if (noinline)
96 vfork();
97 #endif
98
99 return i;
100 }
101
102 static int __noinline
103 the_loop_jump(int i)
104 {
105 while ((*bar)() != 0) {
106 i = func3(i);
107 i = func1(i);
108 i = func2(i);
109 }
110
111 #ifdef NOINLINE_HACK
112 if (noinline)
113 vfork();
114 #endif
115
116 return i;
117 }
118
119 jmp_buf env;
120
121 static void
122 handler(int s)
123 {
124 printf("signal: %d\n", s);
125
126 void *array[10];
127 size_t size = backtrace(array, 10);
128 ATF_REQUIRE(size != 0);
129
130 printf("Backtrace %zd stack frames.\n", size);
131 backtrace_symbols_fd(array, size, STDOUT_FILENO);
132
133 char **strings = backtrace_symbols_fmt(array, size, "%n");
134 bool found_handler = false;
135 bool found_sigtramp = false;
136 bool found_the_loop = false;
137 bool found_main = false;
138 size_t i;
139
140 /*
141 * We must find the symbols in the following order:
142 *
143 * handler -> __sigtramp_siginfo_* -> the_loop -> main
144 */
145 for (i = 0; i < size; i++) {
146 if (!found_handler &&
147 strcmp(strings[i], "handler") == 0) {
148 found_handler = true;
149 continue;
150 }
151 if (found_handler && !found_sigtramp &&
152 strncmp(strings[i], "__sigtramp_siginfo_",
153 strlen("__sigtramp_siginfo_")) == 0) {
154 found_sigtramp = true;
155 continue;
156 }
157 if (found_sigtramp && !found_the_loop &&
158 strncmp(strings[i], "the_loop", strlen("the_loop")) == 0) {
159 found_the_loop = true;
160 continue;
161 }
162 if (found_the_loop && !found_main &&
163 strcmp(strings[i], "atf_tp_main") == 0) {
164 found_main = true;
165 break;
166 }
167 }
168
169 ATF_REQUIRE(found_handler);
170 ATF_REQUIRE(found_sigtramp);
171 ATF_REQUIRE(found_the_loop);
172 ATF_REQUIRE(found_main);
173
174 longjmp(env, 1);
175 }
176
177 ATF_TC(sig_backtrace_deref);
178 ATF_TC_HEAD(sig_backtrace_deref, tc)
179 {
180 atf_tc_set_md_var(tc, "descr",
181 "Test backtrace(3) across signal handlers, null pointer deref");
182 }
183
184 ATF_TC_BODY(sig_backtrace_deref, tc)
185 {
186 sig_stack.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
187 MAP_ANON | MAP_STACK, -1, 0);
188 ATF_REQUIRE(sig_stack.ss_sp != MAP_FAILED);
189
190 sig_stack.ss_size = SIGSTKSZ;
191 sig_stack.ss_flags = 0;
192 ATF_REQUIRE(sigaltstack(&sig_stack, NULL) == 0);
193
194 struct sigaction sa = {
195 .sa_handler = handler,
196 .sa_flags = SA_ONSTACK,
197 };
198 ATF_REQUIRE(sigaction(SIGSEGV, &sa, NULL) == 0);
199
200 if (setjmp(env) == 0) {
201 printf("%d\n", the_loop_deref(0));
202 }
203 }
204
205 ATF_TC(sig_backtrace_jump);
206 ATF_TC_HEAD(sig_backtrace_jump, tc)
207 {
208 atf_tc_set_md_var(tc, "descr",
209 "Test backtrace(3) across signal handlers, null pointer jump");
210 }
211
212 ATF_TC_BODY(sig_backtrace_jump, tc)
213 {
214 sig_stack.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
215 MAP_ANON | MAP_STACK, -1, 0);
216 ATF_REQUIRE(sig_stack.ss_sp != MAP_FAILED);
217
218 sig_stack.ss_size = SIGSTKSZ;
219 sig_stack.ss_flags = 0;
220 ATF_REQUIRE(sigaltstack(&sig_stack, NULL) == 0);
221
222 struct sigaction sa = {
223 .sa_handler = handler,
224 .sa_flags = SA_ONSTACK,
225 };
226 ATF_REQUIRE(sigaction(SIGSEGV, &sa, NULL) == 0);
227
228 atf_tc_expect_fail("PR lib/56940");
229
230 if (setjmp(env) == 0) {
231 printf("%d\n", the_loop_jump(0));
232 }
233 }
234
235 ATF_TP_ADD_TCS(tp)
236 {
237 ATF_TP_ADD_TC(tp, sig_backtrace_deref);
238 ATF_TP_ADD_TC(tp, sig_backtrace_jump);
239
240 return atf_no_error();
241 }
242