1*d5e6e0f5Suwe /* $NetBSD: t_sigstack.c,v 1.12 2024/07/17 07:11:57 uwe Exp $ */ 2a7b03376Sriastradh 3a7b03376Sriastradh /*- 4a7b03376Sriastradh * Copyright (c) 2024 The NetBSD Foundation, Inc. 5a7b03376Sriastradh * All rights reserved. 6a7b03376Sriastradh * 7a7b03376Sriastradh * Redistribution and use in source and binary forms, with or without 8a7b03376Sriastradh * modification, are permitted provided that the following conditions 9a7b03376Sriastradh * are met: 10a7b03376Sriastradh * 1. Redistributions of source code must retain the above copyright 11a7b03376Sriastradh * notice, this list of conditions and the following disclaimer. 12a7b03376Sriastradh * 2. Redistributions in binary form must reproduce the above copyright 13a7b03376Sriastradh * notice, this list of conditions and the following disclaimer in the 14a7b03376Sriastradh * documentation and/or other materials provided with the distribution. 15a7b03376Sriastradh * 16a7b03376Sriastradh * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17a7b03376Sriastradh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18a7b03376Sriastradh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19a7b03376Sriastradh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20a7b03376Sriastradh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21a7b03376Sriastradh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22a7b03376Sriastradh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23a7b03376Sriastradh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24a7b03376Sriastradh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25a7b03376Sriastradh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26a7b03376Sriastradh * POSSIBILITY OF SUCH DAMAGE. 27a7b03376Sriastradh */ 28a7b03376Sriastradh 29a7b03376Sriastradh #include <sys/cdefs.h> 30*d5e6e0f5Suwe __RCSID("$NetBSD: t_sigstack.c,v 1.12 2024/07/17 07:11:57 uwe Exp $"); 31a7b03376Sriastradh 32a7b03376Sriastradh #include <setjmp.h> 33a7b03376Sriastradh #include <signal.h> 34a7b03376Sriastradh #include <stddef.h> 35a7b03376Sriastradh #include <stdlib.h> 36a7b03376Sriastradh #include <ucontext.h> 37a7b03376Sriastradh 38a7b03376Sriastradh #include "h_macros.h" 39a7b03376Sriastradh 409ba2d744Sriastradh struct sigaltstack ss[3]; 41a7b03376Sriastradh jmp_buf jmp; 423026ea48Sriastradh sigjmp_buf sigjmp; 43a7b03376Sriastradh unsigned nentries; 443026ea48Sriastradh const char *bailname; 453026ea48Sriastradh void (*bailfn)(void) __dead; 46a7b03376Sriastradh 47a7b03376Sriastradh static void 48a7b03376Sriastradh on_sigusr1(int signo, siginfo_t *si, void *ctx) 49a7b03376Sriastradh { 50a7b03376Sriastradh ucontext_t *uc = ctx; 51a7b03376Sriastradh void *sp = (void *)(uintptr_t)_UC_MACHINE_SP(uc); 52a7b03376Sriastradh void *fp = __builtin_frame_address(0); 539ba2d744Sriastradh struct sigaltstack *ssp; 549ba2d744Sriastradh 559ba2d744Sriastradh /* 569ba2d744Sriastradh * Ensure we haven't re-entered the signal handler too many 579ba2d744Sriastradh * times. We should enter only twice. 589ba2d744Sriastradh */ 599ba2d744Sriastradh ATF_REQUIRE_MSG(nentries < 2, 609ba2d744Sriastradh "%u recursive signal handler entries is too many in this test", 619ba2d744Sriastradh nentries + 1); 62a7b03376Sriastradh 63a7b03376Sriastradh /* 64a7b03376Sriastradh * Ensure that the signal handler was called in the alternate 65a7b03376Sriastradh * signal stack. 66a7b03376Sriastradh */ 679ba2d744Sriastradh ssp = &ss[nentries]; 689ba2d744Sriastradh ATF_REQUIRE_MSG((fp >= ssp->ss_sp && 699ba2d744Sriastradh fp < (void *)((char *)ssp->ss_sp + ssp->ss_size)), 702bb61943Sriastradh "sigaltstack failed to take effect on entry %u --" 71a7b03376Sriastradh " signal handler's frame pointer %p doesn't lie in sigaltstack" 72a7b03376Sriastradh " [%p, %p), size 0x%zx", 732bb61943Sriastradh nentries, 749ba2d744Sriastradh fp, ssp->ss_sp, (char *)ssp->ss_sp + ssp->ss_size, ssp->ss_size); 75a7b03376Sriastradh 76a7b03376Sriastradh /* 77a7b03376Sriastradh * Ensure that if we enter the signal handler, we are entering 789ba2d744Sriastradh * it from the original stack, not from any of the alternate 799ba2d744Sriastradh * signal stacks. 80a7b03376Sriastradh * 81a7b03376Sriastradh * On some architectures, this is broken. Those that appear to 82a7b03376Sriastradh * get this right are: 83a7b03376Sriastradh * 843e7604f6Sriastradh * aarch64 853e7604f6Sriastradh * alpha 86e21ed88eSriastradh * arm 873e7604f6Sriastradh * i386 883e7604f6Sriastradh * m68k 893e7604f6Sriastradh * or1k 903e7604f6Sriastradh * powerpc 913e7604f6Sriastradh * powerpc64 923e7604f6Sriastradh * riscv 933e7604f6Sriastradh * vax 943e7604f6Sriastradh * x86_64 95a7b03376Sriastradh */ 96d2c36e3eSskrll #if defined __hppa__ || \ 97*d5e6e0f5Suwe defined __ia64__ || defined __mips__ || \ 98df443a3dSriastradh defined __sparc__ || defined __sparc64__ 99a7b03376Sriastradh if (nentries > 0) 100a7b03376Sriastradh atf_tc_expect_fail("PR lib/57946"); 101a7b03376Sriastradh #endif 1029ba2d744Sriastradh for (ssp = &ss[0]; ssp < &ss[__arraycount(ss)]; ssp++) { 1039ba2d744Sriastradh ATF_REQUIRE_MSG((sp < ssp->ss_sp || 1043dfc2808Sriastradh sp >= (void *)((char *)ssp->ss_sp + ssp->ss_size)), 1059ba2d744Sriastradh "%s failed to restore stack" 1069ba2d744Sriastradh " before allowing signal on entry %u --" 1079ba2d744Sriastradh " interrupted stack pointer %p lies in sigaltstack %zd" 108a7b03376Sriastradh " [%p, %p), size 0x%zx", 1099ba2d744Sriastradh bailname, 1102bb61943Sriastradh nentries, 1119ba2d744Sriastradh sp, ssp - ss, 1129ba2d744Sriastradh ssp->ss_sp, (char *)ssp->ss_sp + ssp->ss_size, 1139ba2d744Sriastradh ssp->ss_size); 1149ba2d744Sriastradh } 115a7b03376Sriastradh 116a7b03376Sriastradh /* 117a7b03376Sriastradh * First time through, we want to test whether longjmp restores 118a7b03376Sriastradh * the signal mask first, or restores the stack pointer first. 119a7b03376Sriastradh * The signal should be blocked at this point, so we re-raise 120a7b03376Sriastradh * the signal to queue it up for delivery as soon as it is 121a7b03376Sriastradh * unmasked -- which should wait until the stack pointer has 122a7b03376Sriastradh * been restored in longjmp. 123a7b03376Sriastradh */ 124a7b03376Sriastradh if (nentries++ == 0) 125a7b03376Sriastradh RL(raise(SIGUSR1)); 126a7b03376Sriastradh 127a7b03376Sriastradh /* 1289ba2d744Sriastradh * Set up the next sigaltstack. We can't reuse the current one 1299ba2d744Sriastradh * for the next signal handler re-entry until the system clears 1309ba2d744Sriastradh * the SS_ONSTACK process state -- which normal return from 1319ba2d744Sriastradh * signal handler does, but which longjmp does not. So to keep 1329ba2d744Sriastradh * it simple (ha), we just use another sigaltstack. 1339ba2d744Sriastradh */ 1349ba2d744Sriastradh RL(sigaltstack(&ss[nentries], NULL)); 1359ba2d744Sriastradh 1369ba2d744Sriastradh /* 137a7b03376Sriastradh * Jump back to the original context. 138a7b03376Sriastradh */ 1393026ea48Sriastradh (*bailfn)(); 140a7b03376Sriastradh } 141a7b03376Sriastradh 1423026ea48Sriastradh static void 1433026ea48Sriastradh go(const char *name, void (*fn)(void) __dead) 144a7b03376Sriastradh { 145a7b03376Sriastradh struct sigaction sa; 1469ba2d744Sriastradh unsigned i; 147a7b03376Sriastradh 1483026ea48Sriastradh bailname = name; 1493026ea48Sriastradh bailfn = fn; 1503026ea48Sriastradh 151a7b03376Sriastradh /* 152a7b03376Sriastradh * Allocate a stack for the signal handler to run in, and 1539ba2d744Sriastradh * configure the system to use the first one. 154a7b03376Sriastradh * 155a7b03376Sriastradh * XXX Should maybe use a guard page but this is simpler. 156a7b03376Sriastradh */ 1579ba2d744Sriastradh for (i = 0; i < __arraycount(ss); i++) { 1589ba2d744Sriastradh ss[i].ss_size = SIGSTKSZ; 1599ba2d744Sriastradh REQUIRE_LIBC(ss[i].ss_sp = malloc(ss[i].ss_size), NULL); 1609ba2d744Sriastradh } 1619ba2d744Sriastradh RL(sigaltstack(&ss[0], NULL)); 162a7b03376Sriastradh 163a7b03376Sriastradh /* 164a7b03376Sriastradh * Set up a test signal handler for SIGUSR1. Allow all 165a7b03376Sriastradh * signals, except SIGUSR1 (which is masked by default) -- that 166a7b03376Sriastradh * way we don't inadvertently obscure weird crashes in the 167a7b03376Sriastradh * signal handler. 168a7b03376Sriastradh * 169a7b03376Sriastradh * Set SA_SIGINFO so the system will pass siginfo -- and, more 170a7b03376Sriastradh * to the point, ucontext, so the signal handler can determine 171a7b03376Sriastradh * the stack pointer of the logic it interrupted. 172a7b03376Sriastradh * 173a7b03376Sriastradh * Set SA_ONSTACK so the system will use the alternate signal 174a7b03376Sriastradh * stack to call the signal handler -- that way, it can tell 175a7b03376Sriastradh * whether the stack was restored before the second time 176a7b03376Sriastradh * around. 177a7b03376Sriastradh */ 178a7b03376Sriastradh memset(&sa, 0, sizeof(sa)); 179a7b03376Sriastradh sa.sa_sigaction = &on_sigusr1; 1806514aab6Sriastradh RL(sigemptyset(&sa.sa_mask)); 181a7b03376Sriastradh sa.sa_flags = SA_SIGINFO|SA_ONSTACK; 182a7b03376Sriastradh RL(sigaction(SIGUSR1, &sa, NULL)); 183a7b03376Sriastradh 184a7b03376Sriastradh /* 185a7b03376Sriastradh * Raise the signal to enter the signal handler the first time. 186a7b03376Sriastradh */ 1876514aab6Sriastradh RL(raise(SIGUSR1)); 188a7b03376Sriastradh 189a7b03376Sriastradh /* 190a7b03376Sriastradh * If we ever reach this point, something went seriously wrong. 191a7b03376Sriastradh */ 192a7b03376Sriastradh atf_tc_fail("unreachable"); 193a7b03376Sriastradh } 194a7b03376Sriastradh 1953026ea48Sriastradh static void __dead 1963026ea48Sriastradh bail_longjmp(void) 1973026ea48Sriastradh { 1983026ea48Sriastradh 1993026ea48Sriastradh longjmp(jmp, 1); 2003026ea48Sriastradh } 2013026ea48Sriastradh 2023026ea48Sriastradh ATF_TC(setjmp); 2033026ea48Sriastradh ATF_TC_HEAD(setjmp, tc) 2043026ea48Sriastradh { 2053026ea48Sriastradh atf_tc_set_md_var(tc, "descr", 2063026ea48Sriastradh "Test longjmp restores stack first, then signal mask"); 2073026ea48Sriastradh } 2083026ea48Sriastradh ATF_TC_BODY(setjmp, tc) 2093026ea48Sriastradh { 2103026ea48Sriastradh 2113026ea48Sriastradh /* 2123026ea48Sriastradh * Set up a return point for the signal handler: when the 2133026ea48Sriastradh * signal handler does longjmp(jmp, 1), it comes flying out of 2143026ea48Sriastradh * here. 2153026ea48Sriastradh */ 2163026ea48Sriastradh if (setjmp(jmp) == 1) 2173026ea48Sriastradh return; 2183026ea48Sriastradh 2193026ea48Sriastradh /* 2203026ea48Sriastradh * Run the test with longjmp. 2213026ea48Sriastradh */ 2223026ea48Sriastradh go("longjmp", &bail_longjmp); 2233026ea48Sriastradh } 2243026ea48Sriastradh 2253026ea48Sriastradh static void __dead 2263026ea48Sriastradh bail_siglongjmp(void) 2273026ea48Sriastradh { 2283026ea48Sriastradh 2293026ea48Sriastradh siglongjmp(sigjmp, 1); 2303026ea48Sriastradh } 2313026ea48Sriastradh 2323026ea48Sriastradh ATF_TC(sigsetjmp); 2333026ea48Sriastradh ATF_TC_HEAD(sigsetjmp, tc) 2343026ea48Sriastradh { 2353026ea48Sriastradh atf_tc_set_md_var(tc, "descr", 2363026ea48Sriastradh "Test siglongjmp restores stack first, then signal mask"); 2373026ea48Sriastradh } 2383026ea48Sriastradh ATF_TC_BODY(sigsetjmp, tc) 2393026ea48Sriastradh { 2403026ea48Sriastradh 2413026ea48Sriastradh /* 2423026ea48Sriastradh * Set up a return point for the signal handler: when the 2433026ea48Sriastradh * signal handler does siglongjmp(sigjmp, 1), it comes flying 2443026ea48Sriastradh * out of here. 2453026ea48Sriastradh */ 2463026ea48Sriastradh if (sigsetjmp(sigjmp, /*savesigmask*/1) == 1) 2473026ea48Sriastradh return; 2483026ea48Sriastradh 2493026ea48Sriastradh /* 2503026ea48Sriastradh * Run the test with siglongjmp. 2513026ea48Sriastradh */ 2523026ea48Sriastradh go("siglongjmp", &bail_siglongjmp); 2533026ea48Sriastradh } 2543026ea48Sriastradh 255a7b03376Sriastradh ATF_TP_ADD_TCS(tp) 256a7b03376Sriastradh { 257a7b03376Sriastradh 258a7b03376Sriastradh ATF_TP_ADD_TC(tp, setjmp); 2593026ea48Sriastradh ATF_TP_ADD_TC(tp, sigsetjmp); 260a7b03376Sriastradh 261a7b03376Sriastradh return atf_no_error(); 262a7b03376Sriastradh } 263