Implement PTRACE_O_TRACESYSGOOD. This makes Linux strace(1) work.

Reviewed by:	dchagin
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
Differential Revision:	https://reviews.freebsd.org/D20200
This commit is contained in:
trasz 2019-05-19 12:58:44 +00:00
parent 7217903de2
commit 23bce35991
4 changed files with 92 additions and 21 deletions

View File

@ -34,8 +34,10 @@
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/lock.h>
#include <sys/proc.h>
#include <sys/ptrace.h>
#include <sys/sx.h>
#include <sys/syscallsubr.h>
#include <machine/pcb.h>
@ -43,6 +45,8 @@ __FBSDID("$FreeBSD$");
#include <amd64/linux/linux.h>
#include <amd64/linux/linux_proto.h>
#include <compat/linux/linux_emul.h>
#include <compat/linux/linux_misc.h>
#include <compat/linux/linux_signal.h>
#define LINUX_PTRACE_TRACEME 0
@ -107,6 +111,37 @@ map_signum(int lsig, int *bsigp)
return (0);
}
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) {
printf("%s: PT_LWPINFO failed with error %d\n", __func__, error);
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) &&
lwpinfo.pl_flags & PL_FLAG_SCX)
status |= (LINUX_SIGTRAP | 0x80) << 8;
LINUX_PEM_SUNLOCK(pem);
return (status);
}
struct linux_pt_reg {
l_ulong r15;
l_ulong r14;
@ -279,6 +314,7 @@ linux_ptrace_peek(struct thread *td, pid_t pid, void *addr, void *data)
static int
linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
{
struct linux_pemuldata *pem;
int mask;
mask = 0;
@ -290,15 +326,20 @@ linux_ptrace_setoptions(struct thread *td, pid_t pid, l_ulong data)
return (EINVAL);
}
pem = pem_find(td->td_proc);
KASSERT(pem != NULL, ("%s: proc emuldata not found.\n", __func__));
/*
* PTRACE_O_EXITKILL is ignored, we do that by default.
*/
LINUX_PEM_XLOCK(pem);
if (data & LINUX_PTRACE_O_TRACESYSGOOD) {
printf("%s: PTRACE_O_TRACESYSGOOD not implemented; "
"returning EINVAL\n", __func__);
return (EINVAL);
pem->ptrace_flags |= LINUX_PTRACE_O_TRACESYSGOOD;
} else {
pem->ptrace_flags &= ~LINUX_PTRACE_O_TRACESYSGOOD;
}
LINUX_PEM_XUNLOCK(pem);
if (data & LINUX_PTRACE_O_TRACEFORK)
mask |= PTRACE_FORK;

View File

@ -32,6 +32,8 @@
#ifndef _LINUX_EMUL_H_
#define _LINUX_EMUL_H_
struct image_params;
/*
* modeled after similar structure in NetBSD
* this will be extended as we need more functionality
@ -68,6 +70,7 @@ struct linux_pemuldata {
struct sx pem_sx; /* lock for this struct */
void *epoll; /* epoll data */
uint32_t persona; /* process execution domain */
uint32_t ptrace_flags; /* used by ptrace(2) */
};
#define LINUX_PEM_XLOCK(p) sx_xlock(&(p)->pem_sx)

View File

@ -886,27 +886,53 @@ linux_futimesat(struct thread *td, struct linux_futimesat_args *args)
}
#endif
int
linux_common_wait(struct thread *td, int pid, int *status,
int options, struct rusage *ru)
static int
linux_common_wait(struct thread *td, int pid, int *statusp,
int options, struct __wrusage *wrup)
{
int error, tmpstat;
siginfo_t siginfo;
idtype_t idtype;
id_t id;
int error, status, tmpstat;
error = kern_wait(td, pid, &tmpstat, options, ru);
if (pid == WAIT_ANY) {
idtype = P_ALL;
id = 0;
} else if (pid < 0) {
idtype = P_PGID;
id = (id_t)-pid;
} else {
idtype = P_PID;
id = (id_t)pid;
}
/*
* For backward compatibility we implicitly add flags WEXITED
* and WTRAPPED here.
*/
options |= WEXITED | WTRAPPED;
error = kern_wait6(td, idtype, id, &status, options, wrup, &siginfo);
if (error)
return (error);
if (status) {
tmpstat &= 0xffff;
if (WIFSIGNALED(tmpstat))
if (statusp) {
tmpstat = status & 0xffff;
if (WIFSIGNALED(tmpstat)) {
tmpstat = (tmpstat & 0xffffff80) |
bsd_to_linux_signal(WTERMSIG(tmpstat));
else if (WIFSTOPPED(tmpstat))
} else if (WIFSTOPPED(tmpstat)) {
tmpstat = (tmpstat & 0xffff00ff) |
(bsd_to_linux_signal(WSTOPSIG(tmpstat)) << 8);
else if (WIFCONTINUED(tmpstat))
#if defined(__amd64__) && !defined(COMPAT_LINUX32)
if (WSTOPSIG(status) == SIGTRAP) {
tmpstat = linux_ptrace_status(td,
siginfo.si_pid, tmpstat);
}
#endif
} else if (WIFCONTINUED(tmpstat)) {
tmpstat = 0xffff;
error = copyout(&tmpstat, status, sizeof(int));
}
error = copyout(&tmpstat, statusp, sizeof(int));
}
return (error);
@ -931,7 +957,7 @@ int
linux_wait4(struct thread *td, struct linux_wait4_args *args)
{
int error, options;
struct rusage ru, *rup;
struct __wrusage wru, *wrup;
if (args->options & ~(LINUX_WUNTRACED | LINUX_WNOHANG |
LINUX_WCONTINUED | __WCLONE | __WNOTHREAD | __WALL))
@ -941,14 +967,14 @@ linux_wait4(struct thread *td, struct linux_wait4_args *args)
linux_to_bsd_waitopts(args->options, &options);
if (args->rusage != NULL)
rup = &ru;
wrup = &wru;
else
rup = NULL;
error = linux_common_wait(td, args->pid, args->status, options, rup);
wrup = NULL;
error = linux_common_wait(td, args->pid, args->status, options, wrup);
if (error != 0)
return (error);
if (args->rusage != NULL)
error = linux_copyout_rusage(&ru, args->rusage);
error = linux_copyout_rusage(&wru.wru_self, args->rusage);
return (error);
}

View File

@ -149,8 +149,9 @@ extern int stclohz;
#define LINUX_GRND_NONBLOCK 0x0001
#define LINUX_GRND_RANDOM 0x0002
int linux_common_wait(struct thread *td, int pid, int *status,
int options, struct rusage *ru);
#if defined(__amd64__) && !defined(COMPAT_LINUX32)
int linux_ptrace_status(struct thread *td, int pid, int status);
#endif
void linux_to_bsd_waitopts(int options, int *bsdopts);
int linux_set_upcall_kse(struct thread *td, register_t stack);
int linux_set_cloned_tls(struct thread *td, void *desc);