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