]> granicus.if.org Git - strace/blob - ucopy.c
Fix preprocessor indentation
[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 process_read_mem(const pid_t pid, void *const laddr,
45                  void *const raddr, const size_t len)
46 {
47         const struct iovec local = {
48                 .iov_base = laddr,
49                 .iov_len = len
50         };
51         const struct iovec remote = {
52                 .iov_base = raddr,
53                 .iov_len = len
54         };
55
56         const ssize_t rc = process_vm_readv(pid, &local, 1, &remote, 1, 0);
57         if (rc < 0 && errno == ENOSYS)
58                 process_vm_readv_not_supported = true;
59
60         return rc;
61 }
62
63 static int cached_idx = -1;
64 static unsigned long cached_raddr[2];
65
66 void
67 invalidate_umove_cache(void)
68 {
69         cached_idx = -1;
70 }
71
72 static ssize_t
73 vm_read_mem(const pid_t pid, void *const laddr,
74             const kernel_ulong_t raddr, const size_t len)
75 {
76         if (!len)
77                 return len;
78
79         const unsigned long taddr = raddr;
80
81 #if SIZEOF_LONG < SIZEOF_KERNEL_LONG_T
82         if (raddr != (kernel_ulong_t) taddr) {
83                 errno = EIO;
84                 return -1;
85         }
86 #endif
87
88         const size_t page_size = get_pagesize();
89         const size_t page_mask = page_size - 1;
90         const unsigned long raddr_page_start =
91                 taddr & ~page_mask;
92         const unsigned long raddr_page_next =
93                 (taddr + len + page_mask) & ~page_mask;
94
95         if (!raddr_page_start ||
96             raddr_page_next < raddr_page_start ||
97             raddr_page_next - raddr_page_start != page_size)
98                 return process_read_mem(pid, laddr, (void *) taddr, len);
99
100         int idx = -1;
101         if (cached_idx >= 0) {
102                 if (raddr_page_start == cached_raddr[cached_idx])
103                         idx = cached_idx;
104                 else if (raddr_page_start == cached_raddr[!cached_idx])
105                         idx = !cached_idx;
106         }
107
108         static char *buf[2];
109
110         if (idx == -1) {
111                 idx = !cached_idx;
112
113                 if (!buf[idx])
114                         buf[idx] = xmalloc(page_size);
115
116                 const ssize_t rc =
117                         process_read_mem(pid, buf[idx],
118                                          (void *) raddr_page_start, page_size);
119                 if (rc < 0)
120                         return rc;
121
122                 cached_raddr[idx] = raddr_page_start;
123                 if (cached_idx < 0)
124                         cached_raddr[!idx] = 0;
125                 cached_idx = idx;
126         }
127
128         memcpy(laddr, buf[idx] + (taddr - cached_raddr[idx]), len);
129         return len;
130 }
131
132 static bool
133 tracee_addr_is_invalid(kernel_ulong_t addr)
134 {
135         return
136 #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG
137                 current_wordsize < sizeof(addr) && addr & ~(kernel_ulong_t) -1U;
138 #else
139                 false;
140 #endif
141 }
142
143 /* legacy method of copying from tracee */
144 static int
145 umoven_peekdata(const int pid, kernel_ulong_t addr, unsigned int len,
146                 void *laddr)
147 {
148         unsigned int nread = 0;
149         unsigned int residue = addr & (sizeof(long) - 1);
150
151         while (len) {
152                 addr &= -sizeof(long);          /* aligned address */
153
154                 errno = 0;
155                 union {
156                         long val;
157                         char x[sizeof(long)];
158                 } u = { .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0) };
159
160                 switch (errno) {
161                         case 0:
162                                 break;
163                         case ESRCH: case EINVAL:
164                                 /* these could be seen if the process is gone */
165                                 return -1;
166                         case EFAULT: case EIO: case EPERM:
167                                 /* address space is inaccessible */
168                                 if (nread) {
169                                         perror_func_msg("short read (%u < %u)"
170                                                         " @0x%" PRI_klx,
171                                                         nread, nread + len,
172                                                         addr - nread);
173                                 }
174                                 return -1;
175                         default:
176                                 /* all the rest is strange and should be reported */
177                                 perror_func_msg("pid:%d @0x%" PRI_klx,
178                                                 pid, addr);
179                                 return -1;
180                 }
181
182                 unsigned int m = MIN(sizeof(long) - residue, len);
183                 memcpy(laddr, &u.x[residue], m);
184                 residue = 0;
185                 addr += sizeof(long);
186                 laddr += m;
187                 nread += m;
188                 len -= m;
189         }
190
191         return 0;
192 }
193
194 /*
195  * Copy `len' bytes of data from process `pid'
196  * at address `addr' to our space at `our_addr'.
197  */
198 int
199 umoven(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
200        void *const our_addr)
201 {
202         if (tracee_addr_is_invalid(addr))
203                 return -1;
204
205         const int pid = tcp->pid;
206
207         if (process_vm_readv_not_supported)
208                 return umoven_peekdata(pid, addr, len, our_addr);
209
210         int r = vm_read_mem(pid, our_addr, addr, len);
211         if ((unsigned int) r == len)
212                 return 0;
213         if (r >= 0) {
214                 error_func_msg("short read (%u < %u) @0x%" PRI_klx,
215                                (unsigned int) r, len, addr);
216                 return -1;
217         }
218         switch (errno) {
219                 case ENOSYS:
220                 case EPERM:
221                         /* try PTRACE_PEEKDATA */
222                         return umoven_peekdata(pid, addr, len, our_addr);
223                 case ESRCH:
224                         /* the process is gone */
225                         return -1;
226                 case EFAULT: case EIO:
227                         /* address space is inaccessible */
228                         return -1;
229                 default:
230                         /* all the rest is strange and should be reported */
231                         perror_func_msg("pid:%d @0x%" PRI_klx, pid, addr);
232                         return -1;
233         }
234 }
235
236 /*
237  * Like umoven_peekdata but make the additional effort of looking
238  * for a terminating zero byte.
239  */
240 static int
241 umovestr_peekdata(const int pid, kernel_ulong_t addr, unsigned int len,
242                   void *laddr)
243 {
244         unsigned int nread = 0;
245         unsigned int residue = addr & (sizeof(long) - 1);
246         void *const orig_addr = laddr;
247
248         while (len) {
249                 addr &= -sizeof(long);          /* aligned address */
250
251                 errno = 0;
252                 union {
253                         unsigned long val;
254                         char x[sizeof(long)];
255                 } u = { .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0) };
256
257                 switch (errno) {
258                         case 0:
259                                 break;
260                         case ESRCH: case EINVAL:
261                                 /* these could be seen if the process is gone */
262                                 return -1;
263                         case EFAULT: case EIO: case EPERM:
264                                 /* address space is inaccessible */
265                                 if (nread) {
266                                         perror_func_msg("short read (%d < %d)"
267                                                         " @0x%" PRI_klx,
268                                                         nread, nread + len,
269                                                         addr - nread);
270                                 }
271                                 return -1;
272                         default:
273                                 /* all the rest is strange and should be reported */
274                                 perror_func_msg("pid:%d @0x%" PRI_klx,
275                                                 pid, addr);
276                                 return -1;
277                 }
278
279                 unsigned int m = MIN(sizeof(long) - residue, len);
280                 memcpy(laddr, &u.x[residue], m);
281                 while (residue < sizeof(long))
282                         if (u.x[residue++] == '\0')
283                                 return (laddr - orig_addr) + residue;
284                 residue = 0;
285                 addr += sizeof(long);
286                 laddr += m;
287                 nread += m;
288                 len -= m;
289         }
290
291         return 0;
292 }
293
294 /*
295  * Like `umove' but make the additional effort of looking
296  * for a terminating zero byte.
297  *
298  * Returns < 0 on error, strlen + 1  if NUL was seen,
299  * else 0 if len bytes were read but no NUL byte seen.
300  *
301  * Note: there is no guarantee we won't overwrite some bytes
302  * in laddr[] _after_ terminating NUL (but, of course,
303  * we never write past laddr[len-1]).
304  */
305 int
306 umovestr(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
307          char *laddr)
308 {
309         if (tracee_addr_is_invalid(addr))
310                 return -1;
311
312         const int pid = tcp->pid;
313
314         if (process_vm_readv_not_supported)
315                 return umovestr_peekdata(pid, addr, len, laddr);
316
317         const size_t page_size = get_pagesize();
318         const size_t page_mask = page_size - 1;
319         unsigned int nread = 0;
320
321         while (len) {
322                 /*
323                  * Don't cross pages, otherwise we can get EFAULT
324                  * and fail to notice that terminating NUL lies
325                  * in the existing (first) page.
326                  */
327                 unsigned int chunk_len = len > page_size ? page_size : len;
328                 unsigned int end_in_page = (addr + chunk_len) & page_mask;
329                 if (chunk_len > end_in_page) /* crosses to the next page */
330                         chunk_len -= end_in_page;
331
332                 int r = vm_read_mem(pid, laddr, addr, chunk_len);
333                 if (r > 0) {
334                         char *nul_addr = memchr(laddr, '\0', r);
335
336                         if (nul_addr)
337                                 return (nul_addr - laddr) + 1;
338                         addr += r;
339                         laddr += r;
340                         nread += r;
341                         len -= r;
342                         continue;
343                 }
344                 switch (errno) {
345                         case ENOSYS:
346                         case EPERM:
347                                 /* try PTRACE_PEEKDATA */
348                                 if (!nread)
349                                         return umovestr_peekdata(pid, addr,
350                                                                  len, laddr);
351                                 ATTRIBUTE_FALLTHROUGH;
352                         case EFAULT: case EIO:
353                                 /* address space is inaccessible */
354                                 if (nread)
355                                         perror_func_msg("short read (%d < %d)"
356                                                         " @0x%" PRI_klx,
357                                                         nread, nread + len,
358                                                         addr - nread);
359                                 return -1;
360                         case ESRCH:
361                                 /* the process is gone */
362                                 return -1;
363                         default:
364                                 /* all the rest is strange and should be reported */
365                                 perror_func_msg("pid:%d @0x%" PRI_klx, pid, addr);
366                                 return -1;
367                 }
368         }
369
370         return 0;
371 }