1*bc6fa711SDmitry V. Levin // SPDX-License-Identifier: GPL-2.0+
2*bc6fa711SDmitry V. Levin /*
3*bc6fa711SDmitry V. Levin * Copyright (c) 2018-2025 Dmitry V. Levin <ldv@strace.io>
4*bc6fa711SDmitry V. Levin * All rights reserved.
5*bc6fa711SDmitry V. Levin *
6*bc6fa711SDmitry V. Levin * Check whether PTRACE_SET_SYSCALL_INFO semantics implemented in the kernel
7*bc6fa711SDmitry V. Levin * matches userspace expectations.
8*bc6fa711SDmitry V. Levin */
9*bc6fa711SDmitry V. Levin
10*bc6fa711SDmitry V. Levin #include "../kselftest_harness.h"
11*bc6fa711SDmitry V. Levin #include <err.h>
12*bc6fa711SDmitry V. Levin #include <fcntl.h>
13*bc6fa711SDmitry V. Levin #include <signal.h>
14*bc6fa711SDmitry V. Levin #include <asm/unistd.h>
15*bc6fa711SDmitry V. Levin #include <linux/types.h>
16*bc6fa711SDmitry V. Levin #include <linux/ptrace.h>
17*bc6fa711SDmitry V. Levin
18*bc6fa711SDmitry V. Levin #if defined(_MIPS_SIM) && _MIPS_SIM == _MIPS_SIM_NABI32
19*bc6fa711SDmitry V. Levin /*
20*bc6fa711SDmitry V. Levin * MIPS N32 is the only architecture where __kernel_ulong_t
21*bc6fa711SDmitry V. Levin * does not match the bitness of syscall arguments.
22*bc6fa711SDmitry V. Levin */
23*bc6fa711SDmitry V. Levin typedef unsigned long long kernel_ulong_t;
24*bc6fa711SDmitry V. Levin #else
25*bc6fa711SDmitry V. Levin typedef __kernel_ulong_t kernel_ulong_t;
26*bc6fa711SDmitry V. Levin #endif
27*bc6fa711SDmitry V. Levin
28*bc6fa711SDmitry V. Levin struct si_entry {
29*bc6fa711SDmitry V. Levin int nr;
30*bc6fa711SDmitry V. Levin kernel_ulong_t args[6];
31*bc6fa711SDmitry V. Levin };
32*bc6fa711SDmitry V. Levin struct si_exit {
33*bc6fa711SDmitry V. Levin unsigned int is_error;
34*bc6fa711SDmitry V. Levin int rval;
35*bc6fa711SDmitry V. Levin };
36*bc6fa711SDmitry V. Levin
37*bc6fa711SDmitry V. Levin static unsigned int ptrace_stop;
38*bc6fa711SDmitry V. Levin static pid_t tracee_pid;
39*bc6fa711SDmitry V. Levin
40*bc6fa711SDmitry V. Levin static int
kill_tracee(pid_t pid)41*bc6fa711SDmitry V. Levin kill_tracee(pid_t pid)
42*bc6fa711SDmitry V. Levin {
43*bc6fa711SDmitry V. Levin if (!pid)
44*bc6fa711SDmitry V. Levin return 0;
45*bc6fa711SDmitry V. Levin
46*bc6fa711SDmitry V. Levin int saved_errno = errno;
47*bc6fa711SDmitry V. Levin
48*bc6fa711SDmitry V. Levin int rc = kill(pid, SIGKILL);
49*bc6fa711SDmitry V. Levin
50*bc6fa711SDmitry V. Levin errno = saved_errno;
51*bc6fa711SDmitry V. Levin return rc;
52*bc6fa711SDmitry V. Levin }
53*bc6fa711SDmitry V. Levin
54*bc6fa711SDmitry V. Levin static long
sys_ptrace(int request,pid_t pid,unsigned long addr,unsigned long data)55*bc6fa711SDmitry V. Levin sys_ptrace(int request, pid_t pid, unsigned long addr, unsigned long data)
56*bc6fa711SDmitry V. Levin {
57*bc6fa711SDmitry V. Levin return syscall(__NR_ptrace, request, pid, addr, data);
58*bc6fa711SDmitry V. Levin }
59*bc6fa711SDmitry V. Levin
60*bc6fa711SDmitry V. Levin #define LOG_KILL_TRACEE(fmt, ...) \
61*bc6fa711SDmitry V. Levin do { \
62*bc6fa711SDmitry V. Levin kill_tracee(tracee_pid); \
63*bc6fa711SDmitry V. Levin TH_LOG("wait #%d: " fmt, \
64*bc6fa711SDmitry V. Levin ptrace_stop, ##__VA_ARGS__); \
65*bc6fa711SDmitry V. Levin } while (0)
66*bc6fa711SDmitry V. Levin
67*bc6fa711SDmitry V. Levin static void
check_psi_entry(struct __test_metadata * _metadata,const struct ptrace_syscall_info * info,const struct si_entry * exp_entry,const char * text)68*bc6fa711SDmitry V. Levin check_psi_entry(struct __test_metadata *_metadata,
69*bc6fa711SDmitry V. Levin const struct ptrace_syscall_info *info,
70*bc6fa711SDmitry V. Levin const struct si_entry *exp_entry,
71*bc6fa711SDmitry V. Levin const char *text)
72*bc6fa711SDmitry V. Levin {
73*bc6fa711SDmitry V. Levin unsigned int i;
74*bc6fa711SDmitry V. Levin int exp_nr = exp_entry->nr;
75*bc6fa711SDmitry V. Levin #if defined __s390__ || defined __s390x__
76*bc6fa711SDmitry V. Levin /* s390 is the only architecture that has 16-bit syscall numbers */
77*bc6fa711SDmitry V. Levin exp_nr &= 0xffff;
78*bc6fa711SDmitry V. Levin #endif
79*bc6fa711SDmitry V. Levin
80*bc6fa711SDmitry V. Levin ASSERT_EQ(PTRACE_SYSCALL_INFO_ENTRY, info->op) {
81*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: entry stop mismatch", text);
82*bc6fa711SDmitry V. Levin }
83*bc6fa711SDmitry V. Levin ASSERT_TRUE(info->arch) {
84*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: entry stop mismatch", text);
85*bc6fa711SDmitry V. Levin }
86*bc6fa711SDmitry V. Levin ASSERT_TRUE(info->instruction_pointer) {
87*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: entry stop mismatch", text);
88*bc6fa711SDmitry V. Levin }
89*bc6fa711SDmitry V. Levin ASSERT_TRUE(info->stack_pointer) {
90*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: entry stop mismatch", text);
91*bc6fa711SDmitry V. Levin }
92*bc6fa711SDmitry V. Levin ASSERT_EQ(exp_nr, info->entry.nr) {
93*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: syscall nr mismatch", text);
94*bc6fa711SDmitry V. Levin }
95*bc6fa711SDmitry V. Levin for (i = 0; i < ARRAY_SIZE(exp_entry->args); ++i) {
96*bc6fa711SDmitry V. Levin ASSERT_EQ(exp_entry->args[i], info->entry.args[i]) {
97*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: syscall arg #%u mismatch",
98*bc6fa711SDmitry V. Levin text, i);
99*bc6fa711SDmitry V. Levin }
100*bc6fa711SDmitry V. Levin }
101*bc6fa711SDmitry V. Levin }
102*bc6fa711SDmitry V. Levin
103*bc6fa711SDmitry V. Levin static void
check_psi_exit(struct __test_metadata * _metadata,const struct ptrace_syscall_info * info,const struct si_exit * exp_exit,const char * text)104*bc6fa711SDmitry V. Levin check_psi_exit(struct __test_metadata *_metadata,
105*bc6fa711SDmitry V. Levin const struct ptrace_syscall_info *info,
106*bc6fa711SDmitry V. Levin const struct si_exit *exp_exit,
107*bc6fa711SDmitry V. Levin const char *text)
108*bc6fa711SDmitry V. Levin {
109*bc6fa711SDmitry V. Levin ASSERT_EQ(PTRACE_SYSCALL_INFO_EXIT, info->op) {
110*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: exit stop mismatch", text);
111*bc6fa711SDmitry V. Levin }
112*bc6fa711SDmitry V. Levin ASSERT_TRUE(info->arch) {
113*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: exit stop mismatch", text);
114*bc6fa711SDmitry V. Levin }
115*bc6fa711SDmitry V. Levin ASSERT_TRUE(info->instruction_pointer) {
116*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: exit stop mismatch", text);
117*bc6fa711SDmitry V. Levin }
118*bc6fa711SDmitry V. Levin ASSERT_TRUE(info->stack_pointer) {
119*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: exit stop mismatch", text);
120*bc6fa711SDmitry V. Levin }
121*bc6fa711SDmitry V. Levin ASSERT_EQ(exp_exit->is_error, info->exit.is_error) {
122*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: exit stop mismatch", text);
123*bc6fa711SDmitry V. Levin }
124*bc6fa711SDmitry V. Levin ASSERT_EQ(exp_exit->rval, info->exit.rval) {
125*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("%s: exit stop mismatch", text);
126*bc6fa711SDmitry V. Levin }
127*bc6fa711SDmitry V. Levin }
128*bc6fa711SDmitry V. Levin
TEST(set_syscall_info)129*bc6fa711SDmitry V. Levin TEST(set_syscall_info)
130*bc6fa711SDmitry V. Levin {
131*bc6fa711SDmitry V. Levin const pid_t tracer_pid = getpid();
132*bc6fa711SDmitry V. Levin const kernel_ulong_t dummy[] = {
133*bc6fa711SDmitry V. Levin (kernel_ulong_t) 0xdad0bef0bad0fed0ULL,
134*bc6fa711SDmitry V. Levin (kernel_ulong_t) 0xdad1bef1bad1fed1ULL,
135*bc6fa711SDmitry V. Levin (kernel_ulong_t) 0xdad2bef2bad2fed2ULL,
136*bc6fa711SDmitry V. Levin (kernel_ulong_t) 0xdad3bef3bad3fed3ULL,
137*bc6fa711SDmitry V. Levin (kernel_ulong_t) 0xdad4bef4bad4fed4ULL,
138*bc6fa711SDmitry V. Levin (kernel_ulong_t) 0xdad5bef5bad5fed5ULL,
139*bc6fa711SDmitry V. Levin };
140*bc6fa711SDmitry V. Levin int splice_in[2], splice_out[2];
141*bc6fa711SDmitry V. Levin
142*bc6fa711SDmitry V. Levin ASSERT_EQ(0, pipe(splice_in));
143*bc6fa711SDmitry V. Levin ASSERT_EQ(0, pipe(splice_out));
144*bc6fa711SDmitry V. Levin ASSERT_EQ(sizeof(dummy), write(splice_in[1], dummy, sizeof(dummy)));
145*bc6fa711SDmitry V. Levin
146*bc6fa711SDmitry V. Levin const struct {
147*bc6fa711SDmitry V. Levin struct si_entry entry[2];
148*bc6fa711SDmitry V. Levin struct si_exit exit[2];
149*bc6fa711SDmitry V. Levin } si[] = {
150*bc6fa711SDmitry V. Levin /* change scno, keep non-error rval */
151*bc6fa711SDmitry V. Levin {
152*bc6fa711SDmitry V. Levin {
153*bc6fa711SDmitry V. Levin {
154*bc6fa711SDmitry V. Levin __NR_gettid,
155*bc6fa711SDmitry V. Levin {
156*bc6fa711SDmitry V. Levin dummy[0], dummy[1], dummy[2],
157*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
158*bc6fa711SDmitry V. Levin }
159*bc6fa711SDmitry V. Levin }, {
160*bc6fa711SDmitry V. Levin __NR_getppid,
161*bc6fa711SDmitry V. Levin {
162*bc6fa711SDmitry V. Levin dummy[0], dummy[1], dummy[2],
163*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
164*bc6fa711SDmitry V. Levin }
165*bc6fa711SDmitry V. Levin }
166*bc6fa711SDmitry V. Levin }, {
167*bc6fa711SDmitry V. Levin { 0, tracer_pid }, { 0, tracer_pid }
168*bc6fa711SDmitry V. Levin }
169*bc6fa711SDmitry V. Levin },
170*bc6fa711SDmitry V. Levin
171*bc6fa711SDmitry V. Levin /* set scno to -1, keep error rval */
172*bc6fa711SDmitry V. Levin {
173*bc6fa711SDmitry V. Levin {
174*bc6fa711SDmitry V. Levin {
175*bc6fa711SDmitry V. Levin __NR_chdir,
176*bc6fa711SDmitry V. Levin {
177*bc6fa711SDmitry V. Levin (uintptr_t) ".",
178*bc6fa711SDmitry V. Levin dummy[1], dummy[2],
179*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
180*bc6fa711SDmitry V. Levin }
181*bc6fa711SDmitry V. Levin }, {
182*bc6fa711SDmitry V. Levin -1,
183*bc6fa711SDmitry V. Levin {
184*bc6fa711SDmitry V. Levin (uintptr_t) ".",
185*bc6fa711SDmitry V. Levin dummy[1], dummy[2],
186*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
187*bc6fa711SDmitry V. Levin }
188*bc6fa711SDmitry V. Levin }
189*bc6fa711SDmitry V. Levin }, {
190*bc6fa711SDmitry V. Levin { 1, -ENOSYS }, { 1, -ENOSYS }
191*bc6fa711SDmitry V. Levin }
192*bc6fa711SDmitry V. Levin },
193*bc6fa711SDmitry V. Levin
194*bc6fa711SDmitry V. Levin /* keep scno, change non-error rval */
195*bc6fa711SDmitry V. Levin {
196*bc6fa711SDmitry V. Levin {
197*bc6fa711SDmitry V. Levin {
198*bc6fa711SDmitry V. Levin __NR_getppid,
199*bc6fa711SDmitry V. Levin {
200*bc6fa711SDmitry V. Levin dummy[0], dummy[1], dummy[2],
201*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
202*bc6fa711SDmitry V. Levin }
203*bc6fa711SDmitry V. Levin }, {
204*bc6fa711SDmitry V. Levin __NR_getppid,
205*bc6fa711SDmitry V. Levin {
206*bc6fa711SDmitry V. Levin dummy[0], dummy[1], dummy[2],
207*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
208*bc6fa711SDmitry V. Levin }
209*bc6fa711SDmitry V. Levin }
210*bc6fa711SDmitry V. Levin }, {
211*bc6fa711SDmitry V. Levin { 0, tracer_pid }, { 0, tracer_pid + 1 }
212*bc6fa711SDmitry V. Levin }
213*bc6fa711SDmitry V. Levin },
214*bc6fa711SDmitry V. Levin
215*bc6fa711SDmitry V. Levin /* change arg1, keep non-error rval */
216*bc6fa711SDmitry V. Levin {
217*bc6fa711SDmitry V. Levin {
218*bc6fa711SDmitry V. Levin {
219*bc6fa711SDmitry V. Levin __NR_chdir,
220*bc6fa711SDmitry V. Levin {
221*bc6fa711SDmitry V. Levin (uintptr_t) "",
222*bc6fa711SDmitry V. Levin dummy[1], dummy[2],
223*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
224*bc6fa711SDmitry V. Levin }
225*bc6fa711SDmitry V. Levin }, {
226*bc6fa711SDmitry V. Levin __NR_chdir,
227*bc6fa711SDmitry V. Levin {
228*bc6fa711SDmitry V. Levin (uintptr_t) ".",
229*bc6fa711SDmitry V. Levin dummy[1], dummy[2],
230*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
231*bc6fa711SDmitry V. Levin }
232*bc6fa711SDmitry V. Levin }
233*bc6fa711SDmitry V. Levin }, {
234*bc6fa711SDmitry V. Levin { 0, 0 }, { 0, 0 }
235*bc6fa711SDmitry V. Levin }
236*bc6fa711SDmitry V. Levin },
237*bc6fa711SDmitry V. Levin
238*bc6fa711SDmitry V. Levin /* set scno to -1, change error rval to non-error */
239*bc6fa711SDmitry V. Levin {
240*bc6fa711SDmitry V. Levin {
241*bc6fa711SDmitry V. Levin {
242*bc6fa711SDmitry V. Levin __NR_gettid,
243*bc6fa711SDmitry V. Levin {
244*bc6fa711SDmitry V. Levin dummy[0], dummy[1], dummy[2],
245*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
246*bc6fa711SDmitry V. Levin }
247*bc6fa711SDmitry V. Levin }, {
248*bc6fa711SDmitry V. Levin -1,
249*bc6fa711SDmitry V. Levin {
250*bc6fa711SDmitry V. Levin dummy[0], dummy[1], dummy[2],
251*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
252*bc6fa711SDmitry V. Levin }
253*bc6fa711SDmitry V. Levin }
254*bc6fa711SDmitry V. Levin }, {
255*bc6fa711SDmitry V. Levin { 1, -ENOSYS }, { 0, tracer_pid }
256*bc6fa711SDmitry V. Levin }
257*bc6fa711SDmitry V. Levin },
258*bc6fa711SDmitry V. Levin
259*bc6fa711SDmitry V. Levin /* change scno, change non-error rval to error */
260*bc6fa711SDmitry V. Levin {
261*bc6fa711SDmitry V. Levin {
262*bc6fa711SDmitry V. Levin {
263*bc6fa711SDmitry V. Levin __NR_chdir,
264*bc6fa711SDmitry V. Levin {
265*bc6fa711SDmitry V. Levin dummy[0], dummy[1], dummy[2],
266*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
267*bc6fa711SDmitry V. Levin }
268*bc6fa711SDmitry V. Levin }, {
269*bc6fa711SDmitry V. Levin __NR_getppid,
270*bc6fa711SDmitry V. Levin {
271*bc6fa711SDmitry V. Levin dummy[0], dummy[1], dummy[2],
272*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
273*bc6fa711SDmitry V. Levin }
274*bc6fa711SDmitry V. Levin }
275*bc6fa711SDmitry V. Levin }, {
276*bc6fa711SDmitry V. Levin { 0, tracer_pid }, { 1, -EISDIR }
277*bc6fa711SDmitry V. Levin }
278*bc6fa711SDmitry V. Levin },
279*bc6fa711SDmitry V. Levin
280*bc6fa711SDmitry V. Levin /* change scno and all args, change non-error rval */
281*bc6fa711SDmitry V. Levin {
282*bc6fa711SDmitry V. Levin {
283*bc6fa711SDmitry V. Levin {
284*bc6fa711SDmitry V. Levin __NR_gettid,
285*bc6fa711SDmitry V. Levin {
286*bc6fa711SDmitry V. Levin dummy[0], dummy[1], dummy[2],
287*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
288*bc6fa711SDmitry V. Levin }
289*bc6fa711SDmitry V. Levin }, {
290*bc6fa711SDmitry V. Levin __NR_splice,
291*bc6fa711SDmitry V. Levin {
292*bc6fa711SDmitry V. Levin splice_in[0], 0, splice_out[1], 0,
293*bc6fa711SDmitry V. Levin sizeof(dummy), SPLICE_F_NONBLOCK
294*bc6fa711SDmitry V. Levin }
295*bc6fa711SDmitry V. Levin }
296*bc6fa711SDmitry V. Levin }, {
297*bc6fa711SDmitry V. Levin { 0, sizeof(dummy) }, { 0, sizeof(dummy) + 1 }
298*bc6fa711SDmitry V. Levin }
299*bc6fa711SDmitry V. Levin },
300*bc6fa711SDmitry V. Levin
301*bc6fa711SDmitry V. Levin /* change arg1, no exit stop */
302*bc6fa711SDmitry V. Levin {
303*bc6fa711SDmitry V. Levin {
304*bc6fa711SDmitry V. Levin {
305*bc6fa711SDmitry V. Levin __NR_exit_group,
306*bc6fa711SDmitry V. Levin {
307*bc6fa711SDmitry V. Levin dummy[0], dummy[1], dummy[2],
308*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
309*bc6fa711SDmitry V. Levin }
310*bc6fa711SDmitry V. Levin }, {
311*bc6fa711SDmitry V. Levin __NR_exit_group,
312*bc6fa711SDmitry V. Levin {
313*bc6fa711SDmitry V. Levin 0, dummy[1], dummy[2],
314*bc6fa711SDmitry V. Levin dummy[3], dummy[4], dummy[5]
315*bc6fa711SDmitry V. Levin }
316*bc6fa711SDmitry V. Levin }
317*bc6fa711SDmitry V. Levin }, {
318*bc6fa711SDmitry V. Levin { 0, 0 }, { 0, 0 }
319*bc6fa711SDmitry V. Levin }
320*bc6fa711SDmitry V. Levin },
321*bc6fa711SDmitry V. Levin };
322*bc6fa711SDmitry V. Levin
323*bc6fa711SDmitry V. Levin long rc;
324*bc6fa711SDmitry V. Levin unsigned int i;
325*bc6fa711SDmitry V. Levin
326*bc6fa711SDmitry V. Levin tracee_pid = fork();
327*bc6fa711SDmitry V. Levin
328*bc6fa711SDmitry V. Levin ASSERT_LE(0, tracee_pid) {
329*bc6fa711SDmitry V. Levin TH_LOG("fork: %m");
330*bc6fa711SDmitry V. Levin }
331*bc6fa711SDmitry V. Levin
332*bc6fa711SDmitry V. Levin if (tracee_pid == 0) {
333*bc6fa711SDmitry V. Levin /* get the pid before PTRACE_TRACEME */
334*bc6fa711SDmitry V. Levin tracee_pid = getpid();
335*bc6fa711SDmitry V. Levin ASSERT_EQ(0, sys_ptrace(PTRACE_TRACEME, 0, 0, 0)) {
336*bc6fa711SDmitry V. Levin TH_LOG("PTRACE_TRACEME: %m");
337*bc6fa711SDmitry V. Levin }
338*bc6fa711SDmitry V. Levin ASSERT_EQ(0, kill(tracee_pid, SIGSTOP)) {
339*bc6fa711SDmitry V. Levin /* cannot happen */
340*bc6fa711SDmitry V. Levin TH_LOG("kill SIGSTOP: %m");
341*bc6fa711SDmitry V. Levin }
342*bc6fa711SDmitry V. Levin for (i = 0; i < ARRAY_SIZE(si); ++i) {
343*bc6fa711SDmitry V. Levin rc = syscall(si[i].entry[0].nr,
344*bc6fa711SDmitry V. Levin si[i].entry[0].args[0],
345*bc6fa711SDmitry V. Levin si[i].entry[0].args[1],
346*bc6fa711SDmitry V. Levin si[i].entry[0].args[2],
347*bc6fa711SDmitry V. Levin si[i].entry[0].args[3],
348*bc6fa711SDmitry V. Levin si[i].entry[0].args[4],
349*bc6fa711SDmitry V. Levin si[i].entry[0].args[5]);
350*bc6fa711SDmitry V. Levin if (si[i].exit[1].is_error) {
351*bc6fa711SDmitry V. Levin if (rc != -1 || errno != -si[i].exit[1].rval)
352*bc6fa711SDmitry V. Levin break;
353*bc6fa711SDmitry V. Levin } else {
354*bc6fa711SDmitry V. Levin if (rc != si[i].exit[1].rval)
355*bc6fa711SDmitry V. Levin break;
356*bc6fa711SDmitry V. Levin }
357*bc6fa711SDmitry V. Levin }
358*bc6fa711SDmitry V. Levin /*
359*bc6fa711SDmitry V. Levin * Something went wrong, but in this state tracee
360*bc6fa711SDmitry V. Levin * cannot reliably issue syscalls, so just crash.
361*bc6fa711SDmitry V. Levin */
362*bc6fa711SDmitry V. Levin *(volatile unsigned char *) (uintptr_t) i = 42;
363*bc6fa711SDmitry V. Levin /* unreachable */
364*bc6fa711SDmitry V. Levin _exit(i + 1);
365*bc6fa711SDmitry V. Levin }
366*bc6fa711SDmitry V. Levin
367*bc6fa711SDmitry V. Levin for (ptrace_stop = 0; ; ++ptrace_stop) {
368*bc6fa711SDmitry V. Levin struct ptrace_syscall_info info = {
369*bc6fa711SDmitry V. Levin .op = 0xff /* invalid PTRACE_SYSCALL_INFO_* op */
370*bc6fa711SDmitry V. Levin };
371*bc6fa711SDmitry V. Levin const size_t size = sizeof(info);
372*bc6fa711SDmitry V. Levin const int expected_entry_size =
373*bc6fa711SDmitry V. Levin (void *) &info.entry.args[6] - (void *) &info;
374*bc6fa711SDmitry V. Levin const int expected_exit_size =
375*bc6fa711SDmitry V. Levin (void *) (&info.exit.is_error + 1) -
376*bc6fa711SDmitry V. Levin (void *) &info;
377*bc6fa711SDmitry V. Levin int status;
378*bc6fa711SDmitry V. Levin
379*bc6fa711SDmitry V. Levin ASSERT_EQ(tracee_pid, wait(&status)) {
380*bc6fa711SDmitry V. Levin /* cannot happen */
381*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("wait: %m");
382*bc6fa711SDmitry V. Levin }
383*bc6fa711SDmitry V. Levin if (WIFEXITED(status)) {
384*bc6fa711SDmitry V. Levin tracee_pid = 0; /* the tracee is no more */
385*bc6fa711SDmitry V. Levin ASSERT_EQ(0, WEXITSTATUS(status)) {
386*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("unexpected exit status %u",
387*bc6fa711SDmitry V. Levin WEXITSTATUS(status));
388*bc6fa711SDmitry V. Levin }
389*bc6fa711SDmitry V. Levin break;
390*bc6fa711SDmitry V. Levin }
391*bc6fa711SDmitry V. Levin ASSERT_FALSE(WIFSIGNALED(status)) {
392*bc6fa711SDmitry V. Levin tracee_pid = 0; /* the tracee is no more */
393*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("unexpected signal %u",
394*bc6fa711SDmitry V. Levin WTERMSIG(status));
395*bc6fa711SDmitry V. Levin }
396*bc6fa711SDmitry V. Levin ASSERT_TRUE(WIFSTOPPED(status)) {
397*bc6fa711SDmitry V. Levin /* cannot happen */
398*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("unexpected wait status %#x", status);
399*bc6fa711SDmitry V. Levin }
400*bc6fa711SDmitry V. Levin
401*bc6fa711SDmitry V. Levin ASSERT_LT(ptrace_stop, ARRAY_SIZE(si) * 2) {
402*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("ptrace stop overflow");
403*bc6fa711SDmitry V. Levin }
404*bc6fa711SDmitry V. Levin
405*bc6fa711SDmitry V. Levin switch (WSTOPSIG(status)) {
406*bc6fa711SDmitry V. Levin case SIGSTOP:
407*bc6fa711SDmitry V. Levin ASSERT_EQ(0, ptrace_stop) {
408*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("unexpected signal stop");
409*bc6fa711SDmitry V. Levin }
410*bc6fa711SDmitry V. Levin ASSERT_EQ(0, sys_ptrace(PTRACE_SETOPTIONS, tracee_pid,
411*bc6fa711SDmitry V. Levin 0, PTRACE_O_TRACESYSGOOD)) {
412*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_SETOPTIONS: %m");
413*bc6fa711SDmitry V. Levin }
414*bc6fa711SDmitry V. Levin break;
415*bc6fa711SDmitry V. Levin
416*bc6fa711SDmitry V. Levin case SIGTRAP | 0x80:
417*bc6fa711SDmitry V. Levin ASSERT_LT(0, ptrace_stop) {
418*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("unexpected syscall stop");
419*bc6fa711SDmitry V. Levin }
420*bc6fa711SDmitry V. Levin ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
421*bc6fa711SDmitry V. Levin tracee_pid, size,
422*bc6fa711SDmitry V. Levin (uintptr_t) &info))) {
423*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO #1: %m");
424*bc6fa711SDmitry V. Levin }
425*bc6fa711SDmitry V. Levin if (ptrace_stop & 1) {
426*bc6fa711SDmitry V. Levin /* entering syscall */
427*bc6fa711SDmitry V. Levin const struct si_entry *exp_entry =
428*bc6fa711SDmitry V. Levin &si[ptrace_stop / 2].entry[0];
429*bc6fa711SDmitry V. Levin const struct si_entry *set_entry =
430*bc6fa711SDmitry V. Levin &si[ptrace_stop / 2].entry[1];
431*bc6fa711SDmitry V. Levin
432*bc6fa711SDmitry V. Levin /* check ptrace_syscall_info before the changes */
433*bc6fa711SDmitry V. Levin ASSERT_EQ(expected_entry_size, rc) {
434*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO #1"
435*bc6fa711SDmitry V. Levin ": entry stop mismatch");
436*bc6fa711SDmitry V. Levin }
437*bc6fa711SDmitry V. Levin check_psi_entry(_metadata, &info, exp_entry,
438*bc6fa711SDmitry V. Levin "PTRACE_GET_SYSCALL_INFO #1");
439*bc6fa711SDmitry V. Levin
440*bc6fa711SDmitry V. Levin /* apply the changes */
441*bc6fa711SDmitry V. Levin info.entry.nr = set_entry->nr;
442*bc6fa711SDmitry V. Levin for (i = 0; i < ARRAY_SIZE(set_entry->args); ++i)
443*bc6fa711SDmitry V. Levin info.entry.args[i] = set_entry->args[i];
444*bc6fa711SDmitry V. Levin ASSERT_EQ(0, sys_ptrace(PTRACE_SET_SYSCALL_INFO,
445*bc6fa711SDmitry V. Levin tracee_pid, size,
446*bc6fa711SDmitry V. Levin (uintptr_t) &info)) {
447*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_SET_SYSCALL_INFO: %m");
448*bc6fa711SDmitry V. Levin }
449*bc6fa711SDmitry V. Levin
450*bc6fa711SDmitry V. Levin /* check ptrace_syscall_info after the changes */
451*bc6fa711SDmitry V. Levin memset(&info, 0, sizeof(info));
452*bc6fa711SDmitry V. Levin info.op = 0xff;
453*bc6fa711SDmitry V. Levin ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
454*bc6fa711SDmitry V. Levin tracee_pid, size,
455*bc6fa711SDmitry V. Levin (uintptr_t) &info))) {
456*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO: %m");
457*bc6fa711SDmitry V. Levin }
458*bc6fa711SDmitry V. Levin ASSERT_EQ(expected_entry_size, rc) {
459*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO #2"
460*bc6fa711SDmitry V. Levin ": entry stop mismatch");
461*bc6fa711SDmitry V. Levin }
462*bc6fa711SDmitry V. Levin check_psi_entry(_metadata, &info, set_entry,
463*bc6fa711SDmitry V. Levin "PTRACE_GET_SYSCALL_INFO #2");
464*bc6fa711SDmitry V. Levin } else {
465*bc6fa711SDmitry V. Levin /* exiting syscall */
466*bc6fa711SDmitry V. Levin const struct si_exit *exp_exit =
467*bc6fa711SDmitry V. Levin &si[ptrace_stop / 2 - 1].exit[0];
468*bc6fa711SDmitry V. Levin const struct si_exit *set_exit =
469*bc6fa711SDmitry V. Levin &si[ptrace_stop / 2 - 1].exit[1];
470*bc6fa711SDmitry V. Levin
471*bc6fa711SDmitry V. Levin /* check ptrace_syscall_info before the changes */
472*bc6fa711SDmitry V. Levin ASSERT_EQ(expected_exit_size, rc) {
473*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO #1"
474*bc6fa711SDmitry V. Levin ": exit stop mismatch");
475*bc6fa711SDmitry V. Levin }
476*bc6fa711SDmitry V. Levin check_psi_exit(_metadata, &info, exp_exit,
477*bc6fa711SDmitry V. Levin "PTRACE_GET_SYSCALL_INFO #1");
478*bc6fa711SDmitry V. Levin
479*bc6fa711SDmitry V. Levin /* apply the changes */
480*bc6fa711SDmitry V. Levin info.exit.is_error = set_exit->is_error;
481*bc6fa711SDmitry V. Levin info.exit.rval = set_exit->rval;
482*bc6fa711SDmitry V. Levin ASSERT_EQ(0, sys_ptrace(PTRACE_SET_SYSCALL_INFO,
483*bc6fa711SDmitry V. Levin tracee_pid, size,
484*bc6fa711SDmitry V. Levin (uintptr_t) &info)) {
485*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_SET_SYSCALL_INFO: %m");
486*bc6fa711SDmitry V. Levin }
487*bc6fa711SDmitry V. Levin
488*bc6fa711SDmitry V. Levin /* check ptrace_syscall_info after the changes */
489*bc6fa711SDmitry V. Levin memset(&info, 0, sizeof(info));
490*bc6fa711SDmitry V. Levin info.op = 0xff;
491*bc6fa711SDmitry V. Levin ASSERT_LT(0, (rc = sys_ptrace(PTRACE_GET_SYSCALL_INFO,
492*bc6fa711SDmitry V. Levin tracee_pid, size,
493*bc6fa711SDmitry V. Levin (uintptr_t) &info))) {
494*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO #2: %m");
495*bc6fa711SDmitry V. Levin }
496*bc6fa711SDmitry V. Levin ASSERT_EQ(expected_exit_size, rc) {
497*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_GET_SYSCALL_INFO #2"
498*bc6fa711SDmitry V. Levin ": exit stop mismatch");
499*bc6fa711SDmitry V. Levin }
500*bc6fa711SDmitry V. Levin check_psi_exit(_metadata, &info, set_exit,
501*bc6fa711SDmitry V. Levin "PTRACE_GET_SYSCALL_INFO #2");
502*bc6fa711SDmitry V. Levin }
503*bc6fa711SDmitry V. Levin break;
504*bc6fa711SDmitry V. Levin
505*bc6fa711SDmitry V. Levin default:
506*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("unexpected stop signal %u",
507*bc6fa711SDmitry V. Levin WSTOPSIG(status));
508*bc6fa711SDmitry V. Levin abort();
509*bc6fa711SDmitry V. Levin }
510*bc6fa711SDmitry V. Levin
511*bc6fa711SDmitry V. Levin ASSERT_EQ(0, sys_ptrace(PTRACE_SYSCALL, tracee_pid, 0, 0)) {
512*bc6fa711SDmitry V. Levin LOG_KILL_TRACEE("PTRACE_SYSCALL: %m");
513*bc6fa711SDmitry V. Levin }
514*bc6fa711SDmitry V. Levin }
515*bc6fa711SDmitry V. Levin
516*bc6fa711SDmitry V. Levin ASSERT_EQ(ptrace_stop, ARRAY_SIZE(si) * 2);
517*bc6fa711SDmitry V. Levin }
518*bc6fa711SDmitry V. Levin
519*bc6fa711SDmitry V. Levin TEST_HARNESS_MAIN
520