1 /* $NetBSD: t_ptrace_syscall_wait.h,v 1.3 2023/03/20 11:19:30 hannken Exp $ */ 2 3 /*- 4 * Copyright (c) 2016, 2017, 2018, 2019, 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 30 static int test_syscall_caught; 31 32 static void 33 syscall_sighand(int arg) 34 { 35 36 DPRINTF("Caught a signal %d in process %d\n", arg, getpid()); 37 38 FORKEE_ASSERT_EQ(arg, SIGINFO); 39 40 ++test_syscall_caught; 41 42 FORKEE_ASSERT_EQ(test_syscall_caught, 1); 43 } 44 45 static void 46 syscall_body(const char *op) 47 { 48 const int exitval = 5; 49 const int sigval = SIGSTOP; 50 pid_t child, wpid; 51 #if defined(TWAIT_HAVE_STATUS) 52 int status; 53 #endif 54 struct ptrace_siginfo info; 55 56 memset(&info, 0, sizeof(info)); 57 58 if (strstr(op, "signal") != NULL) { 59 #if defined(TWAIT_HAVE_STATUS) 60 atf_tc_expect_fail("XXX: behavior under investigation"); 61 #else 62 atf_tc_skip("PR lib/55087"); 63 #endif 64 } 65 66 DPRINTF("Before forking process PID=%d\n", getpid()); 67 SYSCALL_REQUIRE((child = fork()) != -1); 68 if (child == 0) { 69 DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); 70 FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); 71 72 signal(SIGINFO, syscall_sighand); 73 74 DPRINTF("Before raising %s from child\n", strsignal(sigval)); 75 FORKEE_ASSERT(raise(sigval) == 0); 76 77 syscall(SYS_getpid); 78 79 if (strstr(op, "signal") != NULL) { 80 FORKEE_ASSERT_EQ(test_syscall_caught, 1); 81 } 82 83 DPRINTF("Before exiting of the child process\n"); 84 _exit(exitval); 85 } 86 DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child); 87 88 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 89 TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); 90 91 validate_status_stopped(status, sigval); 92 93 DPRINTF("Before resuming the child process where it left off and " 94 "without signal to be sent\n"); 95 SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1); 96 97 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 98 TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); 99 100 validate_status_stopped(status, SIGTRAP); 101 102 DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO for child\n"); 103 SYSCALL_REQUIRE(ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) != -1); 104 105 DPRINTF("Before checking siginfo_t and lwpid\n"); 106 ATF_REQUIRE(info.psi_lwpid > 0); 107 ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP); 108 ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCE); 109 110 if (strstr(op, "killed") != NULL) { 111 SYSCALL_REQUIRE(ptrace(PT_KILL, child, NULL, 0) != -1); 112 113 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 114 TWAIT_REQUIRE_SUCCESS( 115 wpid = TWAIT_GENERIC(child, &status, 0), child); 116 117 validate_status_signaled(status, SIGKILL, 0); 118 } else { 119 if (strstr(op, "signal") != NULL) { 120 DPRINTF("Before resuming the child %d and sending a " 121 "signal SIGINFO\n", child); 122 SYSCALL_REQUIRE( 123 ptrace(PT_CONTINUE, child, (void *)1, SIGINFO) 124 != -1); 125 } else if (strstr(op, "detach") != NULL) { 126 DPRINTF("Before detaching the child %d\n", child); 127 SYSCALL_REQUIRE( 128 ptrace(PT_DETACH, child, (void *)1, 0) != -1); 129 } else { 130 DPRINTF("Before resuming the child process where it " 131 "left off and without signal to be sent\n"); 132 SYSCALL_REQUIRE( 133 ptrace(PT_SYSCALL, child, (void *)1, 0) != -1); 134 135 DPRINTF("Before calling %s() for the child\n", 136 TWAIT_FNAME); 137 TWAIT_REQUIRE_SUCCESS( 138 wpid = TWAIT_GENERIC(child, &status, 0), child); 139 140 validate_status_stopped(status, SIGTRAP); 141 142 DPRINTF("Before calling ptrace(2) with PT_GET_SIGINFO " 143 "for child\n"); 144 SYSCALL_REQUIRE( 145 ptrace(PT_GET_SIGINFO, child, &info, sizeof(info)) 146 != -1); 147 148 DPRINTF("Before checking siginfo_t and lwpid\n"); 149 ATF_REQUIRE(info.psi_lwpid > 0); 150 ATF_REQUIRE_EQ(info.psi_siginfo.si_signo, SIGTRAP); 151 ATF_REQUIRE_EQ(info.psi_siginfo.si_code, TRAP_SCX); 152 153 DPRINTF("Before resuming the child process where it " 154 "left off and without signal to be sent\n"); 155 SYSCALL_REQUIRE( 156 ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); 157 } 158 159 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 160 TWAIT_REQUIRE_SUCCESS( 161 wpid = TWAIT_GENERIC(child, &status, 0), child); 162 163 validate_status_exited(status, exitval); 164 } 165 166 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 167 TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); 168 } 169 170 #define SYSCALL_TEST(name,op) \ 171 ATF_TC(name); \ 172 ATF_TC_HEAD(name, tc) \ 173 { \ 174 atf_tc_set_md_var(tc, "timeout", "15"); \ 175 atf_tc_set_md_var(tc, "descr", \ 176 "Verify that getpid(2) can be traced with PT_SYSCALL %s", \ 177 #op ); \ 178 } \ 179 \ 180 ATF_TC_BODY(name, tc) \ 181 { \ 182 \ 183 syscall_body(op); \ 184 } 185 186 SYSCALL_TEST(syscall, "") 187 SYSCALL_TEST(syscall_killed_on_sce, "and killed") 188 SYSCALL_TEST(syscall_signal_on_sce, "and signaled") 189 SYSCALL_TEST(syscall_detach_on_sce, "and detached") 190 191 /// ---------------------------------------------------------------------------- 192 193 ATF_TC(syscallemu1); 194 ATF_TC_HEAD(syscallemu1, tc) 195 { 196 atf_tc_set_md_var(tc, "descr", 197 "Verify that exit(2) can be intercepted with PT_SYSCALLEMU"); 198 } 199 200 ATF_TC_BODY(syscallemu1, tc) 201 { 202 const int exitval = 5; 203 const int sigval = SIGSTOP; 204 pid_t child, wpid; 205 #if defined(TWAIT_HAVE_STATUS) 206 int status; 207 #endif 208 209 DPRINTF("Before forking process PID=%d\n", getpid()); 210 SYSCALL_REQUIRE((child = fork()) != -1); 211 if (child == 0) { 212 DPRINTF("Before calling PT_TRACE_ME from child %d\n", getpid()); 213 FORKEE_ASSERT(ptrace(PT_TRACE_ME, 0, NULL, 0) != -1); 214 215 DPRINTF("Before raising %s from child\n", strsignal(sigval)); 216 FORKEE_ASSERT(raise(sigval) == 0); 217 218 syscall(SYS_exit, 100); 219 220 DPRINTF("Before exiting of the child process\n"); 221 _exit(exitval); 222 } 223 DPRINTF("Parent process PID=%d, child's PID=%d\n", getpid(), child); 224 225 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 226 TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); 227 228 validate_status_stopped(status, sigval); 229 230 DPRINTF("Before resuming the child process where it left off and " 231 "without signal to be sent\n"); 232 SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1); 233 234 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 235 TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); 236 237 validate_status_stopped(status, SIGTRAP); 238 239 DPRINTF("Set SYSCALLEMU for intercepted syscall\n"); 240 SYSCALL_REQUIRE(ptrace(PT_SYSCALLEMU, child, (void *)1, 0) != -1); 241 242 DPRINTF("Before resuming the child process where it left off and " 243 "without signal to be sent\n"); 244 SYSCALL_REQUIRE(ptrace(PT_SYSCALL, child, (void *)1, 0) != -1); 245 246 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 247 TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); 248 249 validate_status_stopped(status, SIGTRAP); 250 251 DPRINTF("Before resuming the child process where it left off and " 252 "without signal to be sent\n"); 253 SYSCALL_REQUIRE(ptrace(PT_CONTINUE, child, (void *)1, 0) != -1); 254 255 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 256 TWAIT_REQUIRE_SUCCESS(wpid = TWAIT_GENERIC(child, &status, 0), child); 257 258 validate_status_exited(status, exitval); 259 260 DPRINTF("Before calling %s() for the child\n", TWAIT_FNAME); 261 TWAIT_REQUIRE_FAILURE(ECHILD, wpid = TWAIT_GENERIC(child, &status, 0)); 262 } 263 264 #define ATF_TP_ADD_TCS_PTRACE_WAIT_SYSCALL() \ 265 ATF_TP_ADD_TC(tp, syscall); \ 266 ATF_TP_ADD_TC(tp, syscall_killed_on_sce); \ 267 ATF_TP_ADD_TC(tp, syscall_signal_on_sce); \ 268 ATF_TP_ADD_TC(tp, syscall_detach_on_sce); \ 269 ATF_TP_ADD_TC(tp, syscallemu1); 270