2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org>
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.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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
32 #include <sys/cdefs.h>
33 __FBSDID("$FreeBSD$");
35 #include <sys/param.h>
38 #include <sys/ptrace.h>
40 #include <sys/syscallsubr.h>
42 #include <machine/../linux/linux.h>
43 #include <machine/../linux/linux_proto.h>
44 #include <compat/linux/linux_emul.h>
45 #include <compat/linux/linux_errno.h>
46 #include <compat/linux/linux_misc.h>
47 #include <compat/linux/linux_signal.h>
48 #include <compat/linux/linux_util.h>
50 #define LINUX_PTRACE_TRACEME 0
51 #define LINUX_PTRACE_PEEKTEXT 1
52 #define LINUX_PTRACE_PEEKDATA 2
53 #define LINUX_PTRACE_PEEKUSER 3
54 #define LINUX_PTRACE_POKETEXT 4
55 #define LINUX_PTRACE_POKEDATA 5
56 #define LINUX_PTRACE_POKEUSER 6
57 #define LINUX_PTRACE_CONT 7
58 #define LINUX_PTRACE_KILL 8
59 #define LINUX_PTRACE_SINGLESTEP 9
60 #define LINUX_PTRACE_GETREGS 12
61 #define LINUX_PTRACE_SETREGS 13
62 #define LINUX_PTRACE_GETFPREGS 14
63 #define LINUX_PTRACE_SETFPREGS 15
64 #define LINUX_PTRACE_ATTACH 16
65 #define LINUX_PTRACE_DETACH 17
66 #define LINUX_PTRACE_SYSCALL 24
67 #define LINUX_PTRACE_SETOPTIONS 0x4200
68 #define LINUX_PTRACE_GETEVENTMSG 0x4201
69 #define LINUX_PTRACE_GETSIGINFO 0x4202
70 #define LINUX_PTRACE_GETREGSET 0x4204
71 #define LINUX_PTRACE_SEIZE 0x4206
72 #define LINUX_PTRACE_GET_SYSCALL_INFO 0x420e
74 #define LINUX_PTRACE_EVENT_EXEC 4
75 #define LINUX_PTRACE_EVENT_EXIT 6
77 #define LINUX_PTRACE_O_TRACESYSGOOD 1
78 #define LINUX_PTRACE_O_TRACEFORK 2
79 #define LINUX_PTRACE_O_TRACEVFORK 4
80 #define LINUX_PTRACE_O_TRACECLONE 8
81 #define LINUX_PTRACE_O_TRACEEXEC 16
82 #define LINUX_PTRACE_O_TRACEVFORKDONE 32
83 #define LINUX_PTRACE_O_TRACEEXIT 64
84 #define LINUX_PTRACE_O_TRACESECCOMP 128
85 #define LINUX_PTRACE_O_EXITKILL 1048576
86 #define LINUX_PTRACE_O_SUSPEND_SECCOMP 2097152
88 #define LINUX_NT_PRSTATUS 0x1
89 #define LINUX_NT_PRFPREG 0x2
90 #define LINUX_NT_X86_XSTATE 0x202
92 #define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \
93 LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \
94 LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \
95 LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \
96 LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \
97 LINUX_PTRACE_O_SUSPEND_SECCOMP)
99 #define LINUX_PTRACE_SYSCALL_INFO_NONE 0
100 #define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1
101 #define LINUX_PTRACE_SYSCALL_INFO_EXIT 2
103 #define LINUX_PTRACE_PEEKUSER_ORIG_RAX 120
104 #define LINUX_PTRACE_PEEKUSER_RIP 128
105 #define LINUX_PTRACE_PEEKUSER_CS 136
106 #define LINUX_PTRACE_PEEKUSER_DS 184
109 map_signum(int lsig, int *bsigp)
118 if (lsig < 0 || lsig > LINUX_SIGRTMAX)
121 bsig = linux_to_bsd_signal(lsig);
130 linux_ptrace_status(struct thread *td, pid_t pid, int status)
132 struct ptrace_lwpinfo lwpinfo;
133 struct linux_pemuldata *pem;
134 register_t saved_retval;
137 saved_retval = td->td_retval[0];
138 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
139 td->td_retval[0] = saved_retval;
141 linux_msg(td, "PT_LWPINFO failed with error %d", error);
145 pem = pem_find(td->td_proc);
146 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
148 LINUX_PEM_SLOCK(pem);
149 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
150 lwpinfo.pl_flags & PL_FLAG_SCE)
151 status |= (LINUX_SIGTRAP | 0x80) << 8;
152 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
153 lwpinfo.pl_flags & PL_FLAG_SCX) {
154 if (lwpinfo.pl_flags & PL_FLAG_EXEC)
155 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8;
157 status |= (LINUX_SIGTRAP | 0x80) << 8;
159 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) &&
160 lwpinfo.pl_flags & PL_FLAG_EXITED)
161 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8;
162 LINUX_PEM_SUNLOCK(pem);
168 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
172 error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
174 error = copyout(td->td_retval, data, sizeof(l_int));
175 else if (error == ENOMEM)
177 td->td_retval[0] = error;
183 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
189 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
193 switch ((uintptr_t)addr) {
195 case LINUX_PTRACE_PEEKUSER_ORIG_RAX:
198 case LINUX_PTRACE_PEEKUSER_RIP:
201 case LINUX_PTRACE_PEEKUSER_CS:
204 case LINUX_PTRACE_PEEKUSER_DS:
207 #endif /* __amd64__ */
209 linux_msg(td, "PTRACE_PEEKUSER offset %ld not implemented; "
210 "returning EINVAL", (uintptr_t)addr);
214 error = copyout(&val, data, sizeof(val));
215 td->td_retval[0] = error;
221 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
224 linux_msg(td, "PTRACE_POKEUSER not implemented; returning EINVAL");
229 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
231 struct linux_pemuldata *pem;
236 if (data & ~LINUX_PTRACE_O_MASK) {
237 linux_msg(td, "unknown ptrace option %lx set; "
239 data & ~LINUX_PTRACE_O_MASK);
243 pem = pem_find(td->td_proc);
244 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
247 * PTRACE_O_EXITKILL is ignored, we do that by default.
250 LINUX_PEM_XLOCK(pem);
251 if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
252 pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
254 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
256 LINUX_PEM_XUNLOCK(pem);
258 if (data & LINUX_PTRACE_O_TRACEFORK)
261 if (data & LINUX_PTRACE_O_TRACEVFORK)
262 mask |= PTRACE_VFORK;
264 if (data & LINUX_PTRACE_O_TRACECLONE)
265 mask |= PTRACE_VFORK;
267 if (data & LINUX_PTRACE_O_TRACEEXEC)
270 if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
271 mask |= PTRACE_VFORK; /* XXX: Close enough? */
273 if (data & LINUX_PTRACE_O_TRACEEXIT) {
274 pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
276 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
279 return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
283 linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data)
286 linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL");
291 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
293 struct ptrace_lwpinfo lwpinfo;
294 l_siginfo_t l_siginfo;
297 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
299 linux_msg(td, "PT_LWPINFO failed with error %d", error);
303 if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
305 linux_msg(td, "no PL_FLAG_SI, returning %d", error);
309 sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
310 memset(&l_siginfo, 0, sizeof(l_siginfo));
311 siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
312 error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
317 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
320 struct linux_pt_regset l_regset;
323 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
327 bsd_to_linux_regset(&b_reg, &l_regset);
328 error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
332 error = copyout(&l_regset, (void *)data, sizeof(l_regset));
337 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
340 struct linux_pt_regset l_regset;
343 error = copyin(data, &l_regset, sizeof(l_regset));
346 linux_to_bsd_regset(&b_reg, &l_regset);
347 error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
352 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
355 struct linux_pt_regset l_regset;
360 error = copyin((const void *)data, &iov, sizeof(iov));
362 linux_msg(td, "copyin error %d", error);
366 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
370 bsd_to_linux_regset(&b_reg, &l_regset);
371 error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
375 len = MIN(iov.iov_len, sizeof(l_regset));
376 error = copyout(&l_regset, (void *)iov.iov_base, len);
378 linux_msg(td, "copyout error %d", error);
383 error = copyout(&iov, (void *)data, sizeof(iov));
385 linux_msg(td, "iov copyout error %d", error);
393 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
397 case LINUX_NT_PRSTATUS:
398 return (linux_ptrace_getregset_prstatus(td, pid, data));
399 case LINUX_NT_PRFPREG:
400 linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; "
403 case LINUX_NT_X86_XSTATE:
404 linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; "
408 linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; "
409 "returning EINVAL", addr);
415 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
418 linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
423 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid,
424 l_ulong len, l_ulong data)
426 struct ptrace_lwpinfo lwpinfo;
427 struct ptrace_sc_ret sr;
429 struct syscall_info si;
432 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
434 linux_msg(td, "PT_LWPINFO failed with error %d", error);
438 memset(&si, 0, sizeof(si));
440 if (lwpinfo.pl_flags & PL_FLAG_SCE) {
441 si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY;
442 si.entry.nr = lwpinfo.pl_syscall_code;
444 * The use of PT_GET_SC_ARGS there is special,
445 * implementation of PT_GET_SC_ARGS for Linux-ABI
446 * callers emulates Linux bug which strace(1) depends
447 * on: at initialization it tests whether ptrace works
448 * by calling close(2), or some other single-argument
449 * syscall, _with six arguments_, and then verifies
450 * whether it can fetch them all using this API;
451 * otherwise it bails out.
453 error = kern_ptrace(td, PT_GET_SC_ARGS, pid,
454 &si.entry.args, sizeof(si.entry.args));
456 linux_msg(td, "PT_GET_SC_ARGS failed with error %d",
460 } else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
461 si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT;
462 error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr));
465 linux_msg(td, "PT_GET_SC_RET failed with error %d",
470 if (sr.sr_error == 0) {
471 si.exit.rval = sr.sr_retval[0];
472 si.exit.is_error = 0;
473 } else if (sr.sr_error == EJUSTRETURN) {
475 * EJUSTRETURN means the actual value to return
476 * has already been put into td_frame; instead
477 * of extracting it and trying to determine whether
478 * it's an error or not just bail out and let
479 * the ptracing process fall back to another method.
481 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
482 } else if (sr.sr_error == ERESTART) {
483 si.exit.rval = -LINUX_ERESTARTSYS;
484 si.exit.is_error = 1;
486 si.exit.rval = bsd_to_linux_errno(sr.sr_error);
487 si.exit.is_error = 1;
490 si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
493 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
497 linux_ptrace_get_syscall_info_machdep(&b_reg, &si);
499 len = MIN(len, sizeof(si));
500 error = copyout(&si, (void *)data, len);
502 td->td_retval[0] = sizeof(si);
508 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
514 pid = (pid_t)uap->pid;
515 addr = (void *)uap->addr;
518 case LINUX_PTRACE_TRACEME:
519 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
521 case LINUX_PTRACE_PEEKTEXT:
522 case LINUX_PTRACE_PEEKDATA:
523 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
527 * Linux expects this syscall to read 64 bits, not 32.
529 error = linux_ptrace_peek(td, pid,
530 (void *)(uap->addr + 4), (void *)(uap->data + 4));
532 case LINUX_PTRACE_PEEKUSER:
533 error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
535 case LINUX_PTRACE_POKETEXT:
536 case LINUX_PTRACE_POKEDATA:
537 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
541 * Linux expects this syscall to write 64 bits, not 32.
543 error = kern_ptrace(td, PT_WRITE_D, pid,
544 (void *)(uap->addr + 4), uap->data >> 32);
546 case LINUX_PTRACE_POKEUSER:
547 error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
549 case LINUX_PTRACE_CONT:
550 error = map_signum(uap->data, &sig);
553 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
555 case LINUX_PTRACE_KILL:
556 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
558 case LINUX_PTRACE_SINGLESTEP:
559 error = map_signum(uap->data, &sig);
562 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
564 case LINUX_PTRACE_GETREGS:
565 error = linux_ptrace_getregs(td, pid, (void *)uap->data);
567 case LINUX_PTRACE_SETREGS:
568 error = linux_ptrace_setregs(td, pid, (void *)uap->data);
570 case LINUX_PTRACE_ATTACH:
571 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
573 case LINUX_PTRACE_DETACH:
574 error = map_signum(uap->data, &sig);
577 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
579 case LINUX_PTRACE_SYSCALL:
580 error = map_signum(uap->data, &sig);
583 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
585 case LINUX_PTRACE_SETOPTIONS:
586 error = linux_ptrace_setoptions(td, pid, uap->data);
588 case LINUX_PTRACE_GETEVENTMSG:
589 error = linux_ptrace_geteventmsg(td, pid, uap->data);
591 case LINUX_PTRACE_GETSIGINFO:
592 error = linux_ptrace_getsiginfo(td, pid, uap->data);
594 case LINUX_PTRACE_GETREGSET:
595 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
597 case LINUX_PTRACE_SEIZE:
598 error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
600 case LINUX_PTRACE_GET_SYSCALL_INFO:
601 error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
604 linux_msg(td, "ptrace(%ld, ...) not implemented; "
605 "returning EINVAL", uap->req);