(root)/
strace-6.5/
tests-m32/
test_ucopy.c
       1  /*
       2   * Test whether process_vm_readv and PTRACE_PEEKDATA work.
       3   *
       4   * Copyright (c) 2016-2017 Dmitry V. Levin <ldv@strace.io>
       5   * Copyright (c) 2017-2021 The strace developers.
       6   * All rights reserved.
       7   *
       8   * SPDX-License-Identifier: GPL-2.0-or-later
       9   */
      10  
      11  #include "tests.h"
      12  
      13  #include <errno.h>
      14  #include <sys/ptrace.h>
      15  #include <signal.h>
      16  #include <stdlib.h>
      17  #include <unistd.h>
      18  #include <sys/uio.h>
      19  #include <sys/wait.h>
      20  
      21  #include "test_ucopy.h"
      22  
      23  #ifndef HAVE_PROCESS_VM_READV
      24  
      25  # include "scno.h"
      26  static ssize_t
      27  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  
      39  #endif /* !HAVE_PROCESS_VM_READV */
      40  
      41  static bool
      42  call_process_vm_readv(const int pid, long *const addr)
      43  {
      44  	long data = 0;
      45  
      46  	const struct iovec local = {
      47  		.iov_base = &data,
      48  		.iov_len = sizeof(data)
      49  	};
      50  	const struct iovec remote = {
      51  		.iov_base = addr,
      52  		.iov_len = sizeof(*addr)
      53  	};
      54  
      55  	return process_vm_readv(pid, &local, 1, &remote, 1, 0) == sizeof(data)
      56  		&& data == 1;
      57  }
      58  
      59  static bool
      60  call_ptrace_peekdata(const int pid, long *const addr)
      61  {
      62  	return ptrace(PTRACE_PEEKDATA, pid, addr, 0) == 1;
      63  }
      64  
      65  static bool
      66  test_ucopy(bool (*fn)(int pid, long *addr))
      67  {
      68  	static long data;
      69  
      70  	data = 0;
      71  	bool rc = false;
      72  	int saved = 0;
      73  
      74  	pid_t pid = fork();
      75  	if (pid < 0)
      76  		perror_msg_and_fail("fork");
      77  
      78  	if (!pid) {
      79  		data = 1;
      80  		if (ptrace(PTRACE_TRACEME, 0, 0, 0))
      81  			perror_msg_and_fail("PTRACE_TRACEME");
      82  		raise(SIGSTOP);
      83  		_exit(0);
      84  	}
      85  
      86  	for (;;) {
      87  		int status, tracee;
      88  
      89  		errno = 0;
      90  		tracee = wait(&status);
      91  		if (tracee != pid) {
      92  			if (errno == EINTR)
      93  				continue;
      94  			saved = errno;
      95  			kill(pid, SIGKILL);
      96  			errno = saved;
      97  			perror_msg_and_fail("wait");
      98  		}
      99  		if (WIFEXITED(status)) {
     100  			if (WEXITSTATUS(status) == 0)
     101  				break;
     102  			error_msg_and_fail("unexpected exit status %u",
     103  					   WEXITSTATUS(status));
     104  		}
     105  		if (WIFSIGNALED(status))
     106  			error_msg_and_fail("unexpected signal %u",
     107  					   WTERMSIG(status));
     108  		if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
     109  			kill(pid, SIGKILL);
     110  			error_msg_and_fail("unexpected wait status %x",
     111  					   status);
     112  		}
     113  
     114  		errno = 0;
     115  		rc = fn(pid, &data);
     116  		if (!rc)
     117  			saved = errno;
     118  
     119  		if (ptrace(PTRACE_CONT, pid, 0, 0)) {
     120  			saved = errno;
     121  			kill(pid, SIGKILL);
     122  			errno = saved;
     123  			perror_msg_and_fail("PTRACE_CONT");
     124  		}
     125  	}
     126  
     127  	if (!rc)
     128  		errno = saved;
     129  	return rc;
     130  }
     131  
     132  bool
     133  test_process_vm_readv(void)
     134  {
     135  	return test_ucopy(call_process_vm_readv);
     136  }
     137  
     138  bool
     139  test_ptrace_peekdata(void)
     140  {
     141  	return test_ucopy(call_ptrace_peekdata);
     142  }