t_ptrace_syscall_wait.h revision 1.4 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