xref: /netbsd-src/tests/lib/libexecinfo/t_sig_backtrace.c (revision 7d87cccbb2013803bdc670585e30cded33791d4d)
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