diff options
author | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-02-20 22:23:40 +0000 |
---|---|---|
committer | Philip Guenthe <guenther@cvs.openbsd.org> | 2012-02-20 22:23:40 +0000 |
commit | 23d4c835c870fad1811850ff7a698a2f77d42891 (patch) | |
tree | 5a131e9e444f40e7cd66618e1c99d06b4bafa989 /sys | |
parent | b73a150e06f421a7575e708802b38aa3d837f2b7 (diff) |
First steps for making ptrace work with rthreads:
- move the P_TRACED and P_INEXEC flags, and p_oppid, p_ptmask, and
p_ptstat member from struct proc to struct process
- sort the PT_* requests into those that take a PID vs those that
can also take a TID
- stub in PT_GET_THREAD_FIRST and PT_GET_THREAD_NEXT
ok kettenis@
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/systrace.c | 8 | ||||
-rw-r--r-- | sys/kern/kern_exec.c | 12 | ||||
-rw-r--r-- | sys/kern/kern_exit.c | 26 | ||||
-rw-r--r-- | sys/kern/kern_fork.c | 45 | ||||
-rw-r--r-- | sys/kern/kern_prot.c | 4 | ||||
-rw-r--r-- | sys/kern/kern_sig.c | 32 | ||||
-rw-r--r-- | sys/kern/kern_sysctl.c | 4 | ||||
-rw-r--r-- | sys/kern/sched_bsd.c | 4 | ||||
-rw-r--r-- | sys/kern/sys_process.c | 182 | ||||
-rw-r--r-- | sys/miscfs/procfs/procfs_vnops.c | 4 | ||||
-rw-r--r-- | sys/sys/proc.h | 20 | ||||
-rw-r--r-- | sys/sys/ptrace.h | 11 | ||||
-rw-r--r-- | sys/sys/signalvar.h | 4 |
13 files changed, 223 insertions, 133 deletions
diff --git a/sys/dev/systrace.c b/sys/dev/systrace.c index f48ffdec652..16d01c7d53d 100644 --- a/sys/dev/systrace.c +++ b/sys/dev/systrace.c @@ -1,4 +1,4 @@ -/* $OpenBSD: systrace.c,v 1.61 2012/02/15 04:26:27 guenther Exp $ */ +/* $OpenBSD: systrace.c,v 1.62 2012/02/20 22:23:39 guenther Exp $ */ /* * Copyright 2002 Niels Provos <provos@citi.umich.edu> * All rights reserved. @@ -1203,12 +1203,12 @@ systrace_attach(struct fsystrace *fst, pid_t pid) struct proc *proc, *p = curproc; struct str_process *newstrp; - if ((proc = pfind(pid)) == NULL) { + if ((proc = pfind(pid)) == NULL || (proc->p_flag & P_THREAD)) { error = ESRCH; goto out; } - if (ISSET(proc->p_flag, P_INEXEC)) { + if (ISSET(proc->p_p->ps_flags, PS_INEXEC)) { error = EAGAIN; goto out; } @@ -1217,7 +1217,7 @@ systrace_attach(struct fsystrace *fst, pid_t pid) * You can't attach to a process if: * (1) it's the process that's doing the attaching, */ - if (proc->p_pid == p->p_pid) { + if (proc->p_p == p->p_p) { error = EINVAL; goto out; } diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 1b1ac0d84d2..c8c2f1c1378 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_exec.c,v 1.123 2012/02/15 04:26:27 guenther Exp $ */ +/* $OpenBSD: kern_exec.c,v 1.124 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $ */ /*- @@ -275,7 +275,7 @@ sys_execve(struct proc *p, void *v, register_t *retval) * Cheap solution to complicated problems. * Mark this process as "leave me alone, I'm execing". */ - atomic_setbits_int(&p->p_flag, P_INEXEC); + atomic_setbits_int(&pr->ps_flags, PS_INEXEC); #if NSYSTRACE > 0 if (ISSET(p->p_flag, P_SYSTRACE)) { @@ -642,7 +642,7 @@ sys_execve(struct proc *p, void *v, register_t *retval) goto free_pack_abort; #endif - if (p->p_flag & P_TRACED) + if (pr->ps_flags & PS_TRACED) psignal(p, SIGTRAP); free(pack.ep_hdr, M_EXEC); @@ -680,7 +680,7 @@ sys_execve(struct proc *p, void *v, register_t *retval) ktremul(p, p->p_emul->e_name); #endif - atomic_clearbits_int(&p->p_flag, P_INEXEC); + atomic_clearbits_int(&pr->ps_flags, PS_INEXEC); single_thread_clear(p); #if NSYSTRACE > 0 @@ -718,7 +718,7 @@ bad: #if NSYSTRACE > 0 clrflag: #endif - atomic_clearbits_int(&p->p_flag, P_INEXEC); + atomic_clearbits_int(&pr->ps_flags, PS_INEXEC); single_thread_clear(p); if (pathbuf != NULL) @@ -747,7 +747,7 @@ free_pack_abort: exit1(p, W_EXITCODE(0, SIGABRT), EXIT_NORMAL); /* NOTREACHED */ - atomic_clearbits_int(&p->p_flag, P_INEXEC); + atomic_clearbits_int(&pr->ps_flags, PS_INEXEC); if (pathbuf != NULL) pool_put(&namei_pool, pathbuf); diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c index 50e9e0e3cf9..89f4fa423fc 100644 --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_exit.c,v 1.106 2012/01/17 02:34:18 guenther Exp $ */ +/* $OpenBSD: kern_exit.c,v 1.107 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: kern_exit.c,v 1.39 1996/04/22 01:38:25 christos Exp $ */ /* @@ -262,9 +262,8 @@ exit1(struct proc *p, int rv, int flags) * Traced processes are killed * since their existence means someone is screwing up. */ - if (qr->ps_mainproc->p_flag & P_TRACED) { - atomic_clearbits_int(&qr->ps_mainproc->p_flag, - P_TRACED); + if (qr->ps_flags & PS_TRACED) { + atomic_clearbits_int(&qr->ps_flags, PS_TRACED); prsignal(qr, SIGKILL); } } @@ -476,7 +475,8 @@ loop: } if (p->p_stat == SSTOP && (p->p_flag & (P_WAITED|P_SUSPSINGLE)) == 0 && - (p->p_flag & P_TRACED || SCARG(uap, options) & WUNTRACED)) { + (pr->ps_flags & PS_TRACED || + SCARG(uap, options) & WUNTRACED)) { atomic_setbits_int(&p->p_flag, P_WAITED); retval[0] = p->p_pid; @@ -515,16 +515,18 @@ loop: void proc_finish_wait(struct proc *waiter, struct proc *p) { - struct process *tr; + struct process *pr, *tr; /* * If we got the child via a ptrace 'attach', * we need to give it back to the old parent. */ - if (p->p_oppid && (tr = prfind(p->p_oppid))) { - atomic_clearbits_int(&p->p_flag, P_TRACED); - p->p_oppid = 0; - proc_reparent(p->p_p, tr); + pr = p->p_p; + if ((p->p_flag & P_THREAD) == 0 && pr->ps_oppid && + (tr = prfind(pr->ps_oppid))) { + atomic_clearbits_int(&pr->ps_flags, PS_TRACED); + pr->ps_oppid = 0; + proc_reparent(pr, tr); if (p->p_exitsig != 0) prsignal(tr, p->p_exitsig); wakeup(tr); @@ -560,8 +562,8 @@ proc_zap(struct proc *p) struct process *pr = p->p_p; pool_put(&rusage_pool, p->p_ru); - if (p->p_ptstat) - free(p->p_ptstat, M_SUBPROC); + if ((p->p_flag & P_THREAD) == 0 && pr->ps_ptstat) + free(pr->ps_ptstat, M_SUBPROC); /* * Finally finished with old proc entry. diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 0c3745ba139..bf667d3b901 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_fork.c,v 1.133 2011/12/14 07:32:16 guenther Exp $ */ +/* $OpenBSD: kern_fork.c,v 1.134 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */ /* @@ -85,7 +85,7 @@ fork_return(void *arg) { struct proc *p = (struct proc *)arg; - if (p->p_flag & P_TRACED) + if (p->p_p->ps_flags & PS_TRACED) psignal(p, SIGTRAP); child_return(p); @@ -98,7 +98,7 @@ sys_fork(struct proc *p, void *v, register_t *retval) int flags; flags = FORK_FORK; - if (p->p_ptmask & PTRACE_FORK) + if (p->p_p->ps_ptmask & PTRACE_FORK) flags |= FORK_PTRACE; return (fork1(p, SIGCHLD, flags, NULL, 0, fork_return, NULL, retval, NULL)); @@ -341,7 +341,7 @@ fork1(struct proc *curp, int exitsig, int flags, void *stack, pid_t *tidptr, if (curp->p_flag & P_PROFIL) startprofclock(p); if (flags & FORK_PTRACE) - atomic_setbits_int(&p->p_flag, curp->p_flag & P_TRACED); + atomic_setbits_int(&pr->ps_flags, curpr->ps_flags & PS_TRACED); /* bump references to the text vnode (for procfs) */ p->p_textvp = curp->p_textvp; @@ -427,7 +427,7 @@ fork1(struct proc *curp, int exitsig, int flags, void *stack, pid_t *tidptr, forkstat.sizkthread += vm->vm_dsize + vm->vm_ssize; } - if (p->p_flag & P_TRACED && flags & FORK_FORK) + if (pr->ps_flags & PS_TRACED && flags & FORK_FORK) newptstat = malloc(sizeof(*newptstat), M_SUBPROC, M_WAITOK); #if NSYSTRACE > 0 if (ISSET(curp->p_flag, P_SYSTRACE)) @@ -445,24 +445,23 @@ fork1(struct proc *curp, int exitsig, int flags, void *stack, pid_t *tidptr, if ((flags & FORK_THREAD) == 0) { LIST_INSERT_AFTER(curpr, pr, ps_pglist); LIST_INSERT_HEAD(&curpr->ps_children, pr, ps_sibling); - } - if (p->p_flag & P_TRACED) { - p->p_oppid = curp->p_pid; - if ((flags & FORK_THREAD) == 0 && - pr->ps_pptr != curpr->ps_pptr) - proc_reparent(pr, curpr->ps_pptr); - - /* - * Set ptrace status. - */ - if (flags & FORK_FORK) { - p->p_ptstat = newptstat; - newptstat = NULL; - curp->p_ptstat->pe_report_event = PTRACE_FORK; - p->p_ptstat->pe_report_event = PTRACE_FORK; - curp->p_ptstat->pe_other_pid = p->p_pid; - p->p_ptstat->pe_other_pid = curp->p_pid; + if (pr->ps_flags & PS_TRACED) { + pr->ps_oppid = curpr->ps_pid; + if (pr->ps_pptr != curpr->ps_pptr) + proc_reparent(pr, curpr->ps_pptr); + + /* + * Set ptrace status. + */ + if (flags & FORK_FORK) { + pr->ps_ptstat = newptstat; + newptstat = NULL; + curpr->ps_ptstat->pe_report_event = PTRACE_FORK; + pr->ps_ptstat->pe_report_event = PTRACE_FORK; + curpr->ps_ptstat->pe_other_pid = pr->ps_pid; + pr->ps_ptstat->pe_other_pid = curpr->ps_pid; + } } } @@ -527,7 +526,7 @@ fork1(struct proc *curp, int exitsig, int flags, void *stack, pid_t *tidptr, /* * If we're tracing the child, alert the parent too. */ - if ((flags & FORK_PTRACE) && (curp->p_flag & P_TRACED)) + if ((flags & FORK_PTRACE) && (curpr->ps_flags & PS_TRACED)) psignal(curp, SIGTRAP); /* diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c index e936e44970e..95a7c0a2401 100644 --- a/sys/kern/kern_prot.c +++ b/sys/kern/kern_prot.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_prot.c,v 1.51 2011/10/15 23:35:29 guenther Exp $ */ +/* $OpenBSD: kern_prot.c,v 1.52 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $ */ /* @@ -884,7 +884,7 @@ int proc_cansugid(struct proc *p) { /* ptrace(2)d processes shouldn't. */ - if ((p->p_flag & P_TRACED) != 0) + if ((p->p_p->ps_flags & PS_TRACED) != 0) return (0); /* processes with shared filedescriptors shouldn't. */ diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index de6f59f7188..e3ec6386bc0 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.133 2012/01/25 06:12:13 guenther Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.134 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -694,7 +694,8 @@ trapsignal(struct proc *p, int signum, u_long trapno, int code, int mask; mask = sigmask(signum); - if ((p->p_flag & P_TRACED) == 0 && (ps->ps_sigcatch & mask) != 0 && + if ((p->p_p->ps_flags & PS_TRACED) == 0 && + (ps->ps_sigcatch & mask) != 0 && (p->p_sigmask & mask) == 0) { #ifdef KTRACE if (KTRPOINT(p, KTR_PSIG)) { @@ -805,7 +806,7 @@ ptsignal(struct proc *p, int signum, enum signal_type type) /* * If proc is traced, always give parent a chance. */ - if (p->p_flag & P_TRACED) { + if (pr->ps_flags & PS_TRACED) { action = SIG_DFL; atomic_setbits_int(&p->p_siglist, mask); } else if (p->p_sigdivert & mask) { @@ -890,7 +891,7 @@ ptsignal(struct proc *p, int signum, enum signal_type type) * so it can discover the signal in issignal() and stop * for the parent. */ - if (p->p_flag & P_TRACED) + if (pr->ps_flags & PS_TRACED) goto run; /* * If SIGCONT is default (or ignored) and process is @@ -929,14 +930,16 @@ ptsignal(struct proc *p, int signum, enum signal_type type) * If traced process is already stopped, * then no further action is necessary. */ - if (p->p_flag & P_TRACED) + if (pr->ps_flags & PS_TRACED) goto out; /* * Kill signal always sets processes running. */ - if (signum == SIGKILL) + if (signum == SIGKILL) { + atomic_clearbits_int(&p->p_flag, P_SUSPSIG); goto runfast; + } if (prop & SA_CONT) { /* @@ -950,6 +953,7 @@ ptsignal(struct proc *p, int signum, enum signal_type type) * Otherwise, process goes back to sleep state. */ atomic_setbits_int(&p->p_flag, P_CONTINUED); + atomic_clearbits_int(&p->p_flag, P_SUSPSIG); wakeparent = 1; if (action == SIG_DFL) atomic_clearbits_int(&p->p_siglist, mask); @@ -1022,13 +1026,14 @@ out: int issignal(struct proc *p) { + struct process *pr = p->p_p; int signum, mask, prop; int dolock = (p->p_flag & P_SINTR) == 0; int s; for (;;) { mask = p->p_siglist & ~p->p_sigmask; - if (p->p_p->ps_flags & PS_PPWAIT) + if (pr->ps_flags & PS_PPWAIT) mask &= ~stopsigmask; if (mask == 0) /* no signal to send */ return (0); @@ -1041,11 +1046,10 @@ issignal(struct proc *p) * only if P_TRACED was on when they were posted. */ if (mask & p->p_sigacts->ps_sigignore && - (p->p_flag & P_TRACED) == 0) + (pr->ps_flags & PS_TRACED) == 0) continue; - if (p->p_flag & P_TRACED && - (p->p_p->ps_flags & PS_PPWAIT) == 0) { + if ((pr->ps_flags & (PS_TRACED | PS_PPWAIT)) == PS_TRACED) { /* * If traced, always stop, and stay * stopped until released by the debugger. @@ -1062,7 +1066,7 @@ issignal(struct proc *p) * If we are no longer being traced, or the parent * didn't give us a signal, look for more signals. */ - if ((p->p_flag & P_TRACED) == 0 || p->p_xstat == 0) + if ((pr->ps_flags & PS_TRACED) == 0 || p->p_xstat == 0) continue; /* @@ -1110,8 +1114,8 @@ issignal(struct proc *p) * process group, ignore tty stop signals. */ if (prop & SA_STOP) { - if (p->p_flag & P_TRACED || - (p->p_p->ps_pgrp->pg_jobc == 0 && + if (pr->ps_flags & PS_TRACED || + (pr->ps_pgrp->pg_jobc == 0 && prop & SA_TTYSTOP)) break; /* == ignore */ p->p_xstat = signum; @@ -1138,7 +1142,7 @@ issignal(struct proc *p) * than SIGCONT, unless process is traced. */ if ((prop & SA_CONT) == 0 && - (p->p_flag & P_TRACED) == 0) + (pr->ps_flags & PS_TRACED) == 0) printf("issignal\n"); break; /* == ignore */ diff --git a/sys/kern/kern_sysctl.c b/sys/kern/kern_sysctl.c index 408cbf793a0..9fc8513424f 100644 --- a/sys/kern/kern_sysctl.c +++ b/sys/kern/kern_sysctl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sysctl.c,v 1.213 2012/02/15 04:29:09 guenther Exp $ */ +/* $OpenBSD: kern_sysctl.c,v 1.214 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: kern_sysctl.c,v 1.17 1996/05/20 17:49:05 mrg Exp $ */ /*- @@ -1584,7 +1584,7 @@ sysctl_proc_args(int *name, u_int namelen, void *oldp, size_t *oldlenp, return (ESRCH); /* Execing - danger. */ - if ((vp->p_flag & P_INEXEC)) + if ((vp->p_p->ps_flags & PS_INEXEC)) return (EBUSY); vm = vp->p_vmspace; diff --git a/sys/kern/sched_bsd.c b/sys/kern/sched_bsd.c index 2a79afb234e..6fb2772e5ce 100644 --- a/sys/kern/sched_bsd.c +++ b/sys/kern/sched_bsd.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sched_bsd.c,v 1.27 2011/07/07 18:00:33 guenther Exp $ */ +/* $OpenBSD: sched_bsd.c,v 1.28 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: kern_synch.c,v 1.37 1996/04/22 01:38:37 christos Exp $ */ /*- @@ -507,7 +507,7 @@ setrunnable(struct proc *p) * If we're being traced (possibly because someone attached us * while we were stopped), check for a signal from the debugger. */ - if ((p->p_flag & P_TRACED) != 0 && p->p_xstat != 0) + if ((p->p_p->ps_flags & PS_TRACED) != 0 && p->p_xstat != 0) atomic_setbits_int(&p->p_siglist, sigmask(p->p_xstat)); case SSLEEP: unsleep(p); /* e.g. when sending signals */ diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c index cfc19e44305..7ab663c1c65 100644 --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sys_process.c,v 1.48 2011/04/02 17:04:35 guenther Exp $ */ +/* $OpenBSD: sys_process.c,v 1.49 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: sys_process.c,v 1.55 1996/05/15 06:17:47 tls Exp $ */ /*- @@ -82,7 +82,9 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) syscallarg(caddr_t) addr; syscallarg(int) data; } */ *uap = v; - struct proc *t; /* target process */ + struct proc *t; /* target thread */ + struct process *tr; /* target process */ + struct proc *q; struct uio uio; struct iovec iov; struct ptrace_io_desc piod; @@ -99,24 +101,65 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) #endif int error, write; int temp; - int req; + int req = SCARG(uap, req); int s; /* "A foolish consistency..." XXX */ - if (SCARG(uap, req) == PT_TRACE_ME) + switch (req) { + case PT_TRACE_ME: t = p; - else { + break; + /* calls that only operate on the PID */ + case PT_READ_I: + case PT_READ_D: + case PT_WRITE_I: + case PT_WRITE_D: + case PT_KILL: + case PT_ATTACH: + case PT_IO: + case PT_SET_EVENT_MASK: + case PT_GET_EVENT_MASK: + case PT_GET_PROCESS_STATE: + case PT_GET_THREAD_FIRST: + case PT_GET_THREAD_NEXT: + default: /* Find the process we're supposed to be operating on. */ if ((t = pfind(SCARG(uap, pid))) == NULL) return (ESRCH); + if (t->p_flag & P_THREAD) + return (ESRCH); + break; + + /* calls that accept a PID or a thread ID */ + case PT_CONTINUE: + case PT_DETACH: +#ifdef PT_STEP + case PT_STEP: +#endif + case PT_GETREGS: + case PT_SETREGS: + case PT_GETFPREGS: + case PT_SETFPREGS: + if (SCARG(uap, pid) > THREAD_PID_OFFSET) { + t = pfind(SCARG(uap, pid) - THREAD_PID_OFFSET); + if (t == NULL) + return (ESRCH); + } else { + if ((t = pfind(SCARG(uap, pid))) == NULL) + return (ESRCH); + if (t->p_flag & P_THREAD) + return (ESRCH); + } + break; } + tr = t->p_p; - if ((t->p_flag & P_INEXEC) != 0) + if ((tr->ps_flags & PS_INEXEC) != 0) return (EAGAIN); /* Make sure we can operate on it. */ - switch (SCARG(uap, req)) { + switch (req) { case PT_TRACE_ME: /* Saying that you're being traced is always legal. */ break; @@ -126,7 +169,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) * You can't attach to a process if: * (1) it's the process that's doing the attaching, */ - if (t->p_pid == p->p_pid) + if (tr == p->p_p) return (EINVAL); /* @@ -138,7 +181,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) /* * (3) it's already being traced, or */ - if (ISSET(t->p_flag, P_TRACED)) + if (ISSET(tr->ps_flags, PS_TRACED)) return (EBUSY); /* @@ -152,8 +195,8 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) * process which revokes its special privileges using * setuid() from being traced. This is good security.] */ - if ((t->p_cred->p_ruid != p->p_cred->p_ruid || - ISSET(t->p_p->ps_flags, PS_SUGIDEXEC | PS_SUGID)) && + if ((tr->ps_cred->p_ruid != p->p_cred->p_ruid || + ISSET(tr->ps_flags, PS_SUGIDEXEC | PS_SUGID)) && (error = suser(p, 0)) != 0) return (error); @@ -163,7 +206,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) * compiled with permanently insecure mode turned * on. */ - if ((t->p_pid == 1) && (securelevel > -1)) + if ((tr->ps_pid == 1) && (securelevel > -1)) return (EPERM); /* @@ -171,7 +214,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) * not init (because that would create a loop in * the process graph). */ - if (t->p_pid != 1 && inferior(p->p_p, t->p_p)) + if (tr->ps_pid != 1 && inferior(p->p_p, tr)) return (EINVAL); break; @@ -210,13 +253,13 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) * You can't do what you want to the process if: * (1) It's not being traced at all, */ - if (!ISSET(t->p_flag, P_TRACED)) + if (!ISSET(tr->ps_flags, PS_TRACED)) return (EPERM); /* * (2) it's not being traced by _you_, or */ - if (t->p_p->ps_pptr != p->p_p) + if (tr->ps_pptr != p->p_p) return (EBUSY); /* @@ -226,6 +269,31 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) return (EBUSY); break; + case PT_GET_THREAD_FIRST: + case PT_GET_THREAD_NEXT: + /* + * You can't do what you want to the process if: + * (1) It's not being traced at all, + */ + if (!ISSET(tr->ps_flags, PS_TRACED)) + return (EPERM); + + /* + * (2) it's not being traced by _you_, or + */ + if (tr->ps_pptr != p->p_p) + return (EBUSY); + + /* + * Do the work here because the request isn't actually + * associated with 't' + * XXX + */ + + return (ENOTSUP); /* XXX */ + + break; + default: /* It was not a legal request. */ return (EINVAL); } @@ -237,15 +305,15 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) write = 0; *retval = 0; - switch (SCARG(uap, req)) { + switch (req) { case PT_TRACE_ME: /* Just set the trace flag. */ - atomic_setbits_int(&t->p_flag, P_TRACED); - t->p_oppid = t->p_p->ps_pptr->ps_pid; - if (t->p_ptstat == NULL) - t->p_ptstat = malloc(sizeof(*t->p_ptstat), + atomic_setbits_int(&tr->ps_flags, PS_TRACED); + tr->ps_oppid = tr->ps_pptr->ps_pid; + if (tr->ps_ptstat == NULL) + tr->ps_ptstat = malloc(sizeof(*tr->ps_ptstat), M_SUBPROC, M_WAITOK); - bzero(t->p_ptstat, sizeof(*t->p_ptstat)); + bzero(tr->ps_ptstat, sizeof(*tr->ps_ptstat)); return (0); case PT_WRITE_I: /* XXX no separate I and D spaces */ @@ -353,7 +421,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) /* * Arrange for a single-step, if that's requested and possible. */ - error = process_sstep(t, SCARG(uap, req) == PT_STEP); + error = process_sstep(t, req == PT_STEP); if (error) goto relebad; #endif @@ -380,25 +448,26 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) /* * Arrange for a single-step, if that's requested and possible. */ - error = process_sstep(t, SCARG(uap, req) == PT_STEP); + error = process_sstep(t, req == PT_STEP); if (error) goto relebad; #endif /* give process back to original parent or init */ - if (t->p_oppid != t->p_p->ps_pptr->ps_pid) { + if (tr->ps_oppid != tr->ps_pptr->ps_pid) { struct process *ppr; - ppr = prfind(t->p_oppid); - proc_reparent(t->p_p, ppr ? ppr : initproc->p_p); + ppr = prfind(tr->ps_oppid); + proc_reparent(tr, ppr ? ppr : initproc->p_p); } /* not being traced any more */ - t->p_oppid = 0; - atomic_clearbits_int(&t->p_flag, P_TRACED|P_WAITED); + tr->ps_oppid = 0; + atomic_clearbits_int(&tr->ps_flags, PS_TRACED); + atomic_clearbits_int(&t->p_flag, P_WAITED); sendsig: - bzero(t->p_ptstat, sizeof(*t->p_ptstat)); + bzero(tr->ps_ptstat, sizeof(*tr->ps_ptstat)); /* Finally, deliver the requested signal (or none). */ if (t->p_stat == SSTOP) { @@ -410,6 +479,13 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) if (SCARG(uap, data) != 0) psignal(t, SCARG(uap, data)); } + SCHED_LOCK(s); + TAILQ_FOREACH(q, &tr->ps_threads, p_thr_link) { + if (q != t && q->p_stat == SSTOP) { + setrunnable(q); + } + } + SCHED_UNLOCK(s); return (0); relebad: @@ -430,12 +506,12 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) * proc gets to see all the action. * Stop the target. */ - atomic_setbits_int(&t->p_flag, P_TRACED); - t->p_oppid = t->p_p->ps_pptr->ps_pid; - if (t->p_p->ps_pptr != p->p_p) - proc_reparent(t->p_p, p->p_p); - if (t->p_ptstat == NULL) - t->p_ptstat = malloc(sizeof(*t->p_ptstat), + atomic_setbits_int(&tr->ps_flags, PS_TRACED); + tr->ps_oppid = tr->ps_pptr->ps_pid; + if (tr->ps_pptr != p->p_p) + proc_reparent(tr, p->p_p); + if (tr->ps_ptstat == NULL) + tr->ps_ptstat = malloc(sizeof(*tr->ps_ptstat), M_SUBPROC, M_WAITOK); SCARG(uap, data) = SIGSTOP; goto sendsig; @@ -444,25 +520,25 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) if (SCARG(uap, data) != sizeof(pe)) return (EINVAL); bzero(&pe, sizeof(pe)); - pe.pe_set_event = t->p_ptmask; + pe.pe_set_event = tr->ps_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; + tr->ps_ptmask = pe.pe_set_event; return (0); case PT_GET_PROCESS_STATE: - if (SCARG(uap, data) != sizeof(*t->p_ptstat)) + if (SCARG(uap, data) != sizeof(*tr->ps_ptstat)) return (EINVAL); - return (copyout(t->p_ptstat, SCARG(uap, addr), - sizeof(*t->p_ptstat))); + return (copyout(tr->ps_ptstat, SCARG(uap, addr), + sizeof(*tr->ps_ptstat))); case PT_SETREGS: KASSERT((p->p_flag & P_SYSTEM) == 0); - if ((error = process_checkioperm(p, t)) != 0) + if ((error = process_checkioperm(p, tr)) != 0) return (error); regs = malloc(sizeof(*regs), M_TEMP, M_WAITOK); @@ -474,7 +550,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) return (error); case PT_GETREGS: KASSERT((p->p_flag & P_SYSTEM) == 0); - if ((error = process_checkioperm(p, t)) != 0) + if ((error = process_checkioperm(p, tr)) != 0) return (error); regs = malloc(sizeof(*regs), M_TEMP, M_WAITOK); @@ -487,7 +563,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) #ifdef PT_SETFPREGS case PT_SETFPREGS: KASSERT((p->p_flag & P_SYSTEM) == 0); - if ((error = process_checkioperm(p, t)) != 0) + if ((error = process_checkioperm(p, tr)) != 0) return (error); fpregs = malloc(sizeof(*fpregs), M_TEMP, M_WAITOK); @@ -501,7 +577,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) #ifdef PT_GETFPREGS case PT_GETFPREGS: KASSERT((p->p_flag & P_SYSTEM) == 0); - if ((error = process_checkioperm(p, t)) != 0) + if ((error = process_checkioperm(p, tr)) != 0) return (error); fpregs = malloc(sizeof(*fpregs), M_TEMP, M_WAITOK); @@ -515,7 +591,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) #ifdef PT_SETXMMREGS case PT_SETXMMREGS: KASSERT((p->p_flag & P_SYSTEM) == 0); - if ((error = process_checkioperm(p, t)) != 0) + if ((error = process_checkioperm(p, tr)) != 0) return (error); xmmregs = malloc(sizeof(*xmmregs), M_TEMP, M_WAITOK); @@ -529,7 +605,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) #ifdef PT_GETXMMREGS case PT_GETXMMREGS: KASSERT((p->p_flag & P_SYSTEM) == 0); - if ((error = process_checkioperm(p, t)) != 0) + if ((error = process_checkioperm(p, tr)) != 0) return (error); xmmregs = malloc(sizeof(*xmmregs), M_TEMP, M_WAITOK); @@ -559,7 +635,7 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) * Check if a process is allowed to fiddle with the memory of another. * * p = tracer - * t = tracee + * tr = tracee * * 1. You can't attach to a process not owned by you or one that has raised * its privileges. @@ -573,19 +649,19 @@ sys_ptrace(struct proc *p, void *v, register_t *retval) * second. */ int -process_checkioperm(struct proc *p, struct proc *t) +process_checkioperm(struct proc *p, struct process *tr) { int error; - if ((t->p_cred->p_ruid != p->p_cred->p_ruid || - ISSET(t->p_p->ps_flags, PS_SUGIDEXEC | PS_SUGID)) && + if ((tr->ps_cred->p_ruid != p->p_cred->p_ruid || + ISSET(tr->ps_flags, PS_SUGIDEXEC | PS_SUGID)) && (error = suser(p, 0)) != 0) return (error); - if ((t->p_pid == 1) && (securelevel > -1)) + if ((tr->ps_pid == 1) && (securelevel > -1)) return (EPERM); - if (t->p_flag & P_INEXEC) + if (tr->ps_flags & PS_INEXEC) return (EAGAIN); return (0); @@ -603,7 +679,7 @@ process_domem(struct proc *curp, struct proc *p, struct uio *uio, int req) if (len == 0) return (0); - if ((error = process_checkioperm(curp, p)) != 0) + if ((error = process_checkioperm(curp, p->p_p)) != 0) return (error); /* XXXCDC: how should locking work here? */ diff --git a/sys/miscfs/procfs/procfs_vnops.c b/sys/miscfs/procfs/procfs_vnops.c index 25ac75ee0bb..be897b61490 100644 --- a/sys/miscfs/procfs/procfs_vnops.c +++ b/sys/miscfs/procfs/procfs_vnops.c @@ -1,4 +1,4 @@ -/* $OpenBSD: procfs_vnops.c,v 1.53 2011/12/24 04:34:20 guenther Exp $ */ +/* $OpenBSD: procfs_vnops.c,v 1.54 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: procfs_vnops.c,v 1.40 1996/03/16 23:52:55 christos Exp $ */ /* @@ -198,7 +198,7 @@ procfs_open(void *v) ((pfs->pfs_flags & O_EXCL) && (ap->a_mode & FWRITE))) return (EBUSY); - if ((error = process_checkioperm(p1, p2)) != 0) + if ((error = process_checkioperm(p1, p2->p_p)) != 0) return (error); if (ap->a_mode & FWRITE) diff --git a/sys/sys/proc.h b/sys/sys/proc.h index 5a5215a312a..e6a584101b0 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.149 2012/01/07 05:38:12 guenther Exp $ */ +/* $OpenBSD: proc.h,v 1.150 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */ /*- @@ -162,6 +162,10 @@ struct process { struct vnode *ps_tracevp; /* Trace to vnode. */ struct ucred *ps_tracecred; /* Creds for writing trace */ + pid_t ps_oppid; /* Save parent pid during ptrace. */ + int ps_ptmask; /* Ptrace event mask */ + struct ptrace_state *ps_ptstat;/* Ptrace state */ + /* End area that is zeroed on creation. */ #define ps_endzero ps_startcopy @@ -236,9 +240,8 @@ struct proc { LIST_ENTRY(proc) p_hash; /* Hash chain. */ /* The following fields are all zeroed upon creation in fork. */ -#define p_startzero p_oppid +#define p_startzero p_dupfd - pid_t p_oppid; /* Save parent pid during ptrace. XXX */ int p_dupfd; /* Sideways return value from filedescopen. XXX */ long p_thrslpid; /* for thrsleep syscall */ @@ -270,9 +273,6 @@ 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. */ @@ -341,7 +341,7 @@ struct proc { #define _P_SUGID 0x000100 /* Had set id privs since last exec. */ #define P_SYSTEM 0x000200 /* No sigs, stats or swapping. */ #define P_TIMEOUT 0x000400 /* Timing out during sleep. */ -#define P_TRACED 0x000800 /* Debugged process being traced. */ +#define _P_TRACED 0x000800 /* Debugged process being traced. */ #define P_WAITED 0x001000 /* Debugging proc has waited for child. */ /* XXX - Should be merged with INEXEC */ #define P_WEXIT 0x002000 /* Working on exiting. */ @@ -357,7 +357,7 @@ struct proc { #define P_SUSPSINGLE 0x080000 /* Need to stop for single threading. */ #define P_NOZOMBIE 0x100000 /* Pid 1 waits for me instead of dad */ -#define P_INEXEC 0x200000 /* Process is doing an exec right now */ +#define _P_INEXEC 0x200000 /* Process is doing an exec right now */ #define P_SYSTRACE 0x400000 /* Process system call tracing active*/ #define P_CONTINUED 0x800000 /* Proc has continued from a stopped state. */ #define _P_SINGLEEXIT 0x1000000 /* Other threads must die. */ @@ -372,8 +372,10 @@ struct proc { #define P_CONTROLT _P_CONTROLT #define P_PPWAIT _P_PPWAIT #define P_SUGID _P_SUGID +#define P_TRACED _P_TRACED #define P_EXEC _P_EXEC #define P_SUGIDEXEC _P_SUGIDEXEC +#define P_INEXEC _P_INEXEC #endif #define P_BITS \ @@ -386,7 +388,7 @@ struct proc { /* Macro to compute the exit signal to be delivered. */ #define P_EXITSIG(p) \ - (((p)->p_flag & P_TRACED) ? SIGCHLD : (p)->p_exitsig) + (((p)->p_p->ps_flags & PS_TRACED) ? SIGCHLD : (p)->p_exitsig) #define THREAD_PID_OFFSET 1000000 diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h index 4baebcd3aca..d29b03bcb22 100644 --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -1,4 +1,4 @@ -/* $OpenBSD: ptrace.h,v 1.12 2010/07/26 01:56:27 guenther Exp $ */ +/* $OpenBSD: ptrace.h,v 1.13 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: ptrace.h,v 1.21 1996/02/09 18:25:26 christos Exp $ */ /*- @@ -78,6 +78,13 @@ typedef struct ptrace_state { pid_t pe_other_pid; } ptrace_state_t; +#define PT_GET_THREAD_FIRST 15 +#define PT_GET_THREAD_NEXT 16 + +struct ptrace_thread_state { + pid_t pts_tid; +}; + #define PT_FIRSTMACH 32 /* for machine-specific requests */ #include <machine/ptrace.h> /* machine-specific requests, if any */ @@ -107,7 +114,7 @@ int process_sstep(struct proc *p, int sstep); int process_write_fpregs(struct proc *p, struct fpreg *regs); #endif int process_write_regs(struct proc *p, struct reg *regs); -int process_checkioperm(struct proc *, struct proc *); +int process_checkioperm(struct proc *, struct process *); int process_domem(struct proc *, struct proc *, struct uio *, int); #ifndef FIX_SSTEP diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index 692d2c730f6..38c92cfa9c3 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: signalvar.h,v 1.24 2011/11/22 23:20:19 joshe Exp $ */ +/* $OpenBSD: signalvar.h,v 1.25 2012/02/20 22:23:39 guenther Exp $ */ /* $NetBSD: signalvar.h,v 1.17 1996/04/22 01:23:31 christos Exp $ */ /* @@ -77,7 +77,7 @@ struct sigacts { */ #define CURSIG(p) \ (((p)->p_siglist == 0 || \ - (((p)->p_flag & P_TRACED) == 0 && \ + (((p)->p_p->ps_flags & PS_TRACED) == 0 && \ ((p)->p_siglist & ~(p)->p_sigmask) == 0)) ? \ 0 : issignal(p)) |