1 /* 2 * Copyright (c) 1991, 1992 Paul Kranenburg <pk (at) cs.few.eur.nl> 3 * Copyright (c) 1993 Branko Lankester <branko (at) hacktic.nl> 4 * Copyright (c) 1993, 1994, 1995, 1996 Rick Sladkey <jrs (at) world.std.com> 5 * Copyright (c) 1996-1999 Wichert Akkerman <wichert (at) cistron.nl> 6 * Copyright (c) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation 7 * Linux for s390 port by D.J. Barrow 8 * <barrow_dj (at) mail.yahoo.com,djbarrow (at) de.ibm.com> 9 * Copyright (c) 1999-2018 The strace developers. 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include "defs.h" 36 #include <sys/uio.h> 37 #include <asm/unistd.h> 38 39 #include "scno.h" 40 #include "ptrace.h" 41 42 static bool process_vm_readv_not_supported; 43 44 #ifndef HAVE_PROCESS_VM_READV 45 /* 46 * Need to do this since process_vm_readv() is not yet available in libc. 47 * When libc is updated, only "static bool process_vm_readv_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_readv(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_readv, 59 (long) pid, lvec, liovcnt, rvec, riovcnt, flags); 60 } 61 # define process_vm_readv strace_process_vm_readv 62 #endif /* !HAVE_PROCESS_VM_READV */ 63 64 static ssize_t 65 vm_read_mem(const pid_t pid, void *const laddr, 66 const kernel_ulong_t raddr, const size_t len) 67 { 68 const unsigned long truncated_raddr = raddr; 69 70 #if SIZEOF_LONG < SIZEOF_KERNEL_LONG_T 71 if (raddr != (kernel_ulong_t) truncated_raddr) { 72 errno = EIO; 73 return -1; 74 } 75 #endif 76 77 const struct iovec local = { 78 .iov_base = laddr, 79 .iov_len = len 80 }; 81 const struct iovec remote = { 82 .iov_base = (void *) truncated_raddr, 83 .iov_len = len 84 }; 85 86 const ssize_t rc = process_vm_readv(pid, &local, 1, &remote, 1, 0); 87 if (rc < 0 && errno == ENOSYS) 88 process_vm_readv_not_supported = true; 89 90 return rc; 91 } 92 93 static bool 94 tracee_addr_is_invalid(kernel_ulong_t addr) 95 { 96 return 97 #if ANY_WORDSIZE_LESS_THAN_KERNEL_LONG 98 current_wordsize < sizeof(addr) && addr & ~(kernel_ulong_t) -1U; 99 #else 100 false; 101 #endif 102 } 103 104 /* legacy method of copying from tracee */ 105 static int 106 umoven_peekdata(const int pid, kernel_ulong_t addr, unsigned int len, 107 void *laddr) 108 { 109 unsigned int nread = 0; 110 unsigned int residue = addr & (sizeof(long) - 1); 111 112 while (len) { 113 addr &= -sizeof(long); /* aligned address */ 114 115 errno = 0; 116 union { 117 long val; 118 char x[sizeof(long)]; 119 } u = { .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0) }; 120 121 switch (errno) { 122 case 0: 123 break; 124 case ESRCH: case EINVAL: 125 /* these could be seen if the process is gone */ 126 return -1; 127 case EFAULT: case EIO: case EPERM: 128 /* address space is inaccessible */ 129 if (nread) { 130 perror_msg("umoven: short read (%u < %u) @0x%" PRI_klx, 131 nread, nread + len, addr - nread); 132 } 133 return -1; 134 default: 135 /* all the rest is strange and should be reported */ 136 perror_msg("umoven: PTRACE_PEEKDATA pid:%d @0x%" PRI_klx, 137 pid, addr); 138 return -1; 139 } 140 141 unsigned int m = MIN(sizeof(long) - residue, len); 142 memcpy(laddr, &u.x[residue], m); 143 residue = 0; 144 addr += sizeof(long); 145 laddr += m; 146 nread += m; 147 len -= m; 148 } 149 150 return 0; 151 } 152 153 /* 154 * Copy `len' bytes of data from process `pid' 155 * at address `addr' to our space at `our_addr'. 156 */ 157 int 158 umoven(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len, 159 void *const our_addr) 160 { 161 if (tracee_addr_is_invalid(addr)) 162 return -1; 163 164 const int pid = tcp->pid; 165 166 if (process_vm_readv_not_supported) 167 return umoven_peekdata(pid, addr, len, our_addr); 168 169 int r = vm_read_mem(pid, our_addr, addr, len); 170 if ((unsigned int) r == len) 171 return 0; 172 if (r >= 0) { 173 error_msg("umoven: short read (%u < %u) @0x%" PRI_klx, 174 (unsigned int) r, len, addr); 175 return -1; 176 } 177 switch (errno) { 178 case ENOSYS: 179 case EPERM: 180 /* try PTRACE_PEEKDATA */ 181 return umoven_peekdata(pid, addr, len, our_addr); 182 case ESRCH: 183 /* the process is gone */ 184 return -1; 185 case EFAULT: case EIO: 186 /* address space is inaccessible */ 187 return -1; 188 default: 189 /* all the rest is strange and should be reported */ 190 perror_msg("process_vm_readv: pid:%d @0x%" PRI_klx, 191 pid, addr); 192 return -1; 193 } 194 } 195 196 /* 197 * Like umoven_peekdata but make the additional effort of looking 198 * for a terminating zero byte. 199 */ 200 static int 201 umovestr_peekdata(const int pid, kernel_ulong_t addr, unsigned int len, 202 void *laddr) 203 { 204 unsigned int nread = 0; 205 unsigned int residue = addr & (sizeof(long) - 1); 206 void *const orig_addr = laddr; 207 208 while (len) { 209 addr &= -sizeof(long); /* aligned address */ 210 211 errno = 0; 212 union { 213 unsigned long val; 214 char x[sizeof(long)]; 215 } u = { .val = ptrace(PTRACE_PEEKDATA, pid, addr, 0) }; 216 217 switch (errno) { 218 case 0: 219 break; 220 case ESRCH: case EINVAL: 221 /* these could be seen if the process is gone */ 222 return -1; 223 case EFAULT: case EIO: case EPERM: 224 /* address space is inaccessible */ 225 if (nread) { 226 perror_msg("umovestr: short read (%d < %d) @0x%" PRI_klx, 227 nread, nread + len, addr - nread); 228 } 229 return -1; 230 default: 231 /* all the rest is strange and should be reported */ 232 perror_msg("umovestr: PTRACE_PEEKDATA pid:%d @0x%" PRI_klx, 233 pid, addr); 234 return -1; 235 } 236 237 unsigned int m = MIN(sizeof(long) - residue, len); 238 memcpy(laddr, &u.x[residue], m); 239 while (residue < sizeof(long)) 240 if (u.x[residue++] == '\0') 241 return (laddr - orig_addr) + residue; 242 residue = 0; 243 addr += sizeof(long); 244 laddr += m; 245 nread += m; 246 len -= m; 247 } 248 249 return 0; 250 } 251 252 /* 253 * Like `umove' but make the additional effort of looking 254 * for a terminating zero byte. 255 * 256 * Returns < 0 on error, strlen + 1 if NUL was seen, 257 * else 0 if len bytes were read but no NUL byte seen. 258 * 259 * Note: there is no guarantee we won't overwrite some bytes 260 * in laddr[] _after_ terminating NUL (but, of course, 261 * we never write past laddr[len-1]). 262 */ 263 int 264 umovestr(struct tcb *const tcp, kernel_ulong_t addr, unsigned int len, 265 char *laddr) 266 { 267 if (tracee_addr_is_invalid(addr)) 268 return -1; 269 270 const int pid = tcp->pid; 271 272 if (process_vm_readv_not_supported) 273 return umovestr_peekdata(pid, addr, len, laddr); 274 275 const size_t page_size = get_pagesize(); 276 const size_t page_mask = page_size - 1; 277 unsigned int nread = 0; 278 279 while (len) { 280 /* 281 * Don't cross pages, otherwise we can get EFAULT 282 * and fail to notice that terminating NUL lies 283 * in the existing (first) page. 284 */ 285 unsigned int chunk_len = len > page_size ? page_size : len; 286 unsigned int end_in_page = (addr + chunk_len) & page_mask; 287 if (chunk_len > end_in_page) /* crosses to the next page */ 288 chunk_len -= end_in_page; 289 290 int r = vm_read_mem(pid, laddr, addr, chunk_len); 291 if (r > 0) { 292 char *nul_addr = memchr(laddr, '\0', r); 293 294 if (nul_addr) 295 return (nul_addr - laddr) + 1; 296 addr += r; 297 laddr += r; 298 nread += r; 299 len -= r; 300 continue; 301 } 302 switch (errno) { 303 case ENOSYS: 304 case EPERM: 305 /* try PTRACE_PEEKDATA */ 306 if (!nread) 307 return umovestr_peekdata(pid, addr, 308 len, laddr); 309 ATTRIBUTE_FALLTHROUGH; 310 case EFAULT: case EIO: 311 /* address space is inaccessible */ 312 if (nread) 313 perror_msg("umovestr: short read (%d < %d) @0x%" PRI_klx, 314 nread, nread + len, addr - nread); 315 return -1; 316 case ESRCH: 317 /* the process is gone */ 318 return -1; 319 default: 320 /* all the rest is strange and should be reported */ 321 perror_msg("process_vm_readv: pid:%d @0x%" PRI_klx, 322 pid, addr); 323 return -1; 324 } 325 } 326 327 return 0; 328 } 329