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