Mirror of strace – the linux syscall tracer
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ucopy.c 7.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  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. #include "defs.h"
  15. #include <sys/uio.h>
  16. #include <asm/unistd.h>
  17. #include "scno.h"
  18. #include "ptrace.h"
  19. static bool process_vm_readv_not_supported;
  20. #ifndef HAVE_PROCESS_VM_READV
  21. /*
  22. * Need to do this since process_vm_readv() is not yet available in libc.
  23. * When libc is updated, only "static bool process_vm_readv_not_supported"
  24. * line remains.
  25. * The name is different to avoid potential collision with OS headers.
  26. */
  27. static ssize_t 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. #endif /* !HAVE_PROCESS_VM_READV */
  39. static ssize_t
  40. vm_read_mem(const pid_t pid, void *const laddr,
  41. const kernel_ulong_t raddr, const size_t len)
  42. {
  43. const unsigned long truncated_raddr = raddr;
  44. #if SIZEOF_LONG < SIZEOF_KERNEL_LONG_T
  45. if (raddr != (kernel_ulong_t) truncated_raddr) {
  46. errno = EIO;
  47. return -1;
  48. }
  49. #endif
  50. const struct iovec local = {
  51. .iov_base = laddr,
  52. .iov_len = len
  53. };
  54. const struct iovec remote = {
  55. .iov_base = (void *) truncated_raddr,
  56. .iov_len = len
  57. };
  58. const ssize_t rc = process_vm_readv(pid, &local, 1, &remote, 1, 0);
  59. if (rc < 0 && errno == ENOSYS)
  60. process_vm_readv_not_supported = true;
  61. return rc;
  62. }
  63. static bool
  64. tracee_addr_is_invalid(kernel_ulong_t addr)
  65. {
  66. return
  67. #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG
  68. current_wordsize < sizeof(addr) && addr & ~(kernel_ulong_t) -1U;
  69. #else
  70. false;
  71. #endif
  72. }
  73. /* legacy method of copying from tracee */
  74. static int
  75. umoven_peekdata(const int pid, kernel_ulong_t addr, unsigned int len,
  76. void *laddr)
  77. {
  78. unsigned int nread = 0;
  79. unsigned int residue = addr & (sizeof(long) - 1);
  80. while (len) {
  81. addr &= -sizeof(long); /* aligned address */
  82. errno = 0;
  83. union {
  84. long val;
  85. char x[sizeof(long)];
  86. } u = { .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0) };
  87. switch (errno) {
  88. case 0:
  89. break;
  90. case ESRCH: case EINVAL:
  91. /* these could be seen if the process is gone */
  92. return -1;
  93. case EFAULT: case EIO: case EPERM:
  94. /* address space is inaccessible */
  95. if (nread) {
  96. perror_msg("umoven: short read (%u < %u) @0x%" PRI_klx,
  97. nread, nread + len, addr - nread);
  98. }
  99. return -1;
  100. default:
  101. /* all the rest is strange and should be reported */
  102. perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%" PRI_klx,
  103. pid, addr);
  104. return -1;
  105. }
  106. unsigned int m = MIN(sizeof(long) - residue, len);
  107. memcpy(laddr, &u.x[residue], m);
  108. residue = 0;
  109. addr += sizeof(long);
  110. laddr += m;
  111. nread += m;
  112. len -= m;
  113. }
  114. return 0;
  115. }
  116. /*
  117. * Copy `len' bytes of data from process `pid'
  118. * at address `addr' to our space at `our_addr'.
  119. */
  120. int
  121. ptrace_umoven(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
  122. void *const our_addr)
  123. {
  124. if (tracee_addr_is_invalid(addr))
  125. return -1;
  126. const int pid = tcp->pid;
  127. if (process_vm_readv_not_supported)
  128. return umoven_peekdata(pid, addr, len, our_addr);
  129. int r = vm_read_mem(pid, our_addr, addr, len);
  130. if ((unsigned int) r == len)
  131. return 0;
  132. if (r >= 0) {
  133. error_msg("umoven: short read (%u < %u) @0x%" PRI_klx,
  134. (unsigned int) r, len, addr);
  135. return -1;
  136. }
  137. switch (errno) {
  138. case ENOSYS:
  139. case EPERM:
  140. /* try PTRACE_PEEKDATA */
  141. return umoven_peekdata(pid, addr, len, our_addr);
  142. case ESRCH:
  143. /* the process is gone */
  144. return -1;
  145. case EFAULT: case EIO:
  146. /* address space is inaccessible */
  147. return -1;
  148. default:
  149. /* all the rest is strange and should be reported */
  150. perror_msg("process_vm_readv: pid:%d @0x%" PRI_klx,
  151. pid, addr);
  152. return -1;
  153. }
  154. }
  155. /*
  156. * Like umoven_peekdata but make the additional effort of looking
  157. * for a terminating zero byte.
  158. */
  159. static int
  160. umovestr_peekdata(const int pid, kernel_ulong_t addr, unsigned int len,
  161. void *laddr)
  162. {
  163. unsigned int nread = 0;
  164. unsigned int residue = addr & (sizeof(long) - 1);
  165. void *const orig_addr = laddr;
  166. while (len) {
  167. addr &= -sizeof(long); /* aligned address */
  168. errno = 0;
  169. union {
  170. unsigned long val;
  171. char x[sizeof(long)];
  172. } u = { .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0) };
  173. switch (errno) {
  174. case 0:
  175. break;
  176. case ESRCH: case EINVAL:
  177. /* these could be seen if the process is gone */
  178. return -1;
  179. case EFAULT: case EIO: case EPERM:
  180. /* address space is inaccessible */
  181. if (nread) {
  182. perror_msg("umovestr: short read (%d < %d) @0x%" PRI_klx,
  183. nread, nread + len, addr - nread);
  184. }
  185. return -1;
  186. default:
  187. /* all the rest is strange and should be reported */
  188. perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%" PRI_klx,
  189. pid, addr);
  190. return -1;
  191. }
  192. unsigned int m = MIN(sizeof(long) - residue, len);
  193. memcpy(laddr, &u.x[residue], m);
  194. while (residue < sizeof(long))
  195. if (u.x[residue++] == '\0')
  196. return (laddr - orig_addr) + residue;
  197. residue = 0;
  198. addr += sizeof(long);
  199. laddr += m;
  200. nread += m;
  201. len -= m;
  202. }
  203. return 0;
  204. }
  205. /*
  206. * Like `umove' but make the additional effort of looking
  207. * for a terminating zero byte.
  208. *
  209. * Returns < 0 on error, strlen + 1 if NUL was seen,
  210. * else 0 if len bytes were read but no NUL byte seen.
  211. *
  212. * Note: there is no guarantee we won't overwrite some bytes
  213. * in laddr[] _after_ terminating NUL (but, of course,
  214. * we never write past laddr[len-1]).
  215. */
  216. int
  217. ptrace_umovestr(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len,
  218. char *laddr)
  219. {
  220. if (tracee_addr_is_invalid(addr))
  221. return -1;
  222. const int pid = tcp->pid;
  223. if (process_vm_readv_not_supported)
  224. return umovestr_peekdata(pid, addr, len, laddr);
  225. const size_t page_size = get_pagesize();
  226. const size_t page_mask = page_size - 1;
  227. unsigned int nread = 0;
  228. while (len) {
  229. /*
  230. * Don't cross pages, otherwise we can get EFAULT
  231. * and fail to notice that terminating NUL lies
  232. * in the existing (first) page.
  233. */
  234. unsigned int chunk_len = len > page_size ? page_size : len;
  235. unsigned int end_in_page = (addr + chunk_len) & page_mask;
  236. if (chunk_len > end_in_page) /* crosses to the next page */
  237. chunk_len -= end_in_page;
  238. int r = vm_read_mem(pid, laddr, addr, chunk_len);
  239. if (r > 0) {
  240. char *nul_addr = memchr(laddr, '\0', r);
  241. if (nul_addr)
  242. return (nul_addr - laddr) + 1;
  243. addr += r;
  244. laddr += r;
  245. nread += r;
  246. len -= r;
  247. continue;
  248. }
  249. switch (errno) {
  250. case ENOSYS:
  251. case EPERM:
  252. /* try PTRACE_PEEKDATA */
  253. if (!nread)
  254. return umovestr_peekdata(pid, addr,
  255. len, laddr);
  256. ATTRIBUTE_FALLTHROUGH;
  257. case EFAULT: case EIO:
  258. /* address space is inaccessible */
  259. if (nread)
  260. perror_msg("umovestr: short read (%d < %d) @0x%" PRI_klx,
  261. nread, nread + len, addr - nread);
  262. return -1;
  263. case ESRCH:
  264. /* the process is gone */
  265. return -1;
  266. default:
  267. /* all the rest is strange and should be reported */
  268. perror_msg("process_vm_readv: pid:%d @0x%" PRI_klx,
  269. pid, addr);
  270. return -1;
  271. }
  272. }
  273. return 0;
  274. }