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