summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2005-09-14 20:55:59 +0000
committerkettenis <kettenis@openbsd.org>2005-09-14 20:55:59 +0000
commitf38bed7f869bd3503530c554b4860228ea4e8641 (patch)
tree78ea133c0d1af019f0fb9951cb0ade43e4df70e7
parentknf (diff)
downloadwireguard-openbsd-f38bed7f869bd3503530c554b4860228ea4e8641.tar.xz
wireguard-openbsd-f38bed7f869bd3503530c554b4860228ea4e8641.zip
ptrace(2) following fork(2)
ok miod@
-rw-r--r--lib/libc/sys/ptrace.265
-rw-r--r--sys/kern/kern_exit.c4
-rw-r--r--sys/kern/kern_fork.c49
-rw-r--r--sys/kern/sys_process.c35
-rw-r--r--sys/sys/proc.h6
-rw-r--r--sys/sys/ptrace.h18
6 files changed, 169 insertions, 8 deletions
diff --git a/lib/libc/sys/ptrace.2 b/lib/libc/sys/ptrace.2
index a5d9f0b2fad..70c53dd316a 100644
--- a/lib/libc/sys/ptrace.2
+++ b/lib/libc/sys/ptrace.2
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ptrace.2,v 1.19 2005/07/20 21:51:36 miod Exp $
+.\" $OpenBSD: ptrace.2,v 1.20 2005/09/14 20:55:59 kettenis Exp $
.\" $NetBSD: ptrace.2,v 1.3 1996/02/23 01:39:41 jtc Exp $
.\"
.\" This file is in the public domain.
@@ -232,6 +232,69 @@ will return
.Li -1
and set
.Va errno .
+.It Dv PT_SET_EVENT_MASK
+This request can be used to specify which events in the traced process
+should be reported to the tracing process.
+These events are specified in a
+.Dq Li "struct ptrace_event"
+defined as:
+.Bd -literal -offset indent
+typedef struct ptrace_event {
+ int pe_set_event;
+} ptrace_event_t;
+.Ed
+Where
+.Fa pe_set_event
+is the set of events to be reported.
+This set is formed by OR'ing together the following values:
+.Bl -tag -width 18n
+.It PTRACE_FORK
+Report
+.Xr fork 2 .
+.El
+.Pp
+A pointer to this structure is passed in
+.Fa addr .
+The
+.Fa data
+argument should be set to
+.Li sizeof(struct ptrace_event) .
+.It Dv PT_GET_EVENT_MASK
+This request can be used to determine which events in the traced
+process will be reported.
+The information is read into the
+.Dq Li struct ptrace_event
+pointed to by
+.Fa addr .
+The
+.Fa data
+argument should be set to
+.Li sizeof(struct ptrace_event) .
+.It Dv PT_GET_PROCESS_STATE
+This request reads the state information associated with the event
+that stopped the traced process.
+The information is reported in a
+.Dq Li "struct ptrace_state"
+defined as:
+.Bd -literal -offset indent
+typedef struct ptrace_state {
+ int pe_report_event;
+ pid_t pe_other_pid;
+} ptrace_state_t;
+.Ed
+Where
+.Fa pe_report_event
+is the event being reported.
+If the event being reported is
+.Dv PTRACE_FORK ,
+.Fa pe_other_pid
+will be set to the process ID of the other end of the fork.
+A pointer to this structure is passed in
+.Fa addr .
+The
+.Fa data
+argument should be set to
+.Li sizeof(struct ptrace_state) .
.El
.Pp
Additionally, machine-specific requests can exist.
diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c
index 8664f92be3e..ed642342fee 100644
--- a/sys/kern/kern_exit.c
+++ b/sys/kern/kern_exit.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_exit.c,v 1.54 2004/12/26 21:22:13 miod Exp $ */
+/* $OpenBSD: kern_exit.c,v 1.55 2005/09/14 20:55:59 kettenis Exp $ */
/* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */
/*
@@ -540,6 +540,8 @@ void
proc_zap(struct proc *p)
{
pool_put(&rusage_pool, p->p_ru);
+ if (p->p_ptstat)
+ free(p->p_ptstat, M_SUBPROC);
/*
* Finally finished with old proc entry.
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 5e0d1273538..45d51df536d 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_fork.c,v 1.76 2005/05/29 03:20:41 deraadt Exp $ */
+/* $OpenBSD: kern_fork.c,v 1.77 2005/09/14 20:55:59 kettenis Exp $ */
/* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */
/*
@@ -55,6 +55,7 @@
#include <dev/rndvar.h>
#include <sys/pool.h>
#include <sys/mman.h>
+#include <sys/ptrace.h>
#include <sys/syscallargs.h>
@@ -69,14 +70,31 @@ int randompid; /* when set to 1, pid's go random */
pid_t lastpid;
struct forkstat forkstat;
+void fork_return(void *);
int pidtaken(pid_t);
+void
+fork_return(void *arg)
+{
+ struct proc *p = (struct proc *)arg;
+
+ if (p->p_flag & P_TRACED)
+ psignal(p, SIGTRAP);
+
+ child_return(p);
+}
+
/*ARGSUSED*/
int
sys_fork(struct proc *p, void *v, register_t *retval)
{
- return (fork1(p, SIGCHLD, FORK_FORK, NULL, 0, NULL,
- NULL, retval, NULL));
+ int flags;
+
+ flags = FORK_FORK;
+ if (p->p_ptmask & PTRACE_FORK)
+ flags |= FORK_PTRACE;
+ return (fork1(p, SIGCHLD, flags, NULL, 0,
+ fork_return, NULL, retval, NULL));
}
/*ARGSUSED*/
@@ -220,6 +238,8 @@ fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize,
if (p1->p_flag & P_PROFIL)
startprofclock(p2);
p2->p_flag |= (p1->p_flag & (P_SUGID | P_SUGIDEXEC));
+ if (flags & FORK_PTRACE)
+ p2->p_flag |= (p1->p_flag & P_TRACED);
p2->p_cred = pool_get(&pcred_pool, PR_WAITOK);
bcopy(p1->p_cred, p2->p_cred, sizeof(*p2->p_cred));
p2->p_cred->p_refcnt = 1;
@@ -329,6 +349,23 @@ fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize,
lastpid = 1 + (randompid ? arc4random() : lastpid) % PID_MAX;
} while (pidtaken(lastpid));
p2->p_pid = lastpid;
+ if (p2->p_flag & P_TRACED) {
+ p2->p_oppid = p1->p_pid;
+ if (p2->p_pptr != p1->p_pptr)
+ proc_reparent(p2, p1->p_pptr);
+
+ /*
+ * Set ptrace status.
+ */
+ if (flags & FORK_FORK) {
+ p2->p_ptstat = malloc(sizeof(*p2->p_ptstat),
+ M_SUBPROC, M_WAITOK);
+ p1->p_ptstat->pe_report_event = PTRACE_FORK;
+ p2->p_ptstat->pe_report_event = PTRACE_FORK;
+ p1->p_ptstat->pe_other_pid = p2->p_pid;
+ p2->p_ptstat->pe_other_pid = p1->p_pid;
+ }
+ }
LIST_INSERT_HEAD(&allproc, p2, p_list);
LIST_INSERT_HEAD(PIDHASH(p2->p_pid), p2, p_hash);
@@ -386,6 +423,12 @@ fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize,
tsleep(p1, PWAIT, "ppwait", 0);
/*
+ * If we're tracing the child, alert the parent too.
+ */
+ if ((flags & FORK_PTRACE) && (p1->p_flag & P_TRACED))
+ psignal(p1, SIGTRAP);
+
+ /*
* Return child pid to parent process,
* marking us as parent via retval[1].
*/
diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c
index 98647d1226c..f6bd38083f7 100644
--- a/sys/kern/sys_process.c
+++ b/sys/kern/sys_process.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sys_process.c,v 1.31 2005/08/02 18:04:07 kettenis Exp $ */
+/* $OpenBSD: sys_process.c,v 1.32 2005/09/14 20:55:59 kettenis Exp $ */
/* $NetBSD: sys_process.c,v 1.55 1996/05/15 06:17:47 tls Exp $ */
/*-
@@ -88,6 +88,7 @@ sys_ptrace(p, v, retval)
struct uio uio;
struct iovec iov;
struct ptrace_io_desc piod;
+ struct ptrace_event pe;
struct reg *regs;
#if defined (PT_SETFPREGS) || defined (PT_GETFPREGS)
struct fpreg *fpregs;
@@ -179,6 +180,9 @@ sys_ptrace(p, v, retval)
#ifdef PT_STEP
case PT_STEP:
#endif
+ case PT_SET_EVENT_MASK:
+ case PT_GET_EVENT_MASK:
+ case PT_GET_PROCESS_STATE:
case PT_GETREGS:
case PT_SETREGS:
#ifdef PT_GETFPREGS
@@ -232,6 +236,10 @@ sys_ptrace(p, v, retval)
/* Just set the trace flag. */
SET(t->p_flag, P_TRACED);
t->p_oppid = t->p_pptr->p_pid;
+ if (t->p_ptstat == NULL)
+ t->p_ptstat = malloc(sizeof(*t->p_ptstat),
+ M_SUBPROC, M_WAITOK);
+ bzero(t->p_ptstat, sizeof(*t->p_ptstat));
return (0);
case PT_WRITE_I: /* XXX no separate I and D spaces */
@@ -366,6 +374,8 @@ sys_ptrace(p, v, retval)
CLR(t->p_flag, P_TRACED|P_WAITED);
sendsig:
+ bzero(t->p_ptstat, sizeof(*t->p_ptstat));
+
/* Finally, deliver the requested signal (or none). */
if (t->p_stat == SSTOP) {
t->p_xstat = SCARG(uap, data);
@@ -401,9 +411,32 @@ sys_ptrace(p, v, retval)
t->p_oppid = t->p_pptr->p_pid;
if (t->p_pptr != p)
proc_reparent(t, p);
+ if (t->p_ptstat == NULL)
+ t->p_ptstat = malloc(sizeof(*t->p_ptstat),
+ M_SUBPROC, M_WAITOK);
SCARG(uap, data) = SIGSTOP;
goto sendsig;
+ case PT_GET_EVENT_MASK:
+ if (SCARG(uap, data) != sizeof(pe))
+ return (EINVAL);
+ bzero(&pe, sizeof(pe));
+ pe.pe_set_event = t->p_ptmask;
+ return (copyout(&pe, SCARG(uap, addr), sizeof(pe)));
+ case PT_SET_EVENT_MASK:
+ if (SCARG(uap, data) != sizeof(pe))
+ return (EINVAL);
+ if ((error = copyin(SCARG(uap, addr), &pe, sizeof(pe))))
+ return (error);
+ t->p_ptmask = pe.pe_set_event;
+ return (0);
+
+ case PT_GET_PROCESS_STATE:
+ if (SCARG(uap, data) != sizeof(*t->p_ptstat))
+ return (EINVAL);
+ return (copyout(t->p_ptstat, SCARG(uap, addr),
+ sizeof(*t->p_ptstat)));
+
case PT_SETREGS:
KASSERT((p->p_flag & P_SYSTEM) == 0);
if ((error = procfs_checkioperm(p, t)) != 0)
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 2d804b9c84f..642633e87e2 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.79 2005/05/29 03:20:42 deraadt Exp $ */
+/* $OpenBSD: proc.h,v 1.80 2005/09/14 20:55:59 kettenis Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -186,6 +186,9 @@ struct proc {
void *p_systrace; /* Back pointer to systrace */
+ int p_ptmask; /* Ptrace event mask */
+ struct ptrace_state *p_ptstat; /* Ptrace state */
+
int p_siglist; /* Signals arrived but not delivered. */
struct vnode *p_textvp; /* Vnode of executable. */
@@ -357,6 +360,7 @@ struct uidinfo *uid_find(uid_t);
#define FORK_NOZOMBIE 0x00000040
#define FORK_SHAREVM 0x00000080
#define FORK_SIGHAND 0x00000200
+#define FORK_PTRACE 0x00000400
#define PIDHASH(pid) (&pidhashtbl[(pid) & pidhash])
extern LIST_HEAD(pidhashhead, proc) *pidhashtbl;
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index e66a65a3c24..e20a7490fee 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ptrace.h,v 1.8 2003/06/02 23:28:21 millert Exp $ */
+/* $OpenBSD: ptrace.h,v 1.9 2005/09/14 20:55:59 kettenis Exp $ */
/* $NetBSD: ptrace.h,v 1.21 1996/02/09 18:25:26 christos Exp $ */
/*-
@@ -61,6 +61,22 @@ struct ptrace_io_desc {
#define PIOD_READ_I 3 /* Read from I space */
#define PIOD_WRITE_I 4 /* Write to I space */
+#define PT_SET_EVENT_MASK 12
+#define PT_GET_EVENT_MASK 13
+
+typedef struct ptrace_event {
+ int pe_set_event;
+} ptrace_event_t;
+
+#define PTRACE_FORK 0x0002 /* Report forks */
+
+#define PT_GET_PROCESS_STATE 14
+
+typedef struct ptrace_state {
+ int pe_report_event;
+ pid_t pe_other_pid;
+} ptrace_state_t;
+
#define PT_FIRSTMACH 32 /* for machine-specific requests */
#include <machine/ptrace.h> /* machine-specific requests, if any */