Module Name:    src
Committed By:   kamil
Date:           Tue Jun 11 23:18:55 UTC 2019

Modified Files:
        src/sys/kern: kern_exec.c kern_proc.c sys_ptrace_common.c
        src/sys/sys: proc.h ptrace.h

Log Message:
Add support for PTRACE_POSIX_SPAWN to report posix_spawn(3) events

posix_spawn(3) is a first class syscall in NetBSD, different to
(V)FORK+EXEC as these operations are executed in one go. This differs to
Linux and FreeBSD, where posix_spawn(3) is implemented with existing kernel
primitives (clone(2), vfork(2), exec(3)) inside libc.

Typically LLDB and GDB software is aware of FORK/VFORK events. As discussed
with the LLDB community, instead of slicing the posix_spawn(3) operation
into phases emulating (V)FORK+EXEC(+VFORK_DONE) and returning intermediate
state to the debugger, that might have abnormal state, introduce new event
type: PTRACE_POSIX_SPAWN.

A debugger implementor can easily map it into existing fork+exec semantics
or treat as a distinct event.

There is no functional change for existing debuggers as there was no
support for reporting posix_spawn(3) events on the kernel side.


To generate a diff of this commit:
cvs rdiff -u -r1.465 -r1.466 src/sys/kern/kern_exec.c
cvs rdiff -u -r1.232 -r1.233 src/sys/kern/kern_proc.c
cvs rdiff -u -r1.54 -r1.55 src/sys/kern/sys_ptrace_common.c
cvs rdiff -u -r1.352 -r1.353 src/sys/sys/proc.h
cvs rdiff -u -r1.64 -r1.65 src/sys/sys/ptrace.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/kern_exec.c
diff -u src/sys/kern/kern_exec.c:1.465 src/sys/kern/kern_exec.c:1.466
--- src/sys/kern/kern_exec.c:1.465	Thu May  9 20:50:14 2019
+++ src/sys/kern/kern_exec.c	Tue Jun 11 23:18:55 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_exec.c,v 1.465 2019/05/09 20:50:14 kamil Exp $	*/
+/*	$NetBSD: kern_exec.c,v 1.466 2019/06/11 23:18:55 kamil Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.465 2019/05/09 20:50:14 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.466 2019/06/11 23:18:55 kamil Exp $");
 
 #include "opt_exec.h"
 #include "opt_execfmt.h"
@@ -74,6 +74,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_exec.c,
 #include <sys/filedesc.h>
 #include <sys/kernel.h>
 #include <sys/proc.h>
+#include <sys/ptrace.h>
 #include <sys/mount.h>
 #include <sys/kmem.h>
 #include <sys/namei.h>
@@ -1269,7 +1270,8 @@ execve_runproc(struct lwp *l, struct exe
 
 	mutex_enter(proc_lock);
 
-	if (p->p_slflag & PSL_TRACED) {
+	/* posix_spawn(3) reports a single event with implied exec(3) */
+	if ((p->p_slflag & PSL_TRACED) && !is_spawn) {
 		mutex_enter(p->p_lock);
 		eventswitch(TRAP_EXEC);
 		mutex_enter(proc_lock);
@@ -1984,6 +1986,7 @@ spawn_return(void *arg)
 {
 	struct spawn_exec_data *spawn_data = arg;
 	struct lwp *l = curlwp;
+	struct proc *p = l->l_proc;
 	int error, newfd;
 	int ostat;
 	size_t i;
@@ -2013,7 +2016,7 @@ spawn_return(void *arg)
 	}
 
 	/* don't allow debugger access yet */
-	rw_enter(&l->l_proc->p_reflock, RW_WRITER);
+	rw_enter(&p->p_reflock, RW_WRITER);
 	have_reflock = true;
 
 	error = 0;
@@ -2072,16 +2075,16 @@ spawn_return(void *arg)
 		 * parent's p_nstopchild here.  For safety, just make
 		 * we're on the good side of SDEAD before we adjust.
 		 */
-		ostat = l->l_proc->p_stat;
+		ostat = p->p_stat;
 		KASSERT(ostat < SSTOP);
-		l->l_proc->p_stat = SSTOP;
-		l->l_proc->p_waited = 0;
-		l->l_proc->p_pptr->p_nstopchild++;
+		p->p_stat = SSTOP;
+		p->p_waited = 0;
+		p->p_pptr->p_nstopchild++;
 		mutex_exit(proc_lock);
 
 		/* Set process group */
 		if (spawn_data->sed_attrs->sa_flags & POSIX_SPAWN_SETPGROUP) {
-			pid_t mypid = l->l_proc->p_pid,
+			pid_t mypid = p->p_pid,
 			     pgrp = spawn_data->sed_attrs->sa_pgroup;
 
 			if (pgrp == 0)
@@ -2095,7 +2098,7 @@ spawn_return(void *arg)
 
 		/* Set scheduler policy */
 		if (spawn_data->sed_attrs->sa_flags & POSIX_SPAWN_SETSCHEDULER)
-			error = do_sched_setparam(l->l_proc->p_pid, 0,
+			error = do_sched_setparam(p->p_pid, 0,
 			    spawn_data->sed_attrs->sa_schedpolicy,
 			    &spawn_data->sed_attrs->sa_schedparam);
 		else if (spawn_data->sed_attrs->sa_flags
@@ -2122,10 +2125,10 @@ spawn_return(void *arg)
 
 		/* Set signal masks/defaults */
 		if (spawn_data->sed_attrs->sa_flags & POSIX_SPAWN_SETSIGMASK) {
-			mutex_enter(l->l_proc->p_lock);
+			mutex_enter(p->p_lock);
 			error = sigprocmask1(l, SIG_SETMASK,
 			    &spawn_data->sed_attrs->sa_sigmask, NULL);
-			mutex_exit(l->l_proc->p_lock);
+			mutex_exit(p->p_lock);
 			if (error)
 				goto report_error_stopped;
 		}
@@ -2149,8 +2152,8 @@ spawn_return(void *arg)
 			}
 		}
 		mutex_enter(proc_lock);
-		l->l_proc->p_stat = ostat;
-		l->l_proc->p_pptr->p_nstopchild--;
+		p->p_stat = ostat;
+		p->p_pptr->p_nstopchild--;
 		mutex_exit(proc_lock);
 	}
 
@@ -2172,6 +2175,19 @@ spawn_return(void *arg)
 	/* release our refcount on the data */
 	spawn_exec_data_release(spawn_data);
 
+	if (p->p_slflag & PSL_TRACED) {
+		/* Paranoid check */
+		mutex_enter(proc_lock);
+		if (!(p->p_slflag & PSL_TRACED)) {
+			mutex_exit(proc_lock);
+			goto cpu_return;
+		}
+
+		mutex_enter(p->p_lock);
+		eventswitch(TRAP_CHLD);
+	}
+
+ cpu_return:
 	/* and finally: leave to userland for the first time */
 	cpu_spawn_return(l);
 
@@ -2180,8 +2196,8 @@ spawn_return(void *arg)
 
  report_error_stopped:
 	mutex_enter(proc_lock);
-	l->l_proc->p_stat = ostat;
-	l->l_proc->p_pptr->p_nstopchild--;
+	p->p_stat = ostat;
+	p->p_pptr->p_nstopchild--;
 	mutex_exit(proc_lock);
  report_error:
 	if (have_reflock) {
@@ -2191,7 +2207,7 @@ spawn_return(void *arg)
 		 * taken ownership of the sed_exec part of spawn_data,
 		 * so release/free both here.
 		 */
-		rw_exit(&l->l_proc->p_reflock);
+		rw_exit(&p->p_reflock);
 		execve_free_data(&spawn_data->sed_exec);
 	}
 
@@ -2209,7 +2225,7 @@ spawn_return(void *arg)
 	spawn_exec_data_release(spawn_data);
 
 	/* done, exit */
-	mutex_enter(l->l_proc->p_lock);
+	mutex_enter(p->p_lock);
 	/*
 	 * Posix explicitly asks for an exit code of 127 if we report
 	 * errors from the child process - so, unfortunately, there
@@ -2545,6 +2561,13 @@ do_posix_spawn(struct lwp *l1, pid_t *pi
 	LIST_INSERT_HEAD(&p1->p_children, p2, p_sibling);
 	p2->p_exitsig = SIGCHLD;	/* signal for parent on exit */
 
+	if ((p1->p_slflag & (PSL_TRACEPOSIX_SPAWN|PSL_TRACED)) ==
+	    (PSL_TRACEPOSIX_SPAWN|PSL_TRACED)) {
+		proc_changeparent(p2, p1->p_pptr);
+		p1->p_pspid = p2->p_pid;
+		p2->p_pspid = p1->p_pid;
+	}
+
 	LIST_INSERT_AFTER(p1, p2, p_pglist);
 	LIST_INSERT_HEAD(&allproc, p2, p_list);
 
@@ -2582,7 +2605,23 @@ do_posix_spawn(struct lwp *l1, pid_t *pi
 	have_exec_lock = false;
 
 	*pid_res = pid;
-	return error;
+
+	if (error)
+		return error;
+
+	if (p1->p_slflag & PSL_TRACED) {
+		/* Paranoid check */
+		mutex_enter(proc_lock);
+		if ((p1->p_slflag & (PSL_TRACEPOSIX_SPAWN|PSL_TRACED)) !=
+		    (PSL_TRACEPOSIX_SPAWN|PSL_TRACED)) {
+			mutex_exit(proc_lock);
+			return 0;
+		}
+
+		mutex_enter(p1->p_lock);
+		eventswitch(TRAP_CHLD);
+	}
+	return 0;
 
  error_exit:
 	if (have_exec_lock) {

Index: src/sys/kern/kern_proc.c
diff -u src/sys/kern/kern_proc.c:1.232 src/sys/kern/kern_proc.c:1.233
--- src/sys/kern/kern_proc.c:1.232	Sat Jun  1 19:48:29 2019
+++ src/sys/kern/kern_proc.c	Tue Jun 11 23:18:55 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_proc.c,v 1.232 2019/06/01 19:48:29 kamil Exp $	*/
+/*	$NetBSD: kern_proc.c,v 1.233 2019/06/11 23:18:55 kamil Exp $	*/
 
 /*-
  * Copyright (c) 1999, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -62,7 +62,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.232 2019/06/01 19:48:29 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_proc.c,v 1.233 2019/06/11 23:18:55 kamil Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_kstack.h"
@@ -2266,6 +2266,7 @@ fill_proc(const struct proc *psrc, struc
 	p->p_vfpid_done = psrc->p_vfpid_done;
 	p->p_lwp_created = psrc->p_lwp_created;
 	p->p_lwp_exited = psrc->p_lwp_exited;
+	p->p_pspid = psrc->p_pspid;
 	COND_SET_VALUE(p->p_path, psrc->p_path, allowaddr);
 	COND_SET_VALUE(p->p_sigctx, psrc->p_sigctx, allowaddr);
 	p->p_nice = psrc->p_nice;

Index: src/sys/kern/sys_ptrace_common.c
diff -u src/sys/kern/sys_ptrace_common.c:1.54 src/sys/kern/sys_ptrace_common.c:1.55
--- src/sys/kern/sys_ptrace_common.c:1.54	Sat May 25 03:20:43 2019
+++ src/sys/kern/sys_ptrace_common.c	Tue Jun 11 23:18:55 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: sys_ptrace_common.c,v 1.54 2019/05/25 03:20:43 kamil Exp $	*/
+/*	$NetBSD: sys_ptrace_common.c,v 1.55 2019/06/11 23:18:55 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.54 2019/05/25 03:20:43 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.55 2019/06/11 23:18:55 kamil Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ptrace.h"
@@ -627,6 +627,8 @@ ptrace_get_event_mask(struct proc *t, vo
 	    PTRACE_LWP_CREATE : 0;
 	pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACELWP_EXIT) ?
 	    PTRACE_LWP_EXIT : 0;
+	pe.pe_set_event |= ISSET(t->p_slflag, PSL_TRACEPOSIX_SPAWN) ?
+	    PTRACE_POSIX_SPAWN : 0;
 	DPRINTF(("%s: lwp=%d event=%#x\n", __func__,
 	    t->p_sigctx.ps_lwp, pe.pe_set_event));
 	return copyout(&pe, addr, sizeof(pe));
@@ -671,6 +673,12 @@ ptrace_set_event_mask(struct proc *t, vo
 		SET(t->p_slflag, PSL_TRACELWP_EXIT);
 	else
 		CLR(t->p_slflag, PSL_TRACELWP_EXIT);
+
+	if (pe.pe_set_event & PTRACE_POSIX_SPAWN)
+		SET(t->p_slflag, PSL_TRACEPOSIX_SPAWN);
+	else
+		CLR(t->p_slflag, PSL_TRACEPOSIX_SPAWN);
+
 	return 0;
 }
 
@@ -700,6 +708,9 @@ ptrace_get_process_state(struct proc *t,
 	} else if (t->p_lwp_exited) {
 		ps.pe_report_event = PTRACE_LWP_EXIT;
 		ps.pe_lwp = t->p_lwp_exited;
+	} else if (t->p_pspid) {
+		ps.pe_report_event = PTRACE_POSIX_SPAWN;
+		ps.pe_other_pid = t->p_pspid;
 	}
 	DPRINTF(("%s: lwp=%d event=%#x pid=%d lwp=%d\n", __func__,
 	    t->p_sigctx.ps_lwp, ps.pe_report_event,
@@ -885,6 +896,7 @@ ptrace_sendsig(struct proc *t, struct lw
 	t->p_vfpid_done = 0;
 	t->p_lwp_created = 0;
 	t->p_lwp_exited = 0;
+	t->p_pspid = 0;
 
 	/* Finally, deliver the requested signal (or none). */
 	if (t->p_stat == SSTOP) {

Index: src/sys/sys/proc.h
diff -u src/sys/sys/proc.h:1.352 src/sys/sys/proc.h:1.353
--- src/sys/sys/proc.h:1.352	Sat Apr  6 11:54:21 2019
+++ src/sys/sys/proc.h	Tue Jun 11 23:18:55 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: proc.h,v 1.352 2019/04/06 11:54:21 kamil Exp $	*/
+/*	$NetBSD: proc.h,v 1.353 2019/06/11 23:18:55 kamil Exp $	*/
 
 /*-
  * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -316,6 +316,7 @@ struct proc {
 	pid_t 		p_vfpid_done;	/* :: vforked done pid */
 	lwpid_t		p_lwp_created;	/* :: lwp created */
 	lwpid_t		p_lwp_exited;	/* :: lwp exited */
+	pid_t 		p_pspid;	/* :: posix_spawn pid */
 	char		*p_path;	/* :: full pathname of executable */
 
 /*
@@ -411,6 +412,8 @@ struct proc {
 			0x00000008 /* traced process wants LWP create events */
 #define	PSL_TRACELWP_EXIT	\
 			0x00000010 /* traced process wants LWP exit events */
+#define	PSL_TRACEPOSIX_SPAWN	\
+			0x00000020 /* traced process wants posix_spawn events */
 
 #define	PSL_TRACED	0x00000800 /* Debugged process being traced */
 #define	PSL_CHTRACED	0x00400000 /* Child has been traced & reparented */

Index: src/sys/sys/ptrace.h
diff -u src/sys/sys/ptrace.h:1.64 src/sys/sys/ptrace.h:1.65
--- src/sys/sys/ptrace.h:1.64	Mon May  6 08:05:03 2019
+++ src/sys/sys/ptrace.h	Tue Jun 11 23:18:55 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: ptrace.h,v 1.64 2019/05/06 08:05:03 kamil Exp $	*/
+/*	$NetBSD: ptrace.h,v 1.65 2019/06/11 23:18:55 kamil Exp $	*/
 
 /*-
  * Copyright (c) 1984, 1993
@@ -108,6 +108,7 @@ typedef struct ptrace_state {
 #define	PTRACE_VFORK_DONE	0x0004	/* Report parent resumed from vforks */
 #define	PTRACE_LWP_CREATE	0x0008	/* Report LWP creation */
 #define	PTRACE_LWP_EXIT		0x0010	/* Report LWP termination */
+#define	PTRACE_POSIX_SPAWN	0x0020	/* Report posix_spawn */
 
 /*
  * Argument structure for PT_IO.

Reply via email to