1*7d87cccbSriastradh /* $NetBSD: t_sig_backtrace.c,v 1.7 2023/07/06 20:44:55 riastradh Exp $ */
24ae1bf14Sthorpej
34ae1bf14Sthorpej /*-
44ae1bf14Sthorpej * Copyright (c) 2021 The NetBSD Foundation, Inc.
54ae1bf14Sthorpej * All rights reserved.
64ae1bf14Sthorpej *
74ae1bf14Sthorpej * This code is derived from software contributed to The NetBSD Foundation
84ae1bf14Sthorpej * by Jason R. Thorpe.
94ae1bf14Sthorpej *
104ae1bf14Sthorpej * Redistribution and use in source and binary forms, with or without
114ae1bf14Sthorpej * modification, are permitted provided that the following conditions
124ae1bf14Sthorpej * are met:
134ae1bf14Sthorpej * 1. Redistributions of source code must retain the above copyright
144ae1bf14Sthorpej * notice, this list of conditions and the following disclaimer.
154ae1bf14Sthorpej * 2. Redistributions in binary form must reproduce the above copyright
164ae1bf14Sthorpej * notice, this list of conditions and the following disclaimer in the
174ae1bf14Sthorpej * documentation and/or other materials provided with the distribution.
184ae1bf14Sthorpej *
194ae1bf14Sthorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
204ae1bf14Sthorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
214ae1bf14Sthorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
224ae1bf14Sthorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
234ae1bf14Sthorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
244ae1bf14Sthorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
254ae1bf14Sthorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
264ae1bf14Sthorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
274ae1bf14Sthorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
284ae1bf14Sthorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
294ae1bf14Sthorpej * POSSIBILITY OF SUCH DAMAGE.
304ae1bf14Sthorpej */
314ae1bf14Sthorpej
324ae1bf14Sthorpej #include <sys/cdefs.h>
33*7d87cccbSriastradh __RCSID("$NetBSD: t_sig_backtrace.c,v 1.7 2023/07/06 20:44:55 riastradh Exp $");
344ae1bf14Sthorpej
354ae1bf14Sthorpej #include <sys/mman.h>
364ae1bf14Sthorpej #include <execinfo.h>
374ae1bf14Sthorpej #include <setjmp.h>
384ae1bf14Sthorpej #include <stdbool.h>
394ae1bf14Sthorpej #include <signal.h>
404ae1bf14Sthorpej #include <stdio.h>
414ae1bf14Sthorpej #include <stddef.h>
424ae1bf14Sthorpej #include <stdlib.h>
434ae1bf14Sthorpej #include <string.h>
444ae1bf14Sthorpej #include <unistd.h>
454ae1bf14Sthorpej
464ae1bf14Sthorpej #include <atf-c.h>
474ae1bf14Sthorpej
484ae1bf14Sthorpej stack_t sig_stack;
494ae1bf14Sthorpej
504ae1bf14Sthorpej char *foo;
5103353bf4Sriastradh char *(*bar)(void);
524ae1bf14Sthorpej
5303353bf4Sriastradh static int the_loop_deref(int);
5403353bf4Sriastradh static int the_loop_jump(int);
554ae1bf14Sthorpej
56f5f80c07Sthorpej #ifdef NOINLINE_HACK
57f5f80c07Sthorpej volatile int noinline;
58f5f80c07Sthorpej #endif
59f5f80c07Sthorpej
604ae1bf14Sthorpej static int __noinline
func1(int i)614ae1bf14Sthorpej func1(int i)
624ae1bf14Sthorpej {
634ae1bf14Sthorpej if (i > 100) {
6403353bf4Sriastradh return the_loop_deref(i);
654ae1bf14Sthorpej }
664ae1bf14Sthorpej return i + 1;
674ae1bf14Sthorpej }
684ae1bf14Sthorpej
694ae1bf14Sthorpej static int __noinline
func2(int i)704ae1bf14Sthorpej func2(int i)
714ae1bf14Sthorpej {
724ae1bf14Sthorpej return func1(i) << 1;
734ae1bf14Sthorpej }
744ae1bf14Sthorpej
754ae1bf14Sthorpej static int __noinline
func3(int i)764ae1bf14Sthorpej func3(int i)
774ae1bf14Sthorpej {
784ae1bf14Sthorpej if (func1(i) < 10) {
794ae1bf14Sthorpej return func2(i);
804ae1bf14Sthorpej } else {
814ae1bf14Sthorpej return func1(i);
824ae1bf14Sthorpej }
834ae1bf14Sthorpej }
844ae1bf14Sthorpej
854ae1bf14Sthorpej static int __noinline
the_loop_deref(int i0)869f0a763cSriastradh the_loop_deref(int i0)
874ae1bf14Sthorpej {
889f0a763cSriastradh volatile int i = i0;
899f0a763cSriastradh
904ae1bf14Sthorpej while (*foo != 0) {
914ae1bf14Sthorpej i = func3(i);
924ae1bf14Sthorpej i = func1(i);
934ae1bf14Sthorpej i = func2(i);
944ae1bf14Sthorpej }
954ae1bf14Sthorpej
96f5f80c07Sthorpej #ifdef NOINLINE_HACK
97f5f80c07Sthorpej if (noinline)
98f5f80c07Sthorpej vfork();
99f5f80c07Sthorpej #endif
100f5f80c07Sthorpej
1014ae1bf14Sthorpej return i;
1024ae1bf14Sthorpej }
1034ae1bf14Sthorpej
10403353bf4Sriastradh static int __noinline
the_loop_jump(int i0)1059f0a763cSriastradh the_loop_jump(int i0)
10603353bf4Sriastradh {
1079f0a763cSriastradh volatile int i = i0;
1089f0a763cSriastradh
10903353bf4Sriastradh while ((*bar)() != 0) {
11003353bf4Sriastradh i = func3(i);
11103353bf4Sriastradh i = func1(i);
11203353bf4Sriastradh i = func2(i);
11303353bf4Sriastradh }
11403353bf4Sriastradh
11503353bf4Sriastradh #ifdef NOINLINE_HACK
11603353bf4Sriastradh if (noinline)
11703353bf4Sriastradh vfork();
11803353bf4Sriastradh #endif
11903353bf4Sriastradh
12003353bf4Sriastradh return i;
12103353bf4Sriastradh }
12203353bf4Sriastradh
1234ae1bf14Sthorpej jmp_buf env;
1244ae1bf14Sthorpej
1254ae1bf14Sthorpej static void
handler(int s)1264ae1bf14Sthorpej handler(int s)
1274ae1bf14Sthorpej {
1284ae1bf14Sthorpej printf("signal: %d\n", s);
1294ae1bf14Sthorpej
1304ae1bf14Sthorpej void *array[10];
1314ae1bf14Sthorpej size_t size = backtrace(array, 10);
1324ae1bf14Sthorpej ATF_REQUIRE(size != 0);
1334ae1bf14Sthorpej
1344ae1bf14Sthorpej printf("Backtrace %zd stack frames.\n", size);
135*7d87cccbSriastradh fflush(stdout);
1364ae1bf14Sthorpej backtrace_symbols_fd(array, size, STDOUT_FILENO);
1374ae1bf14Sthorpej
1384ae1bf14Sthorpej char **strings = backtrace_symbols_fmt(array, size, "%n");
1394ae1bf14Sthorpej bool found_handler = false;
1404ae1bf14Sthorpej bool found_sigtramp = false;
1414ae1bf14Sthorpej bool found_the_loop = false;
1424ae1bf14Sthorpej bool found_main = false;
1434ae1bf14Sthorpej size_t i;
1444ae1bf14Sthorpej
1454ae1bf14Sthorpej /*
1464ae1bf14Sthorpej * We must find the symbols in the following order:
1474ae1bf14Sthorpej *
1484ae1bf14Sthorpej * handler -> __sigtramp_siginfo_* -> the_loop -> main
1494ae1bf14Sthorpej */
1504ae1bf14Sthorpej for (i = 0; i < size; i++) {
1514ae1bf14Sthorpej if (!found_handler &&
1524ae1bf14Sthorpej strcmp(strings[i], "handler") == 0) {
1534ae1bf14Sthorpej found_handler = true;
1544ae1bf14Sthorpej continue;
1554ae1bf14Sthorpej }
1564ae1bf14Sthorpej if (found_handler && !found_sigtramp &&
1574ae1bf14Sthorpej strncmp(strings[i], "__sigtramp_siginfo_",
1584ae1bf14Sthorpej strlen("__sigtramp_siginfo_")) == 0) {
1594ae1bf14Sthorpej found_sigtramp = true;
1604ae1bf14Sthorpej continue;
1614ae1bf14Sthorpej }
1624ae1bf14Sthorpej if (found_sigtramp && !found_the_loop &&
163d14f9f01Sriastradh strncmp(strings[i], "the_loop", strlen("the_loop")) == 0) {
1644ae1bf14Sthorpej found_the_loop = true;
1654ae1bf14Sthorpej continue;
1664ae1bf14Sthorpej }
1674ae1bf14Sthorpej if (found_the_loop && !found_main &&
1684ae1bf14Sthorpej strcmp(strings[i], "atf_tp_main") == 0) {
1694ae1bf14Sthorpej found_main = true;
1704ae1bf14Sthorpej break;
1714ae1bf14Sthorpej }
1724ae1bf14Sthorpej }
1734ae1bf14Sthorpej
1744ae1bf14Sthorpej ATF_REQUIRE(found_handler);
1754ae1bf14Sthorpej ATF_REQUIRE(found_sigtramp);
1764ae1bf14Sthorpej ATF_REQUIRE(found_the_loop);
1774ae1bf14Sthorpej ATF_REQUIRE(found_main);
1784ae1bf14Sthorpej
1794ae1bf14Sthorpej longjmp(env, 1);
1804ae1bf14Sthorpej }
1814ae1bf14Sthorpej
18203353bf4Sriastradh ATF_TC(sig_backtrace_deref);
ATF_TC_HEAD(sig_backtrace_deref,tc)18303353bf4Sriastradh ATF_TC_HEAD(sig_backtrace_deref, tc)
1844ae1bf14Sthorpej {
1854ae1bf14Sthorpej atf_tc_set_md_var(tc, "descr",
18603353bf4Sriastradh "Test backtrace(3) across signal handlers, null pointer deref");
1874ae1bf14Sthorpej }
1884ae1bf14Sthorpej
ATF_TC_BODY(sig_backtrace_deref,tc)18903353bf4Sriastradh ATF_TC_BODY(sig_backtrace_deref, tc)
1904ae1bf14Sthorpej {
1914ae1bf14Sthorpej sig_stack.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
1924ae1bf14Sthorpej MAP_ANON | MAP_STACK, -1, 0);
1934ae1bf14Sthorpej ATF_REQUIRE(sig_stack.ss_sp != MAP_FAILED);
1944ae1bf14Sthorpej
1954ae1bf14Sthorpej sig_stack.ss_size = SIGSTKSZ;
1964ae1bf14Sthorpej sig_stack.ss_flags = 0;
1974ae1bf14Sthorpej ATF_REQUIRE(sigaltstack(&sig_stack, NULL) == 0);
1984ae1bf14Sthorpej
1994ae1bf14Sthorpej struct sigaction sa = {
2004ae1bf14Sthorpej .sa_handler = handler,
2014ae1bf14Sthorpej .sa_flags = SA_ONSTACK,
2024ae1bf14Sthorpej };
2034ae1bf14Sthorpej ATF_REQUIRE(sigaction(SIGSEGV, &sa, NULL) == 0);
2044ae1bf14Sthorpej
2054ae1bf14Sthorpej if (setjmp(env) == 0) {
20603353bf4Sriastradh printf("%d\n", the_loop_deref(0));
20703353bf4Sriastradh }
20803353bf4Sriastradh }
20903353bf4Sriastradh
21003353bf4Sriastradh ATF_TC(sig_backtrace_jump);
ATF_TC_HEAD(sig_backtrace_jump,tc)21103353bf4Sriastradh ATF_TC_HEAD(sig_backtrace_jump, tc)
21203353bf4Sriastradh {
21303353bf4Sriastradh atf_tc_set_md_var(tc, "descr",
21403353bf4Sriastradh "Test backtrace(3) across signal handlers, null pointer jump");
21503353bf4Sriastradh }
21603353bf4Sriastradh
ATF_TC_BODY(sig_backtrace_jump,tc)21703353bf4Sriastradh ATF_TC_BODY(sig_backtrace_jump, tc)
21803353bf4Sriastradh {
21903353bf4Sriastradh sig_stack.ss_sp = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE,
22003353bf4Sriastradh MAP_ANON | MAP_STACK, -1, 0);
22103353bf4Sriastradh ATF_REQUIRE(sig_stack.ss_sp != MAP_FAILED);
22203353bf4Sriastradh
22303353bf4Sriastradh sig_stack.ss_size = SIGSTKSZ;
22403353bf4Sriastradh sig_stack.ss_flags = 0;
22503353bf4Sriastradh ATF_REQUIRE(sigaltstack(&sig_stack, NULL) == 0);
22603353bf4Sriastradh
22703353bf4Sriastradh struct sigaction sa = {
22803353bf4Sriastradh .sa_handler = handler,
22903353bf4Sriastradh .sa_flags = SA_ONSTACK,
23003353bf4Sriastradh };
23103353bf4Sriastradh ATF_REQUIRE(sigaction(SIGSEGV, &sa, NULL) == 0);
23203353bf4Sriastradh
2332edbbc6fSriastradh atf_tc_expect_fail("PR lib/56940");
2342edbbc6fSriastradh
23503353bf4Sriastradh if (setjmp(env) == 0) {
23603353bf4Sriastradh printf("%d\n", the_loop_jump(0));
2374ae1bf14Sthorpej }
2384ae1bf14Sthorpej }
2394ae1bf14Sthorpej
ATF_TP_ADD_TCS(tp)2404ae1bf14Sthorpej ATF_TP_ADD_TCS(tp)
2414ae1bf14Sthorpej {
24203353bf4Sriastradh ATF_TP_ADD_TC(tp, sig_backtrace_deref);
24303353bf4Sriastradh ATF_TP_ADD_TC(tp, sig_backtrace_jump);
2444ae1bf14Sthorpej
2454ae1bf14Sthorpej return atf_no_error();
2464ae1bf14Sthorpej }
247