summaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_fork.c44
-rw-r--r--sys/kern/kern_sig.c29
-rw-r--r--sys/kern/sys_ptrace_common.c13
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