Skip to content

Commit

Permalink
ptrace(2) following fork(2)
Browse files Browse the repository at this point in the history
ok miod@
  • Loading branch information
kettenis committed Sep 14, 2005
1 parent a3a5151 commit f38bed7
Show file tree
Hide file tree
Showing 6 changed files with 169 additions and 8 deletions.
65 changes: 64 additions & 1 deletion lib/libc/sys/ptrace.2
Original file line number Diff line number Diff line change
@@ -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.
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion sys/kern/kern_exit.c
Original file line number Diff line number Diff line change
@@ -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 $ */

/*
Expand Down Expand Up @@ -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.
Expand Down
49 changes: 46 additions & 3 deletions sys/kern/kern_fork.c
Original file line number Diff line number Diff line change
@@ -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 $ */

/*
Expand Down Expand Up @@ -55,6 +55,7 @@
#include <dev/rndvar.h>
#include <sys/pool.h>
#include <sys/mman.h>
#include <sys/ptrace.h>

#include <sys/syscallargs.h>

Expand All @@ -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*/
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -385,6 +422,12 @@ fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize,
while (p2->p_flag & P_PPWAIT)
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].
Expand Down
35 changes: 34 additions & 1 deletion sys/kern/sys_process.c
Original file line number Diff line number Diff line change
@@ -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 $ */

/*-
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 5 additions & 1 deletion sys/sys/proc.h
Original file line number Diff line number Diff line change
@@ -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 $ */

/*-
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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;
Expand Down
18 changes: 17 additions & 1 deletion sys/sys/ptrace.h
Original file line number Diff line number Diff line change
@@ -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 $ */

/*-
Expand Down Expand Up @@ -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 */

Expand Down

0 comments on commit f38bed7

Please sign in to comment.