xref: /freebsd/sys/compat/linux/linux_ptrace.c (revision 61e21613)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
3  *
4  * Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org>
5  *
6  * This software was developed by SRI International and the University of
7  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
8  * ("CTSRD"), as part of the DARPA CRASH research programme.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/param.h>
33 #include <sys/lock.h>
34 #include <sys/proc.h>
35 #include <sys/ptrace.h>
36 #include <sys/sx.h>
37 #include <sys/syscallsubr.h>
38 
39 #include <machine/../linux/linux.h>
40 #include <machine/../linux/linux_proto.h>
41 #include <compat/linux/linux_emul.h>
42 #include <compat/linux/linux_errno.h>
43 #include <compat/linux/linux_misc.h>
44 #include <compat/linux/linux_signal.h>
45 #include <compat/linux/linux_util.h>
46 
47 #define	LINUX_PTRACE_TRACEME		0
48 #define	LINUX_PTRACE_PEEKTEXT		1
49 #define	LINUX_PTRACE_PEEKDATA		2
50 #define	LINUX_PTRACE_PEEKUSER		3
51 #define	LINUX_PTRACE_POKETEXT		4
52 #define	LINUX_PTRACE_POKEDATA		5
53 #define	LINUX_PTRACE_POKEUSER		6
54 #define	LINUX_PTRACE_CONT		7
55 #define	LINUX_PTRACE_KILL		8
56 #define	LINUX_PTRACE_SINGLESTEP		9
57 #define	LINUX_PTRACE_GETREGS		12
58 #define	LINUX_PTRACE_SETREGS		13
59 #define	LINUX_PTRACE_GETFPREGS		14
60 #define	LINUX_PTRACE_SETFPREGS		15
61 #define	LINUX_PTRACE_ATTACH		16
62 #define	LINUX_PTRACE_DETACH		17
63 #define	LINUX_PTRACE_SYSCALL		24
64 #define	LINUX_PTRACE_SETOPTIONS		0x4200
65 #define	LINUX_PTRACE_GETEVENTMSG	0x4201
66 #define	LINUX_PTRACE_GETSIGINFO		0x4202
67 #define	LINUX_PTRACE_GETREGSET		0x4204
68 #define	LINUX_PTRACE_SEIZE		0x4206
69 #define	LINUX_PTRACE_GET_SYSCALL_INFO	0x420e
70 
71 #define	LINUX_PTRACE_EVENT_EXEC		4
72 #define	LINUX_PTRACE_EVENT_EXIT		6
73 
74 #define	LINUX_PTRACE_O_TRACESYSGOOD	1
75 #define	LINUX_PTRACE_O_TRACEFORK	2
76 #define	LINUX_PTRACE_O_TRACEVFORK	4
77 #define	LINUX_PTRACE_O_TRACECLONE	8
78 #define	LINUX_PTRACE_O_TRACEEXEC	16
79 #define	LINUX_PTRACE_O_TRACEVFORKDONE	32
80 #define	LINUX_PTRACE_O_TRACEEXIT	64
81 #define	LINUX_PTRACE_O_TRACESECCOMP	128
82 #define	LINUX_PTRACE_O_EXITKILL		1048576
83 #define	LINUX_PTRACE_O_SUSPEND_SECCOMP	2097152
84 
85 #define	LINUX_NT_PRSTATUS		0x1
86 #define	LINUX_NT_PRFPREG		0x2
87 #define	LINUX_NT_X86_XSTATE		0x202
88 
89 #define	LINUX_PTRACE_O_MASK	(LINUX_PTRACE_O_TRACESYSGOOD |	\
90     LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK |	\
91     LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC |	\
92     LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT |	\
93     LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL |	\
94     LINUX_PTRACE_O_SUSPEND_SECCOMP)
95 
96 #define	LINUX_PTRACE_SYSCALL_INFO_NONE	0
97 #define	LINUX_PTRACE_SYSCALL_INFO_ENTRY	1
98 #define	LINUX_PTRACE_SYSCALL_INFO_EXIT	2
99 
100 static int
101 map_signum(int lsig, int *bsigp)
102 {
103 	int bsig;
104 
105 	if (lsig == 0) {
106 		*bsigp = 0;
107 		return (0);
108 	}
109 
110 	if (lsig < 0 || lsig > LINUX_SIGRTMAX)
111 		return (EINVAL);
112 
113 	bsig = linux_to_bsd_signal(lsig);
114 	if (bsig == SIGSTOP)
115 		bsig = 0;
116 
117 	*bsigp = bsig;
118 	return (0);
119 }
120 
121 int
122 linux_ptrace_status(struct thread *td, pid_t pid, int status)
123 {
124 	struct ptrace_lwpinfo lwpinfo;
125 	struct linux_pemuldata *pem;
126 	register_t saved_retval;
127 	int error;
128 
129 	saved_retval = td->td_retval[0];
130 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
131 	td->td_retval[0] = saved_retval;
132 	if (error != 0) {
133 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
134 		return (status);
135 	}
136 
137 	pem = pem_find(td->td_proc);
138 	KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
139 
140 	LINUX_PEM_SLOCK(pem);
141 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
142 	    lwpinfo.pl_flags & PL_FLAG_SCE)
143 		status |= (LINUX_SIGTRAP | 0x80) << 8;
144 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
145 	    lwpinfo.pl_flags & PL_FLAG_SCX) {
146 		if (lwpinfo.pl_flags & PL_FLAG_EXEC)
147 			status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8;
148 		else
149 			status |= (LINUX_SIGTRAP | 0x80) << 8;
150 	}
151 	if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) &&
152 	    lwpinfo.pl_flags & PL_FLAG_EXITED)
153 		status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8;
154 	LINUX_PEM_SUNLOCK(pem);
155 
156 	return (status);
157 }
158 
159 static int
160 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
161 {
162 	int error;
163 
164 	error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
165 	if (error == 0)
166 		error = copyout(td->td_retval, data, sizeof(l_int));
167 	else if (error == ENOMEM)
168 		error = EIO;
169 	td->td_retval[0] = error;
170 
171 	return (error);
172 }
173 
174 static int
175 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
176 {
177 	struct linux_pemuldata *pem;
178 	int mask;
179 
180 	mask = 0;
181 
182 	if (data & ~LINUX_PTRACE_O_MASK) {
183 		linux_msg(td, "unknown ptrace option %lx set; "
184 		    "returning EINVAL",
185 		    data & ~LINUX_PTRACE_O_MASK);
186 		return (EINVAL);
187 	}
188 
189 	pem = pem_find(td->td_proc);
190 	KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
191 
192 	/*
193 	 * PTRACE_O_EXITKILL is ignored, we do that by default.
194 	 */
195 
196 	LINUX_PEM_XLOCK(pem);
197 	if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
198 		pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
199 	} else {
200 		pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
201 	}
202 	LINUX_PEM_XUNLOCK(pem);
203 
204 	if (data & LINUX_PTRACE_O_TRACEFORK)
205 		mask |= PTRACE_FORK;
206 
207 	if (data & LINUX_PTRACE_O_TRACEVFORK)
208 		mask |= PTRACE_VFORK;
209 
210 	if (data & LINUX_PTRACE_O_TRACECLONE)
211 		mask |= PTRACE_VFORK;
212 
213 	if (data & LINUX_PTRACE_O_TRACEEXEC)
214 		mask |= PTRACE_EXEC;
215 
216 	if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
217 		mask |= PTRACE_VFORK; /* XXX: Close enough? */
218 
219 	if (data & LINUX_PTRACE_O_TRACEEXIT) {
220 		pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
221 	} else {
222 		pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
223 	}
224 
225 	return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
226 }
227 
228 static int
229 linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data)
230 {
231 
232 	linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL");
233 	return (EINVAL);
234 }
235 
236 static int
237 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
238 {
239 	struct ptrace_lwpinfo lwpinfo;
240 	l_siginfo_t l_siginfo;
241 	int error, sig;
242 
243 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
244 	if (error != 0) {
245 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
246 		return (error);
247 	}
248 
249 	if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
250 		error = EINVAL;
251 		linux_msg(td, "no PL_FLAG_SI, returning %d", error);
252 		return (error);
253 	}
254 
255 	sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
256 	memset(&l_siginfo, 0, sizeof(l_siginfo));
257 	siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
258 	error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
259 	return (error);
260 }
261 
262 static int
263 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
264 {
265 	struct reg b_reg;
266 	struct linux_pt_regset l_regset;
267 	int error;
268 
269 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
270 	if (error != 0)
271 		return (error);
272 
273 	bsd_to_linux_regset(&b_reg, &l_regset);
274 	error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
275 	if (error != 0)
276 		return (error);
277 
278 	error = copyout(&l_regset, (void *)data, sizeof(l_regset));
279 	return (error);
280 }
281 
282 static int
283 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
284 {
285 	struct reg b_reg;
286 	struct linux_pt_regset l_regset;
287 	int error;
288 
289 	error = copyin(data, &l_regset, sizeof(l_regset));
290 	if (error != 0)
291 		return (error);
292 	linux_to_bsd_regset(&b_reg, &l_regset);
293 	error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
294 	return (error);
295 }
296 
297 static int
298 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
299 {
300 	struct reg b_reg;
301 	struct linux_pt_regset l_regset;
302 	struct iovec iov;
303 	size_t len;
304 	int error;
305 
306 	error = copyin((const void *)data, &iov, sizeof(iov));
307 	if (error != 0) {
308 		linux_msg(td, "copyin error %d", error);
309 		return (error);
310 	}
311 
312 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
313 	if (error != 0)
314 		return (error);
315 
316 	bsd_to_linux_regset(&b_reg, &l_regset);
317 	error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
318 	if (error != 0)
319 		return (error);
320 
321 	len = MIN(iov.iov_len, sizeof(l_regset));
322 	error = copyout(&l_regset, (void *)iov.iov_base, len);
323 	if (error != 0) {
324 		linux_msg(td, "copyout error %d", error);
325 		return (error);
326 	}
327 
328 	iov.iov_len = len;
329 	error = copyout(&iov, (void *)data, sizeof(iov));
330 	if (error != 0) {
331 		linux_msg(td, "iov copyout error %d", error);
332 		return (error);
333 	}
334 
335 	return (error);
336 }
337 
338 static int
339 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
340 {
341 
342 	switch (addr) {
343 	case LINUX_NT_PRSTATUS:
344 		return (linux_ptrace_getregset_prstatus(td, pid, data));
345 	case LINUX_NT_PRFPREG:
346 		linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; "
347 		    "returning EINVAL");
348 		return (EINVAL);
349 	case LINUX_NT_X86_XSTATE:
350 		linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; "
351 		    "returning EINVAL");
352 		return (EINVAL);
353 	default:
354 		linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; "
355 		    "returning EINVAL", addr);
356 		return (EINVAL);
357 	}
358 }
359 
360 static int
361 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
362 {
363 
364 	linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
365 	return (EINVAL);
366 }
367 
368 static int
369 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid,
370     l_ulong len, l_ulong data)
371 {
372 	struct ptrace_lwpinfo lwpinfo;
373 	struct ptrace_sc_ret sr;
374 	struct reg b_reg;
375 	struct syscall_info si;
376 	int error;
377 
378 	error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
379 	if (error != 0) {
380 		linux_msg(td, "PT_LWPINFO failed with error %d", error);
381 		return (error);
382 	}
383 
384 	memset(&si, 0, sizeof(si));
385 
386 	if (lwpinfo.pl_flags & PL_FLAG_SCE) {
387 		si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY;
388 		si.entry.nr = lwpinfo.pl_syscall_code;
389 		/*
390 		 * The use of PT_GET_SC_ARGS there is special,
391 		 * implementation of PT_GET_SC_ARGS for Linux-ABI
392 		 * callers emulates Linux bug which strace(1) depends
393 		 * on: at initialization it tests whether ptrace works
394 		 * by calling close(2), or some other single-argument
395 		 * syscall, _with six arguments_, and then verifies
396 		 * whether it can fetch them all using this API;
397 		 * otherwise it bails out.
398 		 */
399 		error = kern_ptrace(td, PT_GET_SC_ARGS, pid,
400 		    &si.entry.args, sizeof(si.entry.args));
401 		if (error != 0) {
402 			linux_msg(td, "PT_GET_SC_ARGS failed with error %d",
403 			    error);
404 			return (error);
405 		}
406 	} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
407 		si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT;
408 		error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr));
409 
410 		if (error != 0) {
411 			linux_msg(td, "PT_GET_SC_RET failed with error %d",
412 			    error);
413 			return (error);
414 		}
415 
416 		if (sr.sr_error == 0) {
417 			si.exit.rval = sr.sr_retval[0];
418 			si.exit.is_error = 0;
419 		} else if (sr.sr_error == EJUSTRETURN) {
420 			/*
421 			 * EJUSTRETURN means the actual value to return
422 			 * has already been put into td_frame; instead
423 			 * of extracting it and trying to determine whether
424 			 * it's an error or not just bail out and let
425 			 * the ptracing process fall back to another method.
426 			 */
427 			si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
428 		} else if (sr.sr_error == ERESTART) {
429 			si.exit.rval = -LINUX_ERESTARTSYS;
430 			si.exit.is_error = 1;
431 		} else {
432 			si.exit.rval = bsd_to_linux_errno(sr.sr_error);
433 			si.exit.is_error = 1;
434 		}
435 	} else {
436 		si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
437 	}
438 
439 	error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
440 	if (error != 0)
441 		return (error);
442 
443 	linux_ptrace_get_syscall_info_machdep(&b_reg, &si);
444 
445 	len = MIN(len, sizeof(si));
446 	error = copyout(&si, (void *)data, len);
447 	if (error == 0)
448 		td->td_retval[0] = sizeof(si);
449 
450 	return (error);
451 }
452 
453 int
454 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
455 {
456 	void *addr;
457 	pid_t pid;
458 	int error, sig;
459 
460 	if (!allow_ptrace)
461 		return (ENOSYS);
462 
463 	pid  = (pid_t)uap->pid;
464 	addr = (void *)uap->addr;
465 
466 	switch (uap->req) {
467 	case LINUX_PTRACE_TRACEME:
468 		error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
469 		break;
470 	case LINUX_PTRACE_PEEKTEXT:
471 	case LINUX_PTRACE_PEEKDATA:
472 		error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
473 		if (error != 0)
474 			goto out;
475 		/*
476 		 * Linux expects this syscall to read 64 bits, not 32.
477 		 */
478 		error = linux_ptrace_peek(td, pid,
479 		    (void *)(uap->addr + 4), (void *)(uap->data + 4));
480 		break;
481 	case LINUX_PTRACE_PEEKUSER:
482 		error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
483 		break;
484 	case LINUX_PTRACE_POKETEXT:
485 	case LINUX_PTRACE_POKEDATA:
486 		error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
487 		if (error != 0)
488 			goto out;
489 		/*
490 		 * Linux expects this syscall to write 64 bits, not 32.
491 		 */
492 		error = kern_ptrace(td, PT_WRITE_D, pid,
493 		    (void *)(uap->addr + 4), uap->data >> 32);
494 		break;
495 	case LINUX_PTRACE_POKEUSER:
496 		error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
497 		break;
498 	case LINUX_PTRACE_CONT:
499 		error = map_signum(uap->data, &sig);
500 		if (error != 0)
501 			break;
502 		error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
503 		break;
504 	case LINUX_PTRACE_KILL:
505 		error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
506 		break;
507 	case LINUX_PTRACE_SINGLESTEP:
508 		error = map_signum(uap->data, &sig);
509 		if (error != 0)
510 			break;
511 		error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
512 		break;
513 	case LINUX_PTRACE_GETREGS:
514 		error = linux_ptrace_getregs(td, pid, (void *)uap->data);
515 		break;
516 	case LINUX_PTRACE_SETREGS:
517 		error = linux_ptrace_setregs(td, pid, (void *)uap->data);
518 		break;
519 	case LINUX_PTRACE_ATTACH:
520 		error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
521 		break;
522 	case LINUX_PTRACE_DETACH:
523 		error = map_signum(uap->data, &sig);
524 		if (error != 0)
525 			break;
526 		error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
527 		break;
528 	case LINUX_PTRACE_SYSCALL:
529 		error = map_signum(uap->data, &sig);
530 		if (error != 0)
531 			break;
532 		error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
533 		break;
534 	case LINUX_PTRACE_SETOPTIONS:
535 		error = linux_ptrace_setoptions(td, pid, uap->data);
536 		break;
537 	case LINUX_PTRACE_GETEVENTMSG:
538 		error = linux_ptrace_geteventmsg(td, pid, uap->data);
539 		break;
540 	case LINUX_PTRACE_GETSIGINFO:
541 		error = linux_ptrace_getsiginfo(td, pid, uap->data);
542 		break;
543 	case LINUX_PTRACE_GETREGSET:
544 		error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
545 		break;
546 	case LINUX_PTRACE_SEIZE:
547 		error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
548 		break;
549 	case LINUX_PTRACE_GET_SYSCALL_INFO:
550 		error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
551 		break;
552 	default:
553 		linux_msg(td, "ptrace(%ld, ...) not implemented; "
554 		    "returning EINVAL", uap->req);
555 		error = EINVAL;
556 		break;
557 	}
558 
559 out:
560 	if (error == EBUSY)
561 		error = ESRCH;
562 
563 	return (error);
564 }
565