diff options
Diffstat (limited to 'sys/kern')
| -rw-r--r-- | sys/kern/kern_fork.c | 44 | ||||
| -rw-r--r-- | sys/kern/kern_sig.c | 29 | ||||
| -rw-r--r-- | sys/kern/sys_ptrace_common.c | 13 |
3 files changed, 51 insertions, 35 deletions
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index 02b63231653..22cf730fa4a 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_fork.c,v 1.204 2018/04/16 14:51:59 kamil Exp $ */ +/* $NetBSD: kern_fork.c,v 1.205 2018/05/01 16:37:23 kamil Exp $ */ /*- * Copyright (c) 1999, 2001, 2004, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_fork.c,v 1.204 2018/04/16 14:51:59 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_fork.c,v 1.205 2018/05/01 16:37:23 kamil Exp $"); #include "opt_ktrace.h" #include "opt_dtrace.h" @@ -218,7 +218,7 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, int count; vaddr_t uaddr; int tnprocs; - int tracefork, tracevforkdone; + int tracefork, tracevfork, tracevforkdone; int error = 0; p1 = l1->l_proc; @@ -478,21 +478,19 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, */ tracefork = (p1->p_slflag & (PSL_TRACEFORK|PSL_TRACED)) == (PSL_TRACEFORK|PSL_TRACED) && (flags && FORK_PPWAIT) == 0; + tracevfork = (p1->p_slflag & (PSL_TRACEVFORK|PSL_TRACED)) == + (PSL_TRACEVFORK|PSL_TRACED) && (flags && FORK_PPWAIT) != 0; tracevforkdone = (p1->p_slflag & (PSL_TRACEVFORK_DONE|PSL_TRACED)) == (PSL_TRACEVFORK_DONE|PSL_TRACED) && (flags && FORK_PPWAIT); - if (tracefork) { + if (tracefork || tracevfork) proc_changeparent(p2, p1->p_pptr); - /* - * Set ptrace status. - */ + if (tracefork) { p1->p_fpid = p2->p_pid; p2->p_fpid = p1->p_pid; } - if (tracevforkdone) { - /* - * Set ptrace status. - */ - p1->p_vfpid_done = p2->p_pid; + if (tracevfork) { + p1->p_vfpid = p2->p_pid; + p2->p_vfpid = p1->p_pid; } LIST_INSERT_AFTER(p1, p2, p_pglist); @@ -579,19 +577,35 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, retval[0] = p2->p_pid; retval[1] = 0; } + mutex_exit(p2->p_lock); /* + * Let the parent know that we are tracing its child. + */ + if (tracefork || tracevfork) { + mutex_enter(p1->p_lock); + p1->p_xsig = SIGTRAP; + p1->p_sigctx.ps_faked = true; // XXX + p1->p_sigctx.ps_info._signo = p1->p_xsig; + p1->p_sigctx.ps_info._code = TRAP_CHLD; + sigswitch(0, SIGTRAP, false); + // XXX ktrpoint(KTR_PSIG) + mutex_exit(p1->p_lock); + mutex_enter(proc_lock); + } + + /* * Preserve synchronization semantics of vfork. If waiting for * child to exec or exit, sleep until it clears LP_VFORKWAIT. */ - while (p2->p_lflag & PL_PPWAIT) + while (p2->p_lflag & PL_PPWAIT) // XXX: p2 can go invalid cv_wait(&p1->p_waitcv, proc_lock); /* * Let the parent know that we are tracing its child. */ - if (tracefork || tracevforkdone) { + if (tracevforkdone) { ksiginfo_t ksi; KSI_INIT_EMPTY(&ksi); @@ -599,6 +613,8 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, ksi.ksi_code = TRAP_CHLD; ksi.ksi_lid = l1->l_lid; kpsignal(p1, &ksi, NULL); + + p1->p_vfpid_done = retval[0]; } mutex_exit(proc_lock); diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index a713893e1c9..6111f7e0b25 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_sig.c,v 1.341 2018/05/01 13:48:38 kamil Exp $ */ +/* $NetBSD: kern_sig.c,v 1.342 2018/05/01 16:37:23 kamil Exp $ */ /*- * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -70,7 +70,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.341 2018/05/01 13:48:38 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.342 2018/05/01 16:37:23 kamil Exp $"); #include "opt_ptrace.h" #include "opt_dtrace.h" @@ -118,12 +118,12 @@ sigset_t sigcantmask __cacheline_aligned; static void ksiginfo_exechook(struct proc *, void *); static void proc_stop(struct proc *, int); +static void proc_stop_done(struct proc *, int); static void proc_stop_callout(void *); static int sigchecktrace(void); static int sigpost(struct lwp *, sig_t, int, int); static int sigput(sigpend_t *, struct proc *, ksiginfo_t *); static int sigunwait(struct proc *, const ksiginfo_t *); -static void sigswitch(int, int); static void sigacts_poolpage_free(struct pool *, void *); static void *sigacts_poolpage_alloc(struct pool *, int); @@ -1528,8 +1528,8 @@ proc_stop_done(struct proc *p, int ppmask) /* * Stop the current process and switch away when being stopped or traced. */ -static void -sigswitch(int ppmask, int signo) +void +sigswitch(int ppmask, int signo, bool relock) { struct lwp *l = curlwp; struct proc *p = l->l_proc; @@ -1555,7 +1555,7 @@ sigswitch(int ppmask, int signo) * a new signal, then signal the parent. */ if ((p->p_sflag & PS_STOPPING) != 0) { - if (!mutex_tryenter(proc_lock)) { + if (relock && !mutex_tryenter(proc_lock)) { mutex_exit(p->p_lock); mutex_enter(proc_lock); mutex_enter(p->p_lock); @@ -1665,7 +1665,7 @@ issignal(struct lwp *l) * we awaken, check for a signal from the debugger. */ if (p->p_stat == SSTOP || (p->p_sflag & PS_STOPPING) != 0) { - sigswitch(PS_NOCLDSTOP, 0); + sigswitch(PS_NOCLDSTOP, 0, true); signo = sigchecktrace(); } else signo = 0; @@ -1718,11 +1718,12 @@ issignal(struct lwp *l) /* * If traced, always stop, and stay stopped until released - * by the debugger. If the our parent process is waiting - * for us, don't hang as we could deadlock. + * by the debugger. If the our parent is our debugger waiting + * for us and we vforked, don't hang as we could deadlock. + * + * XXX: support PT_TRACE_ME called after vfork(2) */ - if ((p->p_slflag & PSL_TRACED) != 0 && - (p->p_lflag & PL_PPWAIT) == 0 && signo != SIGKILL) { + if ((p->p_slflag & PSL_TRACED) != 0 && signo != SIGKILL) { /* * Take the signal, but don't remove it from the * siginfo queue, because the debugger can send @@ -1735,7 +1736,7 @@ issignal(struct lwp *l) /* Emulation-specific handling of signal trace */ if (p->p_emul->e_tracesig == NULL || (*p->p_emul->e_tracesig)(p, signo) == 0) - sigswitch(0, signo); + sigswitch(0, signo, true); /* Check for a signal from the debugger. */ if ((signo = sigchecktrace()) == 0) @@ -1789,7 +1790,7 @@ issignal(struct lwp *l) p->p_xsig = signo; p->p_sflag &= ~PS_CONTINUED; signo = 0; - sigswitch(PS_NOCLDSTOP, p->p_xsig); + sigswitch(PS_NOCLDSTOP, p->p_xsig, true); } else if (prop & SA_IGNORE) { /* * Except for SIGCONT, shouldn't get here. @@ -2298,7 +2299,7 @@ proc_stoptrace(int trapno) p->p_xsig = signo; p->p_sigctx.ps_lwp = ksi.ksi_lid; p->p_sigctx.ps_info = ksi.ksi_info; - sigswitch(0, signo); + sigswitch(0, signo, true); mutex_exit(p->p_lock); if (ktrpoint(KTR_PSIG)) { diff --git a/sys/kern/sys_ptrace_common.c b/sys/kern/sys_ptrace_common.c index 4e483d846fd..ca2078ae146 100644 --- a/sys/kern/sys_ptrace_common.c +++ b/sys/kern/sys_ptrace_common.c @@ -1,4 +1,4 @@ -/* $NetBSD: sys_ptrace_common.c,v 1.39 2018/05/01 14:09:53 kamil Exp $ */ +/* $NetBSD: sys_ptrace_common.c,v 1.40 2018/05/01 16:37:23 kamil Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -118,7 +118,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.39 2018/05/01 14:09:53 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.40 2018/05/01 16:37:23 kamil Exp $"); #ifdef _KERNEL_OPT #include "opt_ptrace.h" @@ -634,23 +634,22 @@ ptrace_set_event_mask(struct proc *t, void *addr, size_t data) SET(t->p_slflag, PSL_TRACEFORK); else CLR(t->p_slflag, PSL_TRACEFORK); -#if notyet + if (pe.pe_set_event & PTRACE_VFORK) SET(t->p_slflag, PSL_TRACEVFORK); else CLR(t->p_slflag, PSL_TRACEVFORK); -#else - if (pe.pe_set_event & PTRACE_VFORK) - return ENOTSUP; -#endif + if (pe.pe_set_event & PTRACE_VFORK_DONE) SET(t->p_slflag, PSL_TRACEVFORK_DONE); else CLR(t->p_slflag, PSL_TRACEVFORK_DONE); + if (pe.pe_set_event & PTRACE_LWP_CREATE) SET(t->p_slflag, PSL_TRACELWP_CREATE); else CLR(t->p_slflag, PSL_TRACELWP_CREATE); + if (pe.pe_set_event & PTRACE_LWP_EXIT) SET(t->p_slflag, PSL_TRACELWP_EXIT); else |
