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.