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/pcb.h>
43 #include <machine/reg.h>
45 #include <amd64/linux/linux.h>
46 #include <amd64/linux/linux_proto.h>
47 #include <compat/linux/linux_emul.h>
48 #include <compat/linux/linux_misc.h>
49 #include <compat/linux/linux_signal.h>
50 #include <compat/linux/linux_util.h>
52 #define LINUX_PTRACE_TRACEME 0
53 #define LINUX_PTRACE_PEEKTEXT 1
54 #define LINUX_PTRACE_PEEKDATA 2
55 #define LINUX_PTRACE_PEEKUSER 3
56 #define LINUX_PTRACE_POKETEXT 4
57 #define LINUX_PTRACE_POKEDATA 5
58 #define LINUX_PTRACE_POKEUSER 6
59 #define LINUX_PTRACE_CONT 7
60 #define LINUX_PTRACE_KILL 8
61 #define LINUX_PTRACE_SINGLESTEP 9
62 #define LINUX_PTRACE_GETREGS 12
63 #define LINUX_PTRACE_SETREGS 13
64 #define LINUX_PTRACE_GETFPREGS 14
65 #define LINUX_PTRACE_SETFPREGS 15
66 #define LINUX_PTRACE_ATTACH 16
67 #define LINUX_PTRACE_DETACH 17
68 #define LINUX_PTRACE_SYSCALL 24
69 #define LINUX_PTRACE_SETOPTIONS 0x4200
70 #define LINUX_PTRACE_GETSIGINFO 0x4202
71 #define LINUX_PTRACE_GETREGSET 0x4204
72 #define LINUX_PTRACE_SEIZE 0x4206
73 #define LINUX_PTRACE_GET_SYSCALL_INFO 0x420e
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 1
90 #define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \
91 LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \
92 LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \
93 LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \
94 LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \
95 LINUX_PTRACE_O_SUSPEND_SECCOMP)
98 map_signum(int lsig, int *bsigp)
107 if (lsig < 0 || lsig > LINUX_SIGRTMAX)
110 bsig = linux_to_bsd_signal(lsig);
119 linux_ptrace_status(struct thread *td, pid_t pid, int status)
121 struct ptrace_lwpinfo lwpinfo;
122 struct linux_pemuldata *pem;
123 register_t saved_retval;
126 saved_retval = td->td_retval[0];
127 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
128 td->td_retval[0] = saved_retval;
130 linux_msg(td, "PT_LWPINFO failed with error %d", error);
134 pem = pem_find(td->td_proc);
135 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
137 LINUX_PEM_SLOCK(pem);
138 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
139 lwpinfo.pl_flags & PL_FLAG_SCE)
140 status |= (LINUX_SIGTRAP | 0x80) << 8;
141 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
142 lwpinfo.pl_flags & PL_FLAG_SCX)
143 status |= (LINUX_SIGTRAP | 0x80) << 8;
144 if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) &&
145 lwpinfo.pl_flags & PL_FLAG_EXITED)
146 status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8;
147 LINUX_PEM_SUNLOCK(pem);
152 struct linux_pt_reg {
177 * Translate amd64 ptrace registers between Linux and FreeBSD formats.
178 * The translation is pretty straighforward, for all registers but
179 * orig_rax on Linux side and r_trapno and r_err in FreeBSD.
182 map_regs_to_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
185 l_reg->r15 = b_reg->r_r15;
186 l_reg->r14 = b_reg->r_r14;
187 l_reg->r13 = b_reg->r_r13;
188 l_reg->r12 = b_reg->r_r12;
189 l_reg->rbp = b_reg->r_rbp;
190 l_reg->rbx = b_reg->r_rbx;
191 l_reg->r11 = b_reg->r_r11;
192 l_reg->r10 = b_reg->r_r10;
193 l_reg->r9 = b_reg->r_r9;
194 l_reg->r8 = b_reg->r_r8;
195 l_reg->rax = b_reg->r_rax;
196 l_reg->rcx = b_reg->r_rcx;
197 l_reg->rdx = b_reg->r_rdx;
198 l_reg->rsi = b_reg->r_rsi;
199 l_reg->rdi = b_reg->r_rdi;
200 l_reg->orig_rax = b_reg->r_rax;
201 l_reg->rip = b_reg->r_rip;
202 l_reg->cs = b_reg->r_cs;
203 l_reg->eflags = b_reg->r_rflags;
204 l_reg->rsp = b_reg->r_rsp;
205 l_reg->ss = b_reg->r_ss;
209 map_regs_from_linux(struct reg *b_reg, struct linux_pt_reg *l_reg)
211 b_reg->r_r15 = l_reg->r15;
212 b_reg->r_r14 = l_reg->r14;
213 b_reg->r_r13 = l_reg->r13;
214 b_reg->r_r12 = l_reg->r12;
215 b_reg->r_r11 = l_reg->r11;
216 b_reg->r_r10 = l_reg->r10;
217 b_reg->r_r9 = l_reg->r9;
218 b_reg->r_r8 = l_reg->r8;
219 b_reg->r_rdi = l_reg->rdi;
220 b_reg->r_rsi = l_reg->rsi;
221 b_reg->r_rbp = l_reg->rbp;
222 b_reg->r_rbx = l_reg->rbx;
223 b_reg->r_rdx = l_reg->rdx;
224 b_reg->r_rcx = l_reg->rcx;
225 b_reg->r_rax = l_reg->rax;
228 * XXX: Are zeroes the right thing to put here?
237 b_reg->r_rip = l_reg->rip;
238 b_reg->r_cs = l_reg->cs;
239 b_reg->r_rflags = l_reg->eflags;
240 b_reg->r_rsp = l_reg->rsp;
241 b_reg->r_ss = l_reg->ss;
245 linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
249 error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
251 error = copyout(td->td_retval, data, sizeof(l_int));
252 else if (error == ENOMEM)
254 td->td_retval[0] = error;
260 linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
263 linux_msg(td, "PTRACE_PEEKUSER not implemented; returning EINVAL");
268 linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
271 linux_msg(td, "PTRACE_POKEUSER not implemented; returning EINVAL");
276 linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
278 struct linux_pemuldata *pem;
283 if (data & ~LINUX_PTRACE_O_MASK) {
284 linux_msg(td, "unknown ptrace option %lx set; "
286 data & ~LINUX_PTRACE_O_MASK);
290 pem = pem_find(td->td_proc);
291 KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
294 * PTRACE_O_EXITKILL is ignored, we do that by default.
297 LINUX_PEM_XLOCK(pem);
298 if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
299 pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
301 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
303 LINUX_PEM_XUNLOCK(pem);
305 if (data & LINUX_PTRACE_O_TRACEFORK)
308 if (data & LINUX_PTRACE_O_TRACEVFORK)
309 mask |= PTRACE_VFORK;
311 if (data & LINUX_PTRACE_O_TRACECLONE)
312 mask |= PTRACE_VFORK;
314 if (data & LINUX_PTRACE_O_TRACEEXEC)
317 if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
318 mask |= PTRACE_VFORK; /* XXX: Close enough? */
320 if (data & LINUX_PTRACE_O_TRACEEXIT) {
321 pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
323 pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
326 return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
330 linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
332 struct ptrace_lwpinfo lwpinfo;
333 l_siginfo_t l_siginfo;
336 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
338 linux_msg(td, "PT_LWPINFO failed with error %d", error);
342 if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
344 linux_msg(td, "no PL_FLAG_SI, returning %d", error);
348 sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
349 memset(&l_siginfo, 0, sizeof(l_siginfo));
350 siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
351 error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
356 linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
358 struct ptrace_lwpinfo lwpinfo;
360 struct linux_pt_reg l_reg;
363 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
367 map_regs_to_linux(&b_reg, &l_reg);
369 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
371 linux_msg(td, "PT_LWPINFO failed with error %d", error);
374 if (lwpinfo.pl_flags & PL_FLAG_SCE) {
376 * The strace(1) utility depends on RAX being set to -ENOSYS
377 * on syscall entry; otherwise it loops printing those:
379 * [ Process PID=928 runs in 64 bit mode. ]
380 * [ Process PID=928 runs in x32 mode. ]
382 l_reg.rax = -38; /* -ENOSYS */
385 * Undo the mangling done in exception.S:fast_syscall_common().
387 l_reg.r10 = l_reg.rcx;
390 error = copyout(&l_reg, (void *)data, sizeof(l_reg));
395 linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
398 struct linux_pt_reg l_reg;
401 error = copyin(data, &l_reg, sizeof(l_reg));
404 map_regs_from_linux(&b_reg, &l_reg);
405 error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
410 linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
412 struct ptrace_lwpinfo lwpinfo;
414 struct linux_pt_regset l_regset;
420 error = copyin((const void *)data, &iov, sizeof(iov));
422 linux_msg(td, "copyin error %d", error);
426 error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
432 update_pcb_bases(pcb);
434 bsd_to_linux_regset(&b_reg, &l_regset);
435 l_regset.fs_base = pcb->pcb_fsbase;
436 l_regset.gs_base = pcb->pcb_gsbase;
438 error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
440 linux_msg(td, "PT_LWPINFO failed with error %d", error);
443 if (lwpinfo.pl_flags & PL_FLAG_SCE) {
445 * Undo the mangling done in exception.S:fast_syscall_common().
447 l_regset.r10 = l_regset.rcx;
450 if (lwpinfo.pl_flags & (PL_FLAG_SCE | PL_FLAG_SCX)) {
452 * In Linux, the syscall number - passed to the syscall
453 * as rax - is preserved in orig_rax; rax gets overwritten
454 * with syscall return value.
456 l_regset.orig_rax = lwpinfo.pl_syscall_code;
459 len = MIN(iov.iov_len, sizeof(l_regset));
460 error = copyout(&l_regset, (void *)iov.iov_base, len);
462 linux_msg(td, "copyout error %d", error);
467 error = copyout(&iov, (void *)data, sizeof(iov));
469 linux_msg(td, "iov copyout error %d", error);
477 linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
481 case LINUX_NT_PRSTATUS:
482 return (linux_ptrace_getregset_prstatus(td, pid, data));
484 linux_msg(td, "PTRACE_GETREGSET request %ld not implemented; "
485 "returning EINVAL", addr);
491 linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
494 linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
499 linux_ptrace_get_syscall_info(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
502 linux_msg(td, "PTRACE_GET_SYSCALL_INFO not implemented; returning EINVAL");
507 linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
513 pid = (pid_t)uap->pid;
514 addr = (void *)uap->addr;
517 case LINUX_PTRACE_TRACEME:
518 error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
520 case LINUX_PTRACE_PEEKTEXT:
521 case LINUX_PTRACE_PEEKDATA:
522 error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
526 * Linux expects this syscall to read 64 bits, not 32.
528 error = linux_ptrace_peek(td, pid,
529 (void *)(uap->addr + 4), (void *)(uap->data + 4));
531 case LINUX_PTRACE_PEEKUSER:
532 error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
534 case LINUX_PTRACE_POKETEXT:
535 case LINUX_PTRACE_POKEDATA:
536 error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
540 * Linux expects this syscall to write 64 bits, not 32.
542 error = kern_ptrace(td, PT_WRITE_D, pid,
543 (void *)(uap->addr + 4), uap->data >> 32);
545 case LINUX_PTRACE_POKEUSER:
546 error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
548 case LINUX_PTRACE_CONT:
549 error = map_signum(uap->data, &sig);
552 error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
554 case LINUX_PTRACE_KILL:
555 error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
557 case LINUX_PTRACE_SINGLESTEP:
558 error = map_signum(uap->data, &sig);
561 error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
563 case LINUX_PTRACE_GETREGS:
564 error = linux_ptrace_getregs(td, pid, (void *)uap->data);
566 case LINUX_PTRACE_SETREGS:
567 error = linux_ptrace_setregs(td, pid, (void *)uap->data);
569 case LINUX_PTRACE_ATTACH:
570 error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
572 case LINUX_PTRACE_DETACH:
573 error = map_signum(uap->data, &sig);
576 error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
578 case LINUX_PTRACE_SYSCALL:
579 error = map_signum(uap->data, &sig);
582 error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
584 case LINUX_PTRACE_SETOPTIONS:
585 error = linux_ptrace_setoptions(td, pid, uap->data);
587 case LINUX_PTRACE_GETSIGINFO:
588 error = linux_ptrace_getsiginfo(td, pid, uap->data);
590 case LINUX_PTRACE_GETREGSET:
591 error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
593 case LINUX_PTRACE_SEIZE:
594 error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
596 case LINUX_PTRACE_GET_SYSCALL_INFO:
597 error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
600 linux_msg(td, "ptrace(%ld, ...) not implemented; "
601 "returning EINVAL", uap->req);