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