]> granicus.if.org Git - strace/blob - ucopy.c
clone: fix print_tls_arg on x86
[strace] / ucopy.c
1 /*
2  * Copyright (c) 1991, 1992 Paul Kranenburg <pk@cs.few.eur.nl>
3  * Copyright (c) 1993 Branko Lankester <branko@hacktic.nl>
4  * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs@world.std.com>
5  * Copyright (c) 1996-1999 Wichert Akkerman <wichert@cistron.nl>
6  * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7  *                     Linux for s390 port by D.J. Barrow
8  *                    <barrow_dj@mail.yahoo.com,djbarrow@de.ibm.com>
9  * Copyright (c) 1999-2018 The strace developers.
10  * All rights reserved.
11  *
12  * SPDX-License-Identifier: LGPL-2.1-or-later
13  */
14
15 #include "defs.h"
16 #include <sys/uio.h>
17
18 #include "scno.h"
19 #include "ptrace.h"
20
21 static bool process_vm_readv_not_supported;
22
23 #ifndef HAVE_PROCESS_VM_READV
24 /*
25  * Need to do this since process_vm_readv() is not yet available in libc.
26  * When libc is updated, only "static bool process_vm_readv_not_supported"
27  * line remains.
28  * The name is different to avoid potential collision with OS headers.
29  */
30 static ssize_t strace_process_vm_readv(pid_t pid,
31                  const struct iovec *lvec,
32                  unsigned long liovcnt,
33                  const struct iovec *rvec,
34                  unsigned long riovcnt,
35                  unsigned long flags)
36 {
37         return syscall(__NR_process_vm_readv,
38                        (long) pid, lvec, liovcnt, rvec, riovcnt, flags);
39 }
40 # define process_vm_readv strace_process_vm_readv
41 #endif /* !HAVE_PROCESS_VM_READV */
42
43 static ssize_t
44 vm_read_mem(const pid_t pid, void *const laddr,
45             const kernel_ulong_t raddr, const size_t len)
46 {
47         const unsigned long truncated_raddr = raddr;
48
49 #if SIZEOF_LONG < SIZEOF_KERNEL_LONG_T
50         if (raddr != (kernel_ulong_t) truncated_raddr) {
51                 errno = EIO;
52                 return -1;
53         }
54 #endif
55
56         const struct iovec local = {
57                 .iov_base = laddr,
58                 .iov_len = len
59         };
60         const struct iovec remote = {
61                 .iov_base = (void *) truncated_raddr,
62                 .iov_len = len
63         };
64
65         const ssize_t rc = process_vm_readv(pid, &local, 1, &remote, 1, 0);
66         if (rc < 0 && errno == ENOSYS)
67                 process_vm_readv_not_supported = true;
68
69         return rc;
70 }
71
72 static bool
73 tracee_addr_is_invalid(kernel_ulong_t addr)
74 {
75         return
76 #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG
77                 current_wordsize < sizeof(addr) && addr & ~(kernel_ulong_t) -1U;
78 #else
79                 false;
80 #endif
81 }
82
83 /* legacy method of copying from tracee */
84 static int
85 umoven_peekdata(const int pid, kernel_ulong_t addr, unsigned int len,
86                 void *laddr)
87 {
88         unsigned int nread = 0;
89         unsigned int residue = addr & (sizeof(long) - 1);
90
91         while (len) {
92                 addr &= -sizeof(long);          /* aligned address */
93
94                 errno = 0;
95                 union {
96                         long val;
97                         char x[sizeof(long)];
98                 } u = { .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0) };
99
100                 switch (errno) {
101                         case 0:
102                                 break;
103                         case ESRCH: case EINVAL:
104                                 /* these could be seen if the process is gone */
105                                 return -1;
106                         case EFAULT: case EIO: case EPERM:
107                                 /* address space is inaccessible */
108                                 if (nread) {
109                                         perror_func_msg("short read (%u < %u)"
110                                                         " @0x%" PRI_klx,
111                                                         nread, nread + len,
112                                                         addr - nread);
113                                 }
114                                 return -1;
115                         default:
116                                 /* all the rest is strange and should be reported */
117                                 perror_func_msg("pid:%d @0x%" PRI_klx,
118                                                 pid, addr);
119                                 return -1;
120                 }
121
122                 unsigned int m = MIN(sizeof(long) - residue, len);
123                 memcpy(laddr, &u.x[residue], m);
124                 residue = 0;
125                 addr += sizeof(long);
126                 laddr += m;
127                 nread += m;
128                 len -= m;
129         }
130
131         return 0;
132 }
133
134 /*
135  * Copy `len' bytes of data from process `pid'
136  * at address `addr' to our space at `our_addr'.
137  */
138 int
139 umoven(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
140        void *const our_addr)
141 {
142         if (tracee_addr_is_invalid(addr))
143                 return -1;
144
145         const int pid = tcp->pid;
146
147         if (process_vm_readv_not_supported)
148                 return umoven_peekdata(pid, addr, len, our_addr);
149
150         int r = vm_read_mem(pid, our_addr, addr, len);
151         if ((unsigned int) r == len)
152                 return 0;
153         if (r >= 0) {
154                 error_func_msg("short read (%u < %u) @0x%" PRI_klx,
155                                (unsigned int) r, len, addr);
156                 return -1;
157         }
158         switch (errno) {
159                 case ENOSYS:
160                 case EPERM:
161                         /* try PTRACE_PEEKDATA */
162                         return umoven_peekdata(pid, addr, len, our_addr);
163                 case ESRCH:
164                         /* the process is gone */
165                         return -1;
166                 case EFAULT: case EIO:
167                         /* address space is inaccessible */
168                         return -1;
169                 default:
170                         /* all the rest is strange and should be reported */
171                         perror_func_msg("pid:%d @0x%" PRI_klx, pid, addr);
172                         return -1;
173         }
174 }
175
176 /*
177  * Like umoven_peekdata but make the additional effort of looking
178  * for a terminating zero byte.
179  */
180 static int
181 umovestr_peekdata(const int pid, kernel_ulong_t addr, unsigned int len,
182                   void *laddr)
183 {
184         unsigned int nread = 0;
185         unsigned int residue = addr & (sizeof(long) - 1);
186         void *const orig_addr = laddr;
187
188         while (len) {
189                 addr &= -sizeof(long);          /* aligned address */
190
191                 errno = 0;
192                 union {
193                         unsigned long val;
194                         char x[sizeof(long)];
195                 } u = { .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0) };
196
197                 switch (errno) {
198                         case 0:
199                                 break;
200                         case ESRCH: case EINVAL:
201                                 /* these could be seen if the process is gone */
202                                 return -1;
203                         case EFAULT: case EIO: case EPERM:
204                                 /* address space is inaccessible */
205                                 if (nread) {
206                                         perror_func_msg("short read (%d < %d)"
207                                                         " @0x%" PRI_klx,
208                                                         nread, nread + len,
209                                                         addr - nread);
210                                 }
211                                 return -1;
212                         default:
213                                 /* all the rest is strange and should be reported */
214                                 perror_func_msg("pid:%d @0x%" PRI_klx,
215                                                 pid, addr);
216                                 return -1;
217                 }
218
219                 unsigned int m = MIN(sizeof(long) - residue, len);
220                 memcpy(laddr, &u.x[residue], m);
221                 while (residue < sizeof(long))
222                         if (u.x[residue++] == '\0')
223                                 return (laddr - orig_addr) + residue;
224                 residue = 0;
225                 addr += sizeof(long);
226                 laddr += m;
227                 nread += m;
228                 len -= m;
229         }
230
231         return 0;
232 }
233
234 /*
235  * Like `umove' but make the additional effort of looking
236  * for a terminating zero byte.
237  *
238  * Returns < 0 on error, strlen + 1  if NUL was seen,
239  * else 0 if len bytes were read but no NUL byte seen.
240  *
241  * Note: there is no guarantee we won't overwrite some bytes
242  * in laddr[] _after_ terminating NUL (but, of course,
243  * we never write past laddr[len-1]).
244  */
245 int
246 umovestr(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
247          char *laddr)
248 {
249         if (tracee_addr_is_invalid(addr))
250                 return -1;
251
252         const int pid = tcp->pid;
253
254         if (process_vm_readv_not_supported)
255                 return umovestr_peekdata(pid, addr, len, laddr);
256
257         const size_t page_size = get_pagesize();
258         const size_t page_mask = page_size - 1;
259         unsigned int nread = 0;
260
261         while (len) {
262                 /*
263                  * Don't cross pages, otherwise we can get EFAULT
264                  * and fail to notice that terminating NUL lies
265                  * in the existing (first) page.
266                  */
267                 unsigned int chunk_len = len > page_size ? page_size : len;
268                 unsigned int end_in_page = (addr + chunk_len) & page_mask;
269                 if (chunk_len > end_in_page) /* crosses to the next page */
270                         chunk_len -= end_in_page;
271
272                 int r = vm_read_mem(pid, laddr, addr, chunk_len);
273                 if (r > 0) {
274                         char *nul_addr = memchr(laddr, '\0', r);
275
276                         if (nul_addr)
277                                 return (nul_addr - laddr) + 1;
278                         addr += r;
279                         laddr += r;
280                         nread += r;
281                         len -= r;
282                         continue;
283                 }
284                 switch (errno) {
285                         case ENOSYS:
286                         case EPERM:
287                                 /* try PTRACE_PEEKDATA */
288                                 if (!nread)
289                                         return umovestr_peekdata(pid, addr,
290                                                                  len, laddr);
291                                 ATTRIBUTE_FALLTHROUGH;
292                         case EFAULT: case EIO:
293                                 /* address space is inaccessible */
294                                 if (nread)
295                                         perror_func_msg("short read (%d < %d)"
296                                                         " @0x%" PRI_klx,
297                                                         nread, nread + len,
298                                                         addr - nread);
299                                 return -1;
300                         case ESRCH:
301                                 /* the process is gone */
302                                 return -1;
303                         default:
304                                 /* all the rest is strange and should be reported */
305                                 perror_func_msg("pid:%d @0x%" PRI_klx, pid, addr);
306                                 return -1;
307                 }
308         }
309
310         return 0;
311 }