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