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-2023 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 static bool process_vm_writev_not_supported;
23
24 #ifndef HAVE_PROCESS_VM_READV
25 /*
26 * Need to do this since process_vm_readv() is not yet available in libc.
27 * When libc is updated, only "static bool process_vm_readv_not_supported"
28 * line remains.
29 * The name is different to avoid potential collision with OS headers.
30 */
31 static ssize_t strace_process_vm_readv(pid_t pid,
32 const struct iovec *lvec,
33 unsigned long liovcnt,
34 const struct iovec *rvec,
35 unsigned long riovcnt,
36 unsigned long flags)
37 {
38 return syscall(__NR_process_vm_readv,
39 (long) pid, lvec, liovcnt, rvec, riovcnt, flags);
40 }
41 # define process_vm_readv strace_process_vm_readv
42 #endif /* !HAVE_PROCESS_VM_READV */
43
44 #ifndef HAVE_PROCESS_VM_WRITEV
45 /*
46 * Need to do this since process_vm_writev() is not yet available in libc.
47 * When libc is updated, only "static bool process_vm_writev_not_supported"
48 * line remains.
49 * The name is different to avoid potential collision with OS headers.
50 */
51 static ssize_t strace_process_vm_writev(pid_t pid,
52 const struct iovec *lvec,
53 unsigned long liovcnt,
54 const struct iovec *rvec,
55 unsigned long riovcnt,
56 unsigned long flags)
57 {
58 return syscall(__NR_process_vm_writev,
59 (long) pid, lvec, liovcnt, rvec, riovcnt, flags);
60 }
61 # define process_vm_writev strace_process_vm_writev
62 #endif /* !HAVE_PROCESS_VM_WRITEV */
63
64 static ssize_t
65 process_read_mem(const pid_t pid, void *const laddr,
66 void *const raddr, const size_t len)
67 {
68 const struct iovec local = {
69 .iov_base = laddr,
70 .iov_len = len
71 };
72 const struct iovec remote = {
73 .iov_base = raddr,
74 .iov_len = len
75 };
76
77 const ssize_t rc = process_vm_readv(pid, &local, 1, &remote, 1, 0);
78 if (rc < 0 && errno == ENOSYS)
79 process_vm_readv_not_supported = true;
80
81 return rc;
82 }
83
84 static int cached_idx = -1;
85 static unsigned long cached_raddr[4];
86
87 void
88 invalidate_umove_cache(void)
89 {
90 cached_idx = -1;
91 }
92
93 static int
94 get_next_unused_idx(void)
95 {
96 return (cached_idx + 1) % ARRAY_SIZE(cached_raddr);
97 }
98
99 static int
100 lookup_cached_raddr_idx(const unsigned long raddr)
101 {
102 if (cached_idx >= 0) {
103 for (int i = cached_idx; i >= 0; --i)
104 if (raddr == cached_raddr[i])
105 return i;
106 for (int i = (int) ARRAY_SIZE(cached_raddr) - 1;
107 i > cached_idx; --i)
108 if (raddr == cached_raddr[i])
109 return i;
110 }
111 return -1;
112 }
113
114 static void
115 set_cached_raddr_idx(const unsigned long raddr, const int idx)
116 {
117 if (cached_idx < 0)
118 memset(cached_raddr, 0, sizeof(cached_raddr));
119 cached_raddr[idx] = raddr;
120 cached_idx = idx;
121 }
122
123 static ssize_t
124 vm_read_mem(const pid_t pid, void *laddr,
125 const kernel_ulong_t kraddr, size_t len)
126 {
127 if (!len)
128 return len;
129
130 unsigned long taddr = kraddr;
131
132 #if SIZEOF_LONG < SIZEOF_KERNEL_LONG_T
133 if (kraddr != (kernel_ulong_t) taddr) {
134 errno = EIO;
135 return -1;
136 }
137 #endif
138
139 const size_t page_size = get_pagesize();
140 const size_t page_mask = page_size - 1;
141 unsigned long page_start = taddr & ~page_mask;
142 const unsigned long page_after_last =
143 (taddr + len + page_mask) & ~page_mask;
144
145 if (!page_start ||
146 page_after_last < page_start ||
147 page_after_last - page_start > ARRAY_SIZE(cached_raddr) * page_size)
148 return process_read_mem(pid, laddr, (void *) taddr, len);
149
150 size_t total_read = 0;
151
152 for (;;) {
153 static char *buf[ARRAY_SIZE(cached_raddr)];
154 int idx = lookup_cached_raddr_idx(page_start);
155
156 if (idx == -1) {
157 idx = get_next_unused_idx();
158
159 if (!buf[idx])
160 buf[idx] = xmalloc(page_size);
161
162 const ssize_t rc =
163 process_read_mem(pid, buf[idx],
164 (void *) page_start, page_size);
165 if (rc < 0)
166 return total_read ? (ssize_t) total_read : rc;
167
168 set_cached_raddr_idx(page_start, idx);
169 }
170
171 const unsigned long offset = taddr - page_start;
172 size_t copy_len, next_len;
173
174 if (len <= page_size - offset) {
175 copy_len = len;
176 next_len = 0;
177 } else {
178 copy_len = page_size - offset;
179 next_len = len - copy_len;
180 }
181
182 memcpy(laddr, buf[idx] + offset, copy_len);
183 total_read += copy_len;
184
185 if (!next_len)
186 break;
187
188 len = next_len;
189 laddr += copy_len;
190 page_start += page_size;
191 taddr = page_start;
192 }
193
194 return total_read;
195 }
196
197 static ssize_t
198 vm_write_mem(const pid_t pid, void *const laddr,
199 const kernel_ulong_t raddr, const size_t len)
200 {
201 const unsigned long truncated_raddr = raddr;
202
203 #if SIZEOF_LONG < SIZEOF_KERNEL_LONG_T
204 if (raddr != (kernel_ulong_t) truncated_raddr) {
205 errno = EIO;
206 return -1;
207 }
208 #endif
209
210 const struct iovec local = {
211 .iov_base = laddr,
212 .iov_len = len
213 };
214 const struct iovec remote = {
215 .iov_base = (void *) truncated_raddr,
216 .iov_len = len
217 };
218
219 const ssize_t rc = process_vm_writev(pid, &local, 1, &remote, 1, 0);
220 if (rc < 0 && errno == ENOSYS)
221 process_vm_writev_not_supported = true;
222
223 return rc;
224 }
225
226
227 static bool
228 tracee_addr_is_invalid(kernel_ulong_t addr)
229 {
230 return
231 #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG
232 current_wordsize < sizeof(addr) && addr & ~(kernel_ulong_t) -1U;
233 #else
234 false;
235 #endif
236 }
237
238 typedef union {
239 long val;
240 char data[sizeof(long)];
241 } dissected_long_t;
242
243 /* legacy method of copying from tracee */
244 static int
245 umoven_peekdata(const int pid, kernel_ulong_t addr, unsigned int len,
246 void *laddr)
247 {
248 unsigned int nread = 0;
249 unsigned int residue = addr & (sizeof(long) - 1);
250
251 while (len) {
252 addr &= -sizeof(long); /* aligned address */
253
254 errno = 0;
255 dissected_long_t u = {
256 .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0)
257 };
258
259 switch (errno) {
260 case 0:
261 break;
262 case ESRCH: case EINVAL:
263 /* these could be seen if the process is gone */
264 return -1;
265 case EFAULT: case EIO: case EPERM:
266 /* address space is inaccessible */
267 if (nread) {
268 perror_func_msg("short read (%u < %u)"
269 " @0x%" PRI_klx,
270 nread, nread + len,
271 addr - nread);
272 }
273 return -1;
274 default:
275 /* all the rest is strange and should be reported */
276 perror_func_msg("pid:%d @0x%" PRI_klx,
277 pid, addr);
278 return -1;
279 }
280
281 unsigned int m = MIN(sizeof(long) - residue, len);
282 memcpy(laddr, &u.data[residue], m);
283 residue = 0;
284 addr += sizeof(long);
285 laddr += m;
286 nread += m;
287 len -= m;
288 }
289
290 return 0;
291 }
292
293 /*
294 * Copy `len' bytes of data from process `pid'
295 * at address `addr' to our space at `our_addr'.
296 */
297 int
298 umoven(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
299 void *const our_addr)
300 {
301 if (tracee_addr_is_invalid(addr))
302 return -1;
303
304 const int pid = tcp->pid;
305
306 if (process_vm_readv_not_supported)
307 return umoven_peekdata(pid, addr, len, our_addr);
308
309 int r = vm_read_mem(pid, our_addr, addr, len);
310 if ((unsigned int) r == len)
311 return 0;
312 if (r >= 0) {
313 error_func_msg("short read (%u < %u) @0x%" PRI_klx,
314 (unsigned int) r, len, addr);
315 return -1;
316 }
317 switch (errno) {
318 case ENOSYS:
319 case EPERM:
320 /* try PTRACE_PEEKDATA */
321 return umoven_peekdata(pid, addr, len, our_addr);
322 case ESRCH:
323 /* the process is gone */
324 return -1;
325 case EFAULT: case EIO:
326 /* address space is inaccessible */
327 return -1;
328 default:
329 /* all the rest is strange and should be reported */
330 perror_func_msg("pid:%d @0x%" PRI_klx, pid, addr);
331 return -1;
332 }
333 }
334
335 /*
336 * Like umoven_peekdata but make the additional effort of looking
337 * for a terminating zero byte.
338 */
339 static int
340 umovestr_peekdata(const int pid, kernel_ulong_t addr, unsigned int len,
341 void *laddr)
342 {
343 unsigned int nread = 0;
344 unsigned int residue = addr & (sizeof(long) - 1);
345 void *const orig_addr = laddr;
346
347 while (len) {
348 addr &= -sizeof(long); /* aligned address */
349
350 errno = 0;
351 dissected_long_t u = {
352 .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0)
353 };
354
355 switch (errno) {
356 case 0:
357 break;
358 case ESRCH: case EINVAL:
359 /* these could be seen if the process is gone */
360 return -1;
361 case EFAULT: case EIO: case EPERM:
362 /* address space is inaccessible */
363 if (nread) {
364 perror_func_msg("short read (%d < %d)"
365 " @0x%" PRI_klx,
366 nread, nread + len,
367 addr - nread);
368 }
369 return -1;
370 default:
371 /* all the rest is strange and should be reported */
372 perror_func_msg("pid:%d @0x%" PRI_klx,
373 pid, addr);
374 return -1;
375 }
376
377 unsigned int m = MIN(sizeof(long) - residue, len);
378 memcpy(laddr, &u.data[residue], m);
379 while (residue < sizeof(long))
380 if (u.data[residue++] == '\0')
381 return (laddr - orig_addr) + residue;
382 residue = 0;
383 addr += sizeof(long);
384 laddr += m;
385 nread += m;
386 len -= m;
387 }
388
389 return 0;
390 }
391
392 /*
393 * Like `umove' but make the additional effort of looking
394 * for a terminating zero byte.
395 *
396 * Returns < 0 on error, strlen + 1 if NUL was seen,
397 * else 0 if len bytes were read but no NUL byte seen.
398 *
399 * Note: there is no guarantee we won't overwrite some bytes
400 * in laddr[] _after_ terminating NUL (but, of course,
401 * we never write past laddr[len-1]).
402 */
403 int
404 umovestr(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
405 char *laddr)
406 {
407 if (tracee_addr_is_invalid(addr))
408 return -1;
409
410 const int pid = tcp->pid;
411
412 if (process_vm_readv_not_supported)
413 return umovestr_peekdata(pid, addr, len, laddr);
414
415 const size_t page_size = get_pagesize();
416 const size_t page_mask = page_size - 1;
417 unsigned int nread = 0;
418
419 while (len) {
420 /*
421 * Don't cross pages, otherwise we can get EFAULT
422 * and fail to notice that terminating NUL lies
423 * in the existing (first) page.
424 */
425 unsigned int chunk_len = len > page_size ? page_size : len;
426 unsigned int end_in_page = (addr + chunk_len) & page_mask;
427 if (chunk_len > end_in_page) /* crosses to the next page */
428 chunk_len -= end_in_page;
429
430 int r = vm_read_mem(pid, laddr, addr, chunk_len);
431 if (r > 0) {
432 char *nul_addr = memchr(laddr, '\0', r);
433
434 if (nul_addr)
435 return nread + (nul_addr - laddr) + 1;
436 addr += r;
437 laddr += r;
438 nread += r;
439 len -= r;
440 continue;
441 }
442 switch (errno) {
443 case ENOSYS:
444 case EPERM:
445 /* try PTRACE_PEEKDATA */
446 if (!nread)
447 return umovestr_peekdata(pid, addr,
448 len, laddr);
449 ATTRIBUTE_FALLTHROUGH;
450 case EFAULT: case EIO:
451 /* address space is inaccessible */
452 if (nread)
453 perror_func_msg("short read (%d < %d)"
454 " @0x%" PRI_klx,
455 nread, nread + len,
456 addr - nread);
457 return -1;
458 case ESRCH:
459 /* the process is gone */
460 return -1;
461 default:
462 /* all the rest is strange and should be reported */
463 perror_func_msg("pid:%d @0x%" PRI_klx, pid, addr);
464 return -1;
465 }
466 }
467
468 return 0;
469 }
470
471 static bool
472 upoken_peekpoke(const int pid, const kernel_ulong_t addr,
473 const unsigned int len, void *const our_addr,
474 const unsigned int offset)
475 {
476 errno = 0;
477 dissected_long_t u = {
478 .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0)
479 };
480 if (errno)
481 return false;
482
483 memcpy(u.data + offset, our_addr, len);
484
485 /* write it back */
486 return ptrace(PTRACE_POKEDATA, pid, addr, u.val) == 0;
487 }
488
489 static unsigned int
490 upoken_pokedata(const int pid, kernel_ulong_t addr, unsigned int len,
491 void *our_addr)
492 {
493 unsigned int nwritten = 0;
494
495 if (len && (addr & (sizeof(long) - 1))) {
496 /* addr is not a multiple of sizeof(long) */
497 unsigned int residue = addr & (sizeof(long) - 1);
498 unsigned int npoke = MIN(sizeof(long) - residue, len);
499 addr &= -sizeof(long); /* aligned address */
500 if (!upoken_peekpoke(pid, addr, npoke, our_addr, residue))
501 goto poke_error;
502
503 addr += sizeof(long);
504 nwritten += npoke;
505 our_addr += npoke;
506 len -= npoke;
507 }
508
509 while (len >= sizeof(long)) {
510 /* our_addr may be unaligned */
511 long word;
512 memcpy(&word, our_addr, sizeof(word));
513 if (ptrace(PTRACE_POKEDATA, pid, addr, word) < 0)
514 goto poke_error;
515
516 addr += sizeof(long);
517 nwritten += sizeof(long);
518 our_addr += sizeof(long);
519 len -= sizeof(long);
520 }
521
522 if (len) {
523 if (!upoken_peekpoke(pid, addr, len, our_addr, 0))
524 goto poke_error;
525 nwritten += len;
526 }
527
528 return nwritten;
529
530 poke_error:
531 switch (errno) {
532 case ESRCH: case EINVAL:
533 /* these could be seen if the process is gone */
534 break;
535 case EFAULT: case EIO: case EPERM:
536 /* address space is inaccessible */
537 if (nwritten) {
538 perror_func_msg("pid:%d short write (%u < %u)"
539 " @0x%" PRI_klx,
540 pid, nwritten, nwritten + len,
541 addr - nwritten);
542 }
543 break;
544 default:
545 /* all the rest is strange and should be reported */
546 perror_func_msg("pid:%d @0x%" PRI_klx, pid, addr);
547 break;
548 }
549
550 return nwritten;
551 }
552
553 /*
554 * Copy `len' bytes of data from `our_addr'
555 * to process `pid' at address `addr'.
556 */
557 unsigned int
558 upoken(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
559 void *const our_addr)
560 {
561 if (tracee_addr_is_invalid(addr))
562 return 0;
563
564 const int pid = tcp->pid;
565
566 if (process_vm_writev_not_supported)
567 return upoken_pokedata(pid, addr, len, our_addr);
568
569 ssize_t r = vm_write_mem(pid, our_addr, addr, len);
570 if ((unsigned int) r == len)
571 return len;
572 if (r >= 0) {
573 error_func_msg("pid:%d short write (%u < %u) @0x%" PRI_klx,
574 pid, (unsigned int) r, len, addr);
575 return (unsigned int) r;
576 }
577 switch (errno) {
578 case ENOSYS: case EPERM: /* could not use process_vm_writev */
579 case EFAULT: case EIO: /* address space is inaccessible */
580 /* try PTRACE_POKEDATA */
581 return upoken_pokedata(pid, addr, len, our_addr);
582 case ESRCH:
583 /* the process is gone */
584 return 0;
585 default:
586 /* all the rest is strange and should be reported */
587 perror_func_msg("pid:%d @0x%" PRI_klx, pid, addr);
588 return 0;
589 }
590 }