(root)/
strace-6.5/
src/
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-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  }