1 /* $NetBSD: t_ptrace_sigchld.c,v 1.7 2025/05/02 02:37:07 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2020 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __RCSID("$NetBSD: t_ptrace_sigchld.c,v 1.7 2025/05/02 02:37:07 riastradh Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/types.h> 34 #include <sys/exec_elf.h> 35 #include <sys/mman.h> 36 #include <sys/ptrace.h> 37 #include <sys/resource.h> 38 #include <sys/stat.h> 39 #include <sys/syscall.h> 40 #include <sys/sysctl.h> 41 #include <sys/uio.h> 42 #include <sys/wait.h> 43 #include <machine/reg.h> 44 #include <assert.h> 45 #include <elf.h> 46 #include <err.h> 47 #include <errno.h> 48 #include <fcntl.h> 49 #include <lwp.h> 50 #include <pthread.h> 51 #include <sched.h> 52 #include <signal.h> 53 #include <spawn.h> 54 #include <stdint.h> 55 #include <stdio.h> 56 #include <stdlib.h> 57 #include <strings.h> 58 #include <time.h> 59 #include <unistd.h> 60 61 #include <atf-c.h> 62 63 #include "h_macros.h" 64 #include "msg.h" 65 66 #include "t_ptrace_wait.h" 67 68 #define SYSCALL_REQUIRE(expr) ATF_REQUIRE_MSG(expr, "%s: %s", # expr, \ 69 strerror(errno)) 70 #define SYSCALL_REQUIRE_ERRNO(res, exp) ATF_REQUIRE_MSG(res == exp, \ 71 "%d(%s) != %d", res, strerror(res), exp) 72 73 static int debug = 0; 74 75 #define DPRINTF(a, ...) do \ 76 if (debug) { \ 77 const char *file = __FILE__, *slash = strrchr(file, '/'); \ 78 if (slash) \ 79 file = slash + 1; \ 80 printf("%s() %d.%d %s:%d " a, \ 81 __func__, getpid(), _lwp_self(), file, __LINE__, \ 82 ##__VA_ARGS__); \ 83 } \ 84 while (/*CONSTCOND*/0) 85 86 /// ---------------------------------------------------------------------------- 87 88 static int expected_signo; 89 static int expected_code; 90 static int expected_status; 91 static pid_t expected_pid; 92 93 static void 94 sigchld_action(int sig, siginfo_t *info, void *ctx) 95 { 96 97 FORKEE_ASSERT_EQ(info->si_signo, expected_signo); 98 FORKEE_ASSERT_EQ(info->si_code, expected_code); 99 FORKEE_ASSERT_EQ(info->si_uid, getuid()); 100 FORKEE_ASSERT_EQ(info->si_pid, expected_pid); 101 102 if (WIFEXITED(info->si_status)) 103 ATF_REQUIRE_EQ(WEXITSTATUS(info->si_status), expected_status); 104 else if (WIFSTOPPED(info->si_status)) 105 ATF_REQUIRE_EQ(WSTOPSIG(info->si_status), expected_status); 106 else if (WIFSIGNALED(info->si_status)) 107 ATF_REQUIRE_EQ(WTERMSIG(info->si_status), expected_status); 108 /* 109 else if (WIFCONTINUED(info->si_status)) 110 ; 111 */ 112 } 113 114 static void 115 traceme_raise(int sigval) 116 { 117 const int exitval = 5; 118 struct sigaction sa; 119 pid_t child; 120 struct msg_fds parent_child; 121 uint8_t msg = 0xde; /* dummy message for IPC based on pipe(2) */ 122 123 struct ptrace_siginfo info; 124 memset(&info, 0, sizeof(info)); 125 126 memset(&sa, 0, sizeof(sa)); 127 sa.sa_sigaction = sigchld_action; 128 sa.sa_flags = SA_SIGINFO | SA_NOCLDWAIT; 129 sigemptyset(&sa.sa_mask); 130 131 atf_tc_skip("XXX: zombie is not collected before tracer's death"); 132 133 SYSCALL_REQUIRE(sigaction(SIGCHLD, &sa, NULL) == 0); 134 135 SYSCALL_REQUIRE(msg_open(&parent_child) == 0); 136 137 DPRINTF("Before forking process PID=%d\n", getpid()); 138 SYSCALL_REQUIRE((child = fork()) != -1); 139 if (child == 0) { 140 DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); 141 FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); 142 143 CHILD_FROM_PARENT("raise1 child", parent_child, msg); 144 145 raise(sigval); 146 147 CHILD_TO_PARENT("raise2 child", parent_child, msg); 148 149 switch (sigval) { 150 case SIGKILL: 151 /* NOTREACHED */ 152 FORKEE_ASSERTX(0 && "This shall not be reached"); 153 __unreachable(); 154 default: 155 DPRINTF("Before exiting of the child process\n"); 156 _exit(exitval); 157 } 158 } 159 DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child); 160 161 expected_signo = SIGCHLD; 162 expected_pid = child; 163 switch (sigval) { 164 case SIGKILL: 165 expected_code = CLD_KILLED; 166 expected_status = SIGKILL; 167 break; 168 case SIGSTOP: 169 expected_code = CLD_STOPPED; 170 expected_status = SIGSTOP; 171 break; 172 default: 173 break; 174 } 175 176 PARENT_TO_CHILD("raise1 child", parent_child, msg); 177 178 switch (sigval) { 179 case SIGKILL: 180 break; 181 default: 182 PARENT_FROM_CHILD("raise2 child", parent_child, msg); 183 184 DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for " 185 "child\n"); 186 SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, 187 sizeof(info)) != -1); 188 189 DPRINTF("Signal traced to lwpid=%d\n", info.psi_lwpid); 190 DPRINTF("Signal properties: si_signo=%#x si_code=%#x " 191 "si_errno=%#x\n", 192 info.psi_siginfo.si_signo, info.psi_siginfo.si_code, 193 info.psi_siginfo.si_errno); 194 195 ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, sigval); 196 ATF_REQUIRE_EQ(info.psi_siginfo.si_code, SI_LWP); 197 198 expected_code = CLD_EXITED; 199 expected_status = exitval; 200 201 SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0)); 202 203 break; 204 } 205 206 await_collected(child); /* XXX: Process is never collected */ 207 } 208 209 #define TRACEME_RAISE(test, sig) \ 210 ATF_TC(test); \ 211 ATF_TC_HEAD(test, tc) \ 212 { \ 213 atf_tc_set_md_var(tc, "descr", \ 214 "Verify " #sig " followed by _exit(2) in a child"); \ 215 atf_tc_set_md_var(tc, "timeout", "10"); \ 216 } \ 217 \ 218 ATF_TC_BODY(test, tc) \ 219 { \ 220 \ 221 traceme_raise(sig); \ 222 } 223 224 TRACEME_RAISE(traceme_raise1, SIGKILL) /* non-maskable */ 225 #if notyet 226 TRACEME_RAISE(traceme_raise2, SIGSTOP) /* non-maskable */ 227 TRACEME_RAISE(traceme_raise3, SIGABRT) /* regular abort trap */ 228 TRACEME_RAISE(traceme_raise4, SIGHUP) /* hangup */ 229 TRACEME_RAISE(traceme_raise5, SIGCONT) /* continued? */ 230 TRACEME_RAISE(traceme_raise6, SIGTRAP) /* crash signal */ 231 TRACEME_RAISE(traceme_raise7, SIGBUS) /* crash signal */ 232 TRACEME_RAISE(traceme_raise8, SIGILL) /* crash signal */ 233 TRACEME_RAISE(traceme_raise9, SIGFPE) /* crash signal */ 234 TRACEME_RAISE(traceme_raise10, SIGSEGV) /* crash signal */ 235 #endif 236 237 ATF_TP_ADD_TCS(tp) 238 { 239 setvbuf(stdout, NULL, _IONBF, 0); 240 setvbuf(stderr, NULL, _IONBF, 0); 241 242 ATF_TP_ADD_TC(tp, traceme_raise1); 243 #if notyet 244 ATF_TP_ADD_TC(tp, traceme_raise2); 245 ATF_TP_ADD_TC(tp, traceme_raise3); 246 ATF_TP_ADD_TC(tp, traceme_raise4); 247 ATF_TP_ADD_TC(tp, traceme_raise5); 248 ATF_TP_ADD_TC(tp, traceme_raise6); 249 ATF_TP_ADD_TC(tp, traceme_raise7); 250 ATF_TP_ADD_TC(tp, traceme_raise8); 251 ATF_TP_ADD_TC(tp, traceme_raise9); 252 ATF_TP_ADD_TC(tp, traceme_raise10); 253 #endif 254 255 return atf_no_error(); 256 } 257