2017-02-16 13:32:15 +00:00
|
|
|
/*-
|
2018-01-24 17:04:01 +00:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
|
|
|
*
|
2017-02-16 13:32:15 +00:00
|
|
|
* Copyright (c) 2017 Edward Tomasz Napierala <trasz@FreeBSD.org>
|
|
|
|
*
|
|
|
|
* This software was developed by SRI International and the University of
|
|
|
|
* Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
|
|
|
|
* ("CTSRD"), as part of the DARPA CRASH research programme.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <sys/cdefs.h>
|
|
|
|
__FBSDID("$FreeBSD$");
|
|
|
|
|
|
|
|
#include <sys/param.h>
|
2019-05-19 12:58:44 +00:00
|
|
|
#include <sys/lock.h>
|
2017-02-16 13:32:15 +00:00
|
|
|
#include <sys/proc.h>
|
|
|
|
#include <sys/ptrace.h>
|
2019-05-19 12:58:44 +00:00
|
|
|
#include <sys/sx.h>
|
2017-02-16 13:32:15 +00:00
|
|
|
#include <sys/syscallsubr.h>
|
|
|
|
|
2021-11-06 07:56:51 +00:00
|
|
|
#include <machine/../linux/linux.h>
|
|
|
|
#include <machine/../linux/linux_proto.h>
|
2019-05-19 12:58:44 +00:00
|
|
|
#include <compat/linux/linux_emul.h>
|
2021-10-29 13:21:21 +00:00
|
|
|
#include <compat/linux/linux_errno.h>
|
2019-05-19 12:58:44 +00:00
|
|
|
#include <compat/linux/linux_misc.h>
|
2017-02-16 13:32:15 +00:00
|
|
|
#include <compat/linux/linux_signal.h>
|
2019-05-21 08:23:24 +00:00
|
|
|
#include <compat/linux/linux_util.h>
|
2017-02-16 13:32:15 +00:00
|
|
|
|
|
|
|
#define LINUX_PTRACE_TRACEME 0
|
|
|
|
#define LINUX_PTRACE_PEEKTEXT 1
|
|
|
|
#define LINUX_PTRACE_PEEKDATA 2
|
|
|
|
#define LINUX_PTRACE_PEEKUSER 3
|
|
|
|
#define LINUX_PTRACE_POKETEXT 4
|
|
|
|
#define LINUX_PTRACE_POKEDATA 5
|
|
|
|
#define LINUX_PTRACE_POKEUSER 6
|
|
|
|
#define LINUX_PTRACE_CONT 7
|
|
|
|
#define LINUX_PTRACE_KILL 8
|
|
|
|
#define LINUX_PTRACE_SINGLESTEP 9
|
|
|
|
#define LINUX_PTRACE_GETREGS 12
|
|
|
|
#define LINUX_PTRACE_SETREGS 13
|
|
|
|
#define LINUX_PTRACE_GETFPREGS 14
|
|
|
|
#define LINUX_PTRACE_SETFPREGS 15
|
|
|
|
#define LINUX_PTRACE_ATTACH 16
|
|
|
|
#define LINUX_PTRACE_DETACH 17
|
|
|
|
#define LINUX_PTRACE_SYSCALL 24
|
|
|
|
#define LINUX_PTRACE_SETOPTIONS 0x4200
|
2021-10-23 18:53:12 +00:00
|
|
|
#define LINUX_PTRACE_GETEVENTMSG 0x4201
|
2019-07-04 19:44:13 +00:00
|
|
|
#define LINUX_PTRACE_GETSIGINFO 0x4202
|
2017-02-16 13:32:15 +00:00
|
|
|
#define LINUX_PTRACE_GETREGSET 0x4204
|
|
|
|
#define LINUX_PTRACE_SEIZE 0x4206
|
2020-10-18 15:56:47 +00:00
|
|
|
#define LINUX_PTRACE_GET_SYSCALL_INFO 0x420e
|
2017-02-16 13:32:15 +00:00
|
|
|
|
2021-10-23 18:13:14 +00:00
|
|
|
#define LINUX_PTRACE_EVENT_EXEC 4
|
2019-07-04 19:46:58 +00:00
|
|
|
#define LINUX_PTRACE_EVENT_EXIT 6
|
|
|
|
|
2017-02-16 13:32:15 +00:00
|
|
|
#define LINUX_PTRACE_O_TRACESYSGOOD 1
|
|
|
|
#define LINUX_PTRACE_O_TRACEFORK 2
|
|
|
|
#define LINUX_PTRACE_O_TRACEVFORK 4
|
|
|
|
#define LINUX_PTRACE_O_TRACECLONE 8
|
|
|
|
#define LINUX_PTRACE_O_TRACEEXEC 16
|
|
|
|
#define LINUX_PTRACE_O_TRACEVFORKDONE 32
|
|
|
|
#define LINUX_PTRACE_O_TRACEEXIT 64
|
|
|
|
#define LINUX_PTRACE_O_TRACESECCOMP 128
|
2018-02-05 17:29:12 +00:00
|
|
|
#define LINUX_PTRACE_O_EXITKILL 1048576
|
2017-02-16 13:32:15 +00:00
|
|
|
#define LINUX_PTRACE_O_SUSPEND_SECCOMP 2097152
|
|
|
|
|
2021-10-17 11:52:39 +00:00
|
|
|
#define LINUX_NT_PRSTATUS 0x1
|
2021-10-22 18:58:52 +00:00
|
|
|
#define LINUX_NT_PRFPREG 0x2
|
2021-10-17 11:52:39 +00:00
|
|
|
#define LINUX_NT_X86_XSTATE 0x202
|
2017-02-16 13:32:15 +00:00
|
|
|
|
|
|
|
#define LINUX_PTRACE_O_MASK (LINUX_PTRACE_O_TRACESYSGOOD | \
|
|
|
|
LINUX_PTRACE_O_TRACEFORK | LINUX_PTRACE_O_TRACEVFORK | \
|
|
|
|
LINUX_PTRACE_O_TRACECLONE | LINUX_PTRACE_O_TRACEEXEC | \
|
|
|
|
LINUX_PTRACE_O_TRACEVFORKDONE | LINUX_PTRACE_O_TRACEEXIT | \
|
|
|
|
LINUX_PTRACE_O_TRACESECCOMP | LINUX_PTRACE_O_EXITKILL | \
|
|
|
|
LINUX_PTRACE_O_SUSPEND_SECCOMP)
|
|
|
|
|
2021-09-12 11:31:10 +00:00
|
|
|
#define LINUX_PTRACE_SYSCALL_INFO_NONE 0
|
|
|
|
#define LINUX_PTRACE_SYSCALL_INFO_ENTRY 1
|
|
|
|
#define LINUX_PTRACE_SYSCALL_INFO_EXIT 2
|
|
|
|
|
2021-10-17 11:20:16 +00:00
|
|
|
#define LINUX_PTRACE_PEEKUSER_ORIG_RAX 120
|
|
|
|
#define LINUX_PTRACE_PEEKUSER_RIP 128
|
|
|
|
#define LINUX_PTRACE_PEEKUSER_CS 136
|
|
|
|
#define LINUX_PTRACE_PEEKUSER_DS 184
|
|
|
|
|
2017-02-16 13:32:15 +00:00
|
|
|
static int
|
|
|
|
map_signum(int lsig, int *bsigp)
|
|
|
|
{
|
|
|
|
int bsig;
|
|
|
|
|
|
|
|
if (lsig == 0) {
|
|
|
|
*bsigp = 0;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (lsig < 0 || lsig > LINUX_SIGRTMAX)
|
|
|
|
return (EINVAL);
|
|
|
|
|
|
|
|
bsig = linux_to_bsd_signal(lsig);
|
|
|
|
if (bsig == SIGSTOP)
|
|
|
|
bsig = 0;
|
|
|
|
|
|
|
|
*bsigp = bsig;
|
|
|
|
return (0);
|
|
|
|
}
|
|
|
|
|
2019-05-19 12:58:44 +00:00
|
|
|
int
|
|
|
|
linux_ptrace_status(struct thread *td, pid_t pid, int status)
|
|
|
|
{
|
|
|
|
struct ptrace_lwpinfo lwpinfo;
|
|
|
|
struct linux_pemuldata *pem;
|
|
|
|
register_t saved_retval;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
saved_retval = td->td_retval[0];
|
|
|
|
error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
|
|
|
|
td->td_retval[0] = saved_retval;
|
|
|
|
if (error != 0) {
|
2019-05-21 08:23:24 +00:00
|
|
|
linux_msg(td, "PT_LWPINFO failed with error %d", error);
|
2019-05-19 12:58:44 +00:00
|
|
|
return (status);
|
|
|
|
}
|
|
|
|
|
|
|
|
pem = pem_find(td->td_proc);
|
|
|
|
KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
|
|
|
|
|
|
|
|
LINUX_PEM_SLOCK(pem);
|
|
|
|
if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
|
|
|
|
lwpinfo.pl_flags & PL_FLAG_SCE)
|
|
|
|
status |= (LINUX_SIGTRAP | 0x80) << 8;
|
|
|
|
if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACESYSGOOD) &&
|
2021-10-23 18:13:14 +00:00
|
|
|
lwpinfo.pl_flags & PL_FLAG_SCX) {
|
|
|
|
if (lwpinfo.pl_flags & PL_FLAG_EXEC)
|
|
|
|
status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXEC << 8) << 8;
|
|
|
|
else
|
|
|
|
status |= (LINUX_SIGTRAP | 0x80) << 8;
|
|
|
|
}
|
2019-07-04 19:46:58 +00:00
|
|
|
if ((pem->ptrace_flags & LINUX_PTRACE_O_TRACEEXIT) &&
|
|
|
|
lwpinfo.pl_flags & PL_FLAG_EXITED)
|
|
|
|
status |= (LINUX_SIGTRAP | LINUX_PTRACE_EVENT_EXIT << 8) << 8;
|
2019-05-19 12:58:44 +00:00
|
|
|
LINUX_PEM_SUNLOCK(pem);
|
|
|
|
|
|
|
|
return (status);
|
|
|
|
}
|
|
|
|
|
2017-02-16 13:32:15 +00:00
|
|
|
static int
|
|
|
|
linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
|
|
|
|
{
|
|
|
|
int error;
|
|
|
|
|
|
|
|
error = kern_ptrace(td, PT_READ_I, pid, addr, 0);
|
|
|
|
if (error == 0)
|
|
|
|
error = copyout(td->td_retval, data, sizeof(l_int));
|
2021-04-24 10:37:06 +00:00
|
|
|
else if (error == ENOMEM)
|
|
|
|
error = EIO;
|
2017-02-16 13:32:15 +00:00
|
|
|
td->td_retval[0] = error;
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2019-09-04 18:00:03 +00:00
|
|
|
static int
|
|
|
|
linux_ptrace_peekuser(struct thread *td, pid_t pid, void *addr, void *data)
|
|
|
|
{
|
2021-10-17 11:20:16 +00:00
|
|
|
struct reg b_reg;
|
|
|
|
uint64_t val;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
|
|
|
switch ((uintptr_t)addr) {
|
2021-11-03 08:54:30 +00:00
|
|
|
#ifdef __amd64__
|
2021-10-17 11:20:16 +00:00
|
|
|
case LINUX_PTRACE_PEEKUSER_ORIG_RAX:
|
|
|
|
val = b_reg.r_rax;
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_PEEKUSER_RIP:
|
|
|
|
val = b_reg.r_rip;
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_PEEKUSER_CS:
|
|
|
|
val = b_reg.r_cs;
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_PEEKUSER_DS:
|
|
|
|
val = b_reg.r_ds;
|
|
|
|
break;
|
2021-11-03 08:54:30 +00:00
|
|
|
#endif /* __amd64__ */
|
2021-10-17 11:20:16 +00:00
|
|
|
default:
|
|
|
|
linux_msg(td, "PTRACE_PEEKUSER offset %ld not implemented; "
|
|
|
|
"returning EINVAL", (uintptr_t)addr);
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
|
|
|
error = copyout(&val, data, sizeof(val));
|
|
|
|
td->td_retval[0] = error;
|
2019-09-04 18:00:03 +00:00
|
|
|
|
2021-10-17 11:20:16 +00:00
|
|
|
return (error);
|
2019-09-04 18:00:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_ptrace_pokeuser(struct thread *td, pid_t pid, void *addr, void *data)
|
|
|
|
{
|
|
|
|
|
|
|
|
linux_msg(td, "PTRACE_POKEUSER not implemented; returning EINVAL");
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
2017-02-16 13:32:15 +00:00
|
|
|
static int
|
|
|
|
linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
|
|
|
|
{
|
2019-05-19 12:58:44 +00:00
|
|
|
struct linux_pemuldata *pem;
|
2017-02-16 13:32:15 +00:00
|
|
|
int mask;
|
|
|
|
|
|
|
|
mask = 0;
|
|
|
|
|
|
|
|
if (data & ~LINUX_PTRACE_O_MASK) {
|
2019-05-21 08:23:24 +00:00
|
|
|
linux_msg(td, "unknown ptrace option %lx set; "
|
|
|
|
"returning EINVAL",
|
|
|
|
data & ~LINUX_PTRACE_O_MASK);
|
2017-02-16 13:32:15 +00:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
2019-05-19 12:58:44 +00:00
|
|
|
pem = pem_find(td->td_proc);
|
|
|
|
KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
|
|
|
|
|
2017-02-16 13:32:15 +00:00
|
|
|
/*
|
|
|
|
* PTRACE_O_EXITKILL is ignored, we do that by default.
|
|
|
|
*/
|
|
|
|
|
2019-05-19 12:58:44 +00:00
|
|
|
LINUX_PEM_XLOCK(pem);
|
2017-02-16 13:32:15 +00:00
|
|
|
if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
|
2019-05-19 12:58:44 +00:00
|
|
|
pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
|
|
|
|
} else {
|
|
|
|
pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
|
2017-02-16 13:32:15 +00:00
|
|
|
}
|
2019-05-19 12:58:44 +00:00
|
|
|
LINUX_PEM_XUNLOCK(pem);
|
2017-02-16 13:32:15 +00:00
|
|
|
|
|
|
|
if (data & LINUX_PTRACE_O_TRACEFORK)
|
|
|
|
mask |= PTRACE_FORK;
|
|
|
|
|
2018-02-05 17:29:12 +00:00
|
|
|
if (data & LINUX_PTRACE_O_TRACEVFORK)
|
2017-02-16 13:32:15 +00:00
|
|
|
mask |= PTRACE_VFORK;
|
|
|
|
|
|
|
|
if (data & LINUX_PTRACE_O_TRACECLONE)
|
|
|
|
mask |= PTRACE_VFORK;
|
|
|
|
|
|
|
|
if (data & LINUX_PTRACE_O_TRACEEXEC)
|
|
|
|
mask |= PTRACE_EXEC;
|
|
|
|
|
|
|
|
if (data & LINUX_PTRACE_O_TRACEVFORKDONE)
|
|
|
|
mask |= PTRACE_VFORK; /* XXX: Close enough? */
|
|
|
|
|
|
|
|
if (data & LINUX_PTRACE_O_TRACEEXIT) {
|
2019-07-04 19:46:58 +00:00
|
|
|
pem->ptrace_flags |= LINUX_PTRACE_O_TRACEEXIT;
|
|
|
|
} else {
|
|
|
|
pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACEEXIT;
|
2017-02-16 13:32:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (kern_ptrace(td, PT_SET_EVENT_MASK, pid, &mask, sizeof(mask)));
|
|
|
|
}
|
|
|
|
|
2021-10-23 18:53:12 +00:00
|
|
|
static int
|
|
|
|
linux_ptrace_geteventmsg(struct thread *td, pid_t pid, l_ulong data)
|
|
|
|
{
|
|
|
|
|
|
|
|
linux_msg(td, "PTRACE_GETEVENTMSG not implemented; returning EINVAL");
|
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
2019-07-04 19:44:13 +00:00
|
|
|
static int
|
|
|
|
linux_ptrace_getsiginfo(struct thread *td, pid_t pid, l_ulong data)
|
|
|
|
{
|
|
|
|
struct ptrace_lwpinfo lwpinfo;
|
|
|
|
l_siginfo_t l_siginfo;
|
|
|
|
int error, sig;
|
|
|
|
|
|
|
|
error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
|
|
|
|
if (error != 0) {
|
|
|
|
linux_msg(td, "PT_LWPINFO failed with error %d", error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((lwpinfo.pl_flags & PL_FLAG_SI) == 0) {
|
|
|
|
error = EINVAL;
|
|
|
|
linux_msg(td, "no PL_FLAG_SI, returning %d", error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
sig = bsd_to_linux_signal(lwpinfo.pl_siginfo.si_signo);
|
2021-06-08 09:18:29 +00:00
|
|
|
memset(&l_siginfo, 0, sizeof(l_siginfo));
|
2019-07-04 19:44:13 +00:00
|
|
|
siginfo_to_lsiginfo(&lwpinfo.pl_siginfo, &l_siginfo, sig);
|
|
|
|
error = copyout(&l_siginfo, (void *)data, sizeof(l_siginfo));
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2017-02-16 13:32:15 +00:00
|
|
|
static int
|
|
|
|
linux_ptrace_getregs(struct thread *td, pid_t pid, void *data)
|
|
|
|
{
|
|
|
|
struct reg b_reg;
|
2021-10-29 15:18:13 +00:00
|
|
|
struct linux_pt_regset l_regset;
|
2017-02-16 13:32:15 +00:00
|
|
|
int error;
|
|
|
|
|
|
|
|
error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
2021-11-03 08:54:30 +00:00
|
|
|
bsd_to_linux_regset(&b_reg, &l_regset);
|
2021-11-09 11:54:06 +00:00
|
|
|
error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
|
|
|
|
if (error != 0)
|
2017-02-16 13:32:15 +00:00
|
|
|
return (error);
|
|
|
|
|
2021-10-29 15:18:13 +00:00
|
|
|
error = copyout(&l_regset, (void *)data, sizeof(l_regset));
|
2017-02-16 13:32:15 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_ptrace_setregs(struct thread *td, pid_t pid, void *data)
|
|
|
|
{
|
|
|
|
struct reg b_reg;
|
2021-10-30 09:13:32 +00:00
|
|
|
struct linux_pt_regset l_regset;
|
2017-02-16 13:32:15 +00:00
|
|
|
int error;
|
|
|
|
|
2021-10-30 09:13:32 +00:00
|
|
|
error = copyin(data, &l_regset, sizeof(l_regset));
|
2017-02-16 13:32:15 +00:00
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
2021-10-30 09:13:32 +00:00
|
|
|
linux_to_bsd_regset(&b_reg, &l_regset);
|
2017-02-16 13:32:15 +00:00
|
|
|
error = kern_ptrace(td, PT_SETREGS, pid, &b_reg, 0);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2019-05-07 19:06:41 +00:00
|
|
|
static int
|
|
|
|
linux_ptrace_getregset_prstatus(struct thread *td, pid_t pid, l_ulong data)
|
|
|
|
{
|
|
|
|
struct reg b_reg;
|
|
|
|
struct linux_pt_regset l_regset;
|
|
|
|
struct iovec iov;
|
|
|
|
size_t len;
|
|
|
|
int error;
|
|
|
|
|
|
|
|
error = copyin((const void *)data, &iov, sizeof(iov));
|
|
|
|
if (error != 0) {
|
2019-05-21 08:23:24 +00:00
|
|
|
linux_msg(td, "copyin error %d", error);
|
2019-05-07 19:06:41 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
2021-11-03 08:54:30 +00:00
|
|
|
bsd_to_linux_regset(&b_reg, &l_regset);
|
2021-11-09 11:54:06 +00:00
|
|
|
error = linux_ptrace_getregs_machdep(td, pid, &l_regset);
|
|
|
|
if (error != 0)
|
2019-05-07 19:06:41 +00:00
|
|
|
return (error);
|
|
|
|
|
|
|
|
len = MIN(iov.iov_len, sizeof(l_regset));
|
|
|
|
error = copyout(&l_regset, (void *)iov.iov_base, len);
|
|
|
|
if (error != 0) {
|
2019-05-21 08:23:24 +00:00
|
|
|
linux_msg(td, "copyout error %d", error);
|
2019-05-07 19:06:41 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2021-10-29 14:28:56 +00:00
|
|
|
iov.iov_len = len;
|
2019-05-07 19:06:41 +00:00
|
|
|
error = copyout(&iov, (void *)data, sizeof(iov));
|
|
|
|
if (error != 0) {
|
2019-05-21 08:23:24 +00:00
|
|
|
linux_msg(td, "iov copyout error %d", error);
|
2019-05-07 19:06:41 +00:00
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
2017-02-16 13:32:15 +00:00
|
|
|
static int
|
|
|
|
linux_ptrace_getregset(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
|
|
|
|
{
|
|
|
|
|
|
|
|
switch (addr) {
|
|
|
|
case LINUX_NT_PRSTATUS:
|
2019-05-07 19:06:41 +00:00
|
|
|
return (linux_ptrace_getregset_prstatus(td, pid, data));
|
2021-10-22 18:58:52 +00:00
|
|
|
case LINUX_NT_PRFPREG:
|
|
|
|
linux_msg(td, "PTRAGE_GETREGSET NT_PRFPREG not implemented; "
|
|
|
|
"returning EINVAL");
|
|
|
|
return (EINVAL);
|
2021-10-17 11:52:39 +00:00
|
|
|
case LINUX_NT_X86_XSTATE:
|
|
|
|
linux_msg(td, "PTRAGE_GETREGSET NT_X86_XSTATE not implemented; "
|
|
|
|
"returning EINVAL");
|
|
|
|
return (EINVAL);
|
2017-02-16 13:32:15 +00:00
|
|
|
default:
|
2021-10-17 11:52:39 +00:00
|
|
|
linux_msg(td, "PTRACE_GETREGSET request %#lx not implemented; "
|
2019-05-21 08:23:24 +00:00
|
|
|
"returning EINVAL", addr);
|
2017-02-16 13:32:15 +00:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_ptrace_seize(struct thread *td, pid_t pid, l_ulong addr, l_ulong data)
|
|
|
|
{
|
|
|
|
|
2019-05-21 08:23:24 +00:00
|
|
|
linux_msg(td, "PTRACE_SEIZE not implemented; returning EINVAL");
|
2017-02-16 13:32:15 +00:00
|
|
|
return (EINVAL);
|
|
|
|
}
|
|
|
|
|
2020-10-18 15:56:47 +00:00
|
|
|
static int
|
2021-09-12 11:31:10 +00:00
|
|
|
linux_ptrace_get_syscall_info(struct thread *td, pid_t pid,
|
2021-10-17 10:49:42 +00:00
|
|
|
l_ulong len, l_ulong data)
|
2020-10-18 15:56:47 +00:00
|
|
|
{
|
2021-09-12 11:31:10 +00:00
|
|
|
struct ptrace_lwpinfo lwpinfo;
|
|
|
|
struct ptrace_sc_ret sr;
|
|
|
|
struct reg b_reg;
|
|
|
|
struct syscall_info si;
|
|
|
|
int error;
|
2020-10-18 15:56:47 +00:00
|
|
|
|
2021-09-12 11:31:10 +00:00
|
|
|
error = kern_ptrace(td, PT_LWPINFO, pid, &lwpinfo, sizeof(lwpinfo));
|
|
|
|
if (error != 0) {
|
|
|
|
linux_msg(td, "PT_LWPINFO failed with error %d", error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&si, 0, sizeof(si));
|
|
|
|
|
|
|
|
if (lwpinfo.pl_flags & PL_FLAG_SCE) {
|
|
|
|
si.op = LINUX_PTRACE_SYSCALL_INFO_ENTRY;
|
|
|
|
si.entry.nr = lwpinfo.pl_syscall_code;
|
|
|
|
/*
|
2021-09-15 13:24:09 +00:00
|
|
|
* The use of PT_GET_SC_ARGS there is special,
|
|
|
|
* implementation of PT_GET_SC_ARGS for Linux-ABI
|
|
|
|
* callers emulates Linux bug which strace(1) depends
|
|
|
|
* on: at initialization it tests whether ptrace works
|
|
|
|
* by calling close(2), or some other single-argument
|
|
|
|
* syscall, _with six arguments_, and then verifies
|
|
|
|
* whether it can fetch them all using this API;
|
|
|
|
* otherwise it bails out.
|
2021-09-12 11:31:10 +00:00
|
|
|
*/
|
2021-09-15 13:24:09 +00:00
|
|
|
error = kern_ptrace(td, PT_GET_SC_ARGS, pid,
|
2021-09-12 11:31:10 +00:00
|
|
|
&si.entry.args, sizeof(si.entry.args));
|
|
|
|
if (error != 0) {
|
2021-09-15 13:24:09 +00:00
|
|
|
linux_msg(td, "PT_GET_SC_ARGS failed with error %d",
|
2021-09-12 11:31:10 +00:00
|
|
|
error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
} else if (lwpinfo.pl_flags & PL_FLAG_SCX) {
|
|
|
|
si.op = LINUX_PTRACE_SYSCALL_INFO_EXIT;
|
|
|
|
error = kern_ptrace(td, PT_GET_SC_RET, pid, &sr, sizeof(sr));
|
|
|
|
|
|
|
|
if (error != 0) {
|
|
|
|
linux_msg(td, "PT_GET_SC_RET failed with error %d",
|
|
|
|
error);
|
|
|
|
return (error);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sr.sr_error == 0) {
|
|
|
|
si.exit.rval = sr.sr_retval[0];
|
|
|
|
si.exit.is_error = 0;
|
2021-10-23 17:56:29 +00:00
|
|
|
} else if (sr.sr_error == EJUSTRETURN) {
|
|
|
|
/*
|
|
|
|
* EJUSTRETURN means the actual value to return
|
|
|
|
* has already been put into td_frame; instead
|
|
|
|
* of extracting it and trying to determine whether
|
|
|
|
* it's an error or not just bail out and let
|
|
|
|
* the ptracing process fall back to another method.
|
|
|
|
*/
|
|
|
|
si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
|
2021-10-29 13:21:21 +00:00
|
|
|
} else if (sr.sr_error == ERESTART) {
|
|
|
|
si.exit.rval = -LINUX_ERESTARTSYS;
|
|
|
|
si.exit.is_error = 1;
|
2021-09-12 11:31:10 +00:00
|
|
|
} else {
|
|
|
|
si.exit.rval = bsd_to_linux_errno(sr.sr_error);
|
|
|
|
si.exit.is_error = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
si.op = LINUX_PTRACE_SYSCALL_INFO_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
error = kern_ptrace(td, PT_GETREGS, pid, &b_reg, 0);
|
|
|
|
if (error != 0)
|
|
|
|
return (error);
|
|
|
|
|
2021-11-09 11:54:06 +00:00
|
|
|
linux_ptrace_get_syscall_info_machdep(&b_reg, &si);
|
2021-09-12 11:31:10 +00:00
|
|
|
|
2021-10-17 10:49:42 +00:00
|
|
|
len = MIN(len, sizeof(si));
|
|
|
|
error = copyout(&si, (void *)data, len);
|
2021-09-12 11:31:10 +00:00
|
|
|
if (error == 0)
|
|
|
|
td->td_retval[0] = sizeof(si);
|
|
|
|
|
|
|
|
return (error);
|
2020-10-18 15:56:47 +00:00
|
|
|
}
|
|
|
|
|
2017-02-16 13:32:15 +00:00
|
|
|
int
|
|
|
|
linux_ptrace(struct thread *td, struct linux_ptrace_args *uap)
|
|
|
|
{
|
|
|
|
void *addr;
|
|
|
|
pid_t pid;
|
|
|
|
int error, sig;
|
|
|
|
|
2022-01-21 21:52:35 +00:00
|
|
|
if (!allow_ptrace)
|
|
|
|
return (ENOSYS);
|
|
|
|
|
2017-02-16 13:32:15 +00:00
|
|
|
pid = (pid_t)uap->pid;
|
|
|
|
addr = (void *)uap->addr;
|
|
|
|
|
|
|
|
switch (uap->req) {
|
|
|
|
case LINUX_PTRACE_TRACEME:
|
|
|
|
error = kern_ptrace(td, PT_TRACE_ME, 0, 0, 0);
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_PEEKTEXT:
|
|
|
|
case LINUX_PTRACE_PEEKDATA:
|
|
|
|
error = linux_ptrace_peek(td, pid, addr, (void *)uap->data);
|
|
|
|
if (error != 0)
|
2021-01-15 17:11:41 +00:00
|
|
|
goto out;
|
2017-02-16 13:32:15 +00:00
|
|
|
/*
|
|
|
|
* Linux expects this syscall to read 64 bits, not 32.
|
|
|
|
*/
|
|
|
|
error = linux_ptrace_peek(td, pid,
|
|
|
|
(void *)(uap->addr + 4), (void *)(uap->data + 4));
|
|
|
|
break;
|
2019-09-04 18:00:03 +00:00
|
|
|
case LINUX_PTRACE_PEEKUSER:
|
|
|
|
error = linux_ptrace_peekuser(td, pid, addr, (void *)uap->data);
|
|
|
|
break;
|
2017-02-16 13:32:15 +00:00
|
|
|
case LINUX_PTRACE_POKETEXT:
|
|
|
|
case LINUX_PTRACE_POKEDATA:
|
|
|
|
error = kern_ptrace(td, PT_WRITE_D, pid, addr, uap->data);
|
2021-01-15 16:57:24 +00:00
|
|
|
if (error != 0)
|
2021-01-15 17:11:41 +00:00
|
|
|
goto out;
|
2021-01-15 16:57:24 +00:00
|
|
|
/*
|
|
|
|
* Linux expects this syscall to write 64 bits, not 32.
|
|
|
|
*/
|
|
|
|
error = kern_ptrace(td, PT_WRITE_D, pid,
|
|
|
|
(void *)(uap->addr + 4), uap->data >> 32);
|
2017-02-16 13:32:15 +00:00
|
|
|
break;
|
2019-09-04 18:00:03 +00:00
|
|
|
case LINUX_PTRACE_POKEUSER:
|
|
|
|
error = linux_ptrace_pokeuser(td, pid, addr, (void *)uap->data);
|
|
|
|
break;
|
2017-02-16 13:32:15 +00:00
|
|
|
case LINUX_PTRACE_CONT:
|
|
|
|
error = map_signum(uap->data, &sig);
|
|
|
|
if (error != 0)
|
|
|
|
break;
|
|
|
|
error = kern_ptrace(td, PT_CONTINUE, pid, (void *)1, sig);
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_KILL:
|
|
|
|
error = kern_ptrace(td, PT_KILL, pid, addr, uap->data);
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_SINGLESTEP:
|
|
|
|
error = map_signum(uap->data, &sig);
|
|
|
|
if (error != 0)
|
|
|
|
break;
|
|
|
|
error = kern_ptrace(td, PT_STEP, pid, (void *)1, sig);
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_GETREGS:
|
|
|
|
error = linux_ptrace_getregs(td, pid, (void *)uap->data);
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_SETREGS:
|
|
|
|
error = linux_ptrace_setregs(td, pid, (void *)uap->data);
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_ATTACH:
|
|
|
|
error = kern_ptrace(td, PT_ATTACH, pid, addr, uap->data);
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_DETACH:
|
|
|
|
error = map_signum(uap->data, &sig);
|
|
|
|
if (error != 0)
|
|
|
|
break;
|
|
|
|
error = kern_ptrace(td, PT_DETACH, pid, (void *)1, sig);
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_SYSCALL:
|
|
|
|
error = map_signum(uap->data, &sig);
|
|
|
|
if (error != 0)
|
|
|
|
break;
|
|
|
|
error = kern_ptrace(td, PT_SYSCALL, pid, (void *)1, sig);
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_SETOPTIONS:
|
|
|
|
error = linux_ptrace_setoptions(td, pid, uap->data);
|
|
|
|
break;
|
2021-10-23 18:53:12 +00:00
|
|
|
case LINUX_PTRACE_GETEVENTMSG:
|
|
|
|
error = linux_ptrace_geteventmsg(td, pid, uap->data);
|
|
|
|
break;
|
2019-07-04 19:44:13 +00:00
|
|
|
case LINUX_PTRACE_GETSIGINFO:
|
|
|
|
error = linux_ptrace_getsiginfo(td, pid, uap->data);
|
|
|
|
break;
|
2017-02-16 13:32:15 +00:00
|
|
|
case LINUX_PTRACE_GETREGSET:
|
|
|
|
error = linux_ptrace_getregset(td, pid, uap->addr, uap->data);
|
|
|
|
break;
|
|
|
|
case LINUX_PTRACE_SEIZE:
|
|
|
|
error = linux_ptrace_seize(td, pid, uap->addr, uap->data);
|
|
|
|
break;
|
2020-10-18 15:56:47 +00:00
|
|
|
case LINUX_PTRACE_GET_SYSCALL_INFO:
|
|
|
|
error = linux_ptrace_get_syscall_info(td, pid, uap->addr, uap->data);
|
|
|
|
break;
|
2017-02-16 13:32:15 +00:00
|
|
|
default:
|
2019-05-21 08:23:24 +00:00
|
|
|
linux_msg(td, "ptrace(%ld, ...) not implemented; "
|
|
|
|
"returning EINVAL", uap->req);
|
2017-02-16 13:32:15 +00:00
|
|
|
error = EINVAL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-01-15 17:11:41 +00:00
|
|
|
out:
|
|
|
|
if (error == EBUSY)
|
|
|
|
error = ESRCH;
|
|
|
|
|
2017-02-16 13:32:15 +00:00
|
|
|
return (error);
|
|
|
|
}
|