File: test_ucopy.c

package info (click to toggle)
strace 6.13%2Bds-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 71,488 kB
  • sloc: ansic: 176,497; sh: 9,675; makefile: 4,133; cpp: 885; awk: 353; perl: 267; exp: 62; sed: 9
file content (142 lines) | stat: -rw-r--r-- 2,716 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
 * Test whether process_vm_readv and PTRACE_PEEKDATA work.
 *
 * Copyright (c) 2016-2017 Dmitry V. Levin <ldv@strace.io>
 * Copyright (c) 2017-2021 The strace developers.
 * All rights reserved.
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

#include "tests.h"

#include <errno.h>
#include <sys/ptrace.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/uio.h>
#include <sys/wait.h>

#include "test_ucopy.h"

#ifndef HAVE_PROCESS_VM_READV

# include "scno.h"
static ssize_t
strace_process_vm_readv(pid_t pid,
		 const struct iovec *lvec,
		 unsigned long liovcnt,
		 const struct iovec *rvec,
		 unsigned long riovcnt,
		 unsigned long flags)
{
	return syscall(__NR_process_vm_readv,
		       (long) pid, lvec, liovcnt, rvec, riovcnt, flags);
}
# define process_vm_readv strace_process_vm_readv

#endif /* !HAVE_PROCESS_VM_READV */

static bool
call_process_vm_readv(const int pid, long *const addr)
{
	long data = 0;

	const struct iovec local = {
		.iov_base = &data,
		.iov_len = sizeof(data)
	};
	const struct iovec remote = {
		.iov_base = addr,
		.iov_len = sizeof(*addr)
	};

	return process_vm_readv(pid, &local, 1, &remote, 1, 0) == sizeof(data)
		&& data == 1;
}

static bool
call_ptrace_peekdata(const int pid, long *const addr)
{
	return ptrace(PTRACE_PEEKDATA, pid, addr, 0) == 1;
}

static bool
test_ucopy(bool (*fn)(int pid, long *addr))
{
	static long data;

	data = 0;
	bool rc = false;
	int saved = 0;

	pid_t pid = fork();
	if (pid < 0)
		perror_msg_and_fail("fork");

	if (!pid) {
		data = 1;
		if (ptrace(PTRACE_TRACEME, 0, 0, 0))
			perror_msg_and_fail("PTRACE_TRACEME");
		raise(SIGSTOP);
		_exit(0);
	}

	for (;;) {
		int status, tracee;

		errno = 0;
		tracee = wait(&status);
		if (tracee != pid) {
			if (errno == EINTR)
				continue;
			saved = errno;
			kill(pid, SIGKILL);
			errno = saved;
			perror_msg_and_fail("wait");
		}
		if (WIFEXITED(status)) {
			if (WEXITSTATUS(status) == 0)
				break;
			error_msg_and_fail("unexpected exit status %u",
					   WEXITSTATUS(status));
		}
		if (WIFSIGNALED(status))
			error_msg_and_fail("unexpected signal %u",
					   WTERMSIG(status));
		if (!WIFSTOPPED(status) || WSTOPSIG(status) != SIGSTOP) {
			kill(pid, SIGKILL);
			error_msg_and_fail("unexpected wait status %x",
					   status);
		}

		errno = 0;
		rc = fn(pid, &data);
		if (!rc)
			saved = errno;

		if (ptrace(PTRACE_CONT, pid, 0, 0)) {
			saved = errno;
			kill(pid, SIGKILL);
			errno = saved;
			perror_msg_and_fail("PTRACE_CONT");
		}
	}

	if (!rc)
		errno = saved;
	return rc;
}

bool
test_process_vm_readv(void)
{
	return test_ucopy(call_process_vm_readv);
}

bool
test_ptrace_peekdata(void)
{
	return test_ucopy(call_ptrace_peekdata);
}