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