1 /*
2 * Test whether process_vm_readv and PTRACE_PEEKDATA work.
3 *
4 * Copyright (c) 2016-2017 Dmitry V. Levin <ldv@strace.io>
5 * Copyright (c) 2017-2021 The strace developers.
6 * All rights reserved.
7 *
8 * SPDX-License-Identifier: GPL-2.0-or-later
9 */
10
11 #include "tests.h"
12
13 #include <errno.h>
14 #include <sys/ptrace.h>
15 #include <signal.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <sys/uio.h>
19 #include <sys/wait.h>
20
21 #include "test_ucopy.h"
22
23 #ifndef HAVE_PROCESS_VM_READV
24
25 # include "scno.h"
26 static ssize_t
27 strace_process_vm_readv(pid_t pid,
28 const struct iovec *lvec,
29 unsigned long liovcnt,
30 const struct iovec *rvec,
31 unsigned long riovcnt,
32 unsigned long flags)
33 {
34 return syscall(__NR_process_vm_readv,
35 (long) pid, lvec, liovcnt, rvec, riovcnt, flags);
36 }
37 # define process_vm_readv strace_process_vm_readv
38
39 #endif /* !HAVE_PROCESS_VM_READV */
40
41 static bool
42 call_process_vm_readv(const int pid, long *const addr)
43 {
44 long data = 0;
45
46 const struct iovec local = {
47 .iov_base = &data,
48 .iov_len = sizeof(data)
49 };
50 const struct iovec remote = {
51 .iov_base = addr,
52 .iov_len = sizeof(*addr)
53 };
54
55 return process_vm_readv(pid, &local, 1, &remote, 1, 0) == sizeof(data)
56 && data == 1;
57 }
58
59 static bool
60 call_ptrace_peekdata(const int pid, long *const addr)
61 {
62 return ptrace(PTRACE_PEEKDATA, pid, addr, 0) == 1;
63 }
64
65 static bool
66 test_ucopy(bool (*fn)(int pid, long *addr))
67 {
68 static long data;
69
70 data = 0;
71 bool rc = false;
72 int saved = 0;
73
74 pid_t pid = fork();
75 if (pid < 0)
76 perror_msg_and_fail("fork");
77
78 if (!pid) {
79 data = 1;
80 if (ptrace(PTRACE_TRACEME, 0, 0, 0))
81 perror_msg_and_fail("PTRACE_TRACEME");
82 raise(SIGSTOP);
83 _exit(0);
84 }
85
86 for (;;) {
87 int status, tracee;
88
89 errno = 0;
90 tracee = wait(&status);
91 if (tracee != pid) {
92 if (errno == EINTR)
93 continue;
94 saved = errno;
95 kill(pid, SIGKILL);
96 errno = saved;
97 perror_msg_and_fail("wait");
98 }
99 if (WIFEXITED(status)) {
100 if (WEXITSTATUS(status) == 0)
101 break;
102 error_msg_and_fail("unexpected exit status %u",
103 WEXITSTATUS(status));
104 }
105 if (WIFSIGNALED(status))
106 error_msg_and_fail("unexpected signal %u",
107 WTERMSIG(status));
108 if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
109 kill(pid, SIGKILL);
110 error_msg_and_fail("unexpected wait status %x",
111 status);
112 }
113
114 errno = 0;
115 rc = fn(pid, &data);
116 if (!rc)
117 saved = errno;
118
119 if (ptrace(PTRACE_CONT, pid, 0, 0)) {
120 saved = errno;
121 kill(pid, SIGKILL);
122 errno = saved;
123 perror_msg_and_fail("PTRACE_CONT");
124 }
125 }
126
127 if (!rc)
128 errno = saved;
129 return rc;
130 }
131
132 bool
133 test_process_vm_readv(void)
134 {
135 return test_ucopy(call_process_vm_readv);
136 }
137
138 bool
139 test_ptrace_peekdata(void)
140 {
141 return test_ucopy(call_ptrace_peekdata);
142 }