commit 6a54d09e628780bbecec094c4ed779bdc8e1ab6b Author: kamil Date: Mon Sep 30 21:13:33 2019 +0000 Move TRAP_CHLD/TRAP_LWP ptrace information from struct proc to siginfo Storing struct ptrace_state information inside struct proc was vulnerable to synchronization bugs, as multiple events emitted in the same time were overwritting other ones. Cache the original parent process id in p_oppid. Reusing here p_opptr is in theory prone to slight race codition. Change the semantics of PT_GET_PROCESS_STATE, reutning EINVAL for calls prompting for the value in cases when there wasn't registered an appropriate event. Add an alternative approach to check the ptrace_state information, directly from the siginfo_t value returned from PT_GET_SIGINFO. The original PT_GET_PROCESS_STATE approach is kept for compat with older NetBSD and OpenBSD. New code is recommended to keep using PT_GET_PROCESS_STATE. Add a couple of compile-time asserts for assumptions in the code. No functional change intended in existing ptrace(2) software. All ATF ptrace(2) and ATF GDB tests pass. This change improves reliability of the threading ptrace(2) code. diff --git a/sys/compat/sys/siginfo.h b/sys/compat/sys/siginfo.h index 78a20284b011..5ea83b82657b 100644 --- a/sys/compat/sys/siginfo.h +++ b/sys/compat/sys/siginfo.h @@ -1,4 +1,4 @@ -/* $NetBSD: siginfo.h,v 1.7 2019/06/30 08:49:21 martin Exp $ */ +/* $NetBSD: siginfo.h,v 1.8 2019/09/30 21:13:33 kamil Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. @@ -75,6 +75,14 @@ struct __ksiginfo32 { int _error; uint64_t _args[8]; /* SYS_MAXSYSARGS */ } _syscall; + + struct { + int _pe_report_event; + union { + pid_t _pe_other_pid; + lwpid_t _pe_lwp; + } _option; + } _ptrace_state; } _reason; }; diff --git a/sys/kern/kern_exec.c b/sys/kern/kern_exec.c index 3d25d869ee76..cca6763c69fe 100644 --- a/sys/kern/kern_exec.c +++ b/sys/kern/kern_exec.c @@ -1285,7 +1285,7 @@ execve_runproc(struct lwp *l, struct execve_data * restrict data, /* 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); + eventswitch(TRAP_EXEC, 0, 0); mutex_enter(proc_lock); } @@ -2197,7 +2197,7 @@ spawn_return(void *arg) } mutex_enter(p->p_lock); - eventswitch(TRAP_CHLD); + eventswitch(TRAP_CHLD, PTRACE_POSIX_SPAWN, p->p_opptr->p_pid); } cpu_return: @@ -2578,8 +2578,6 @@ do_posix_spawn(struct lwp *l1, pid_t *pid_res, bool *child_ok, const char *path, 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); @@ -2633,7 +2631,7 @@ do_posix_spawn(struct lwp *l1, pid_t *pid_res, bool *child_ok, const char *path, } mutex_enter(p1->p_lock); - eventswitch(TRAP_CHLD); + eventswitch(TRAP_CHLD, PTRACE_POSIX_SPAWN, pid); } return 0; diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c index f3c778f2bf03..31f209e3656a 100644 --- a/sys/kern/kern_fork.c +++ b/sys/kern/kern_fork.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_fork.c,v 1.213 2019/06/13 20:20:18 kamil Exp $ */ +/* $NetBSD: kern_fork.c,v 1.214 2019/09/30 21:13:33 kamil Exp $ */ /*- * Copyright (c) 1999, 2001, 2004, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -67,7 +67,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kern_fork.c,v 1.213 2019/06/13 20:20:18 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_fork.c,v 1.214 2019/09/30 21:13:33 kamil Exp $"); #include "opt_ktrace.h" #include "opt_dtrace.h" @@ -252,7 +252,6 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, int count; vaddr_t uaddr; int tnprocs; - bool trace_fork, trace_vfork; int error = 0; p1 = l1->l_proc; @@ -511,17 +510,8 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, /* * Trace fork(2) and vfork(2)-like events on demand in a debugger. */ - trace_fork = tracefork(p1, flags); - trace_vfork = tracevfork(p1, flags); - if (trace_fork || trace_vfork) + if (tracefork(p1, flags) || tracevfork(p1, flags)) { proc_changeparent(p2, p1->p_pptr); - if (trace_fork) { - p1->p_fpid = p2->p_pid; - p2->p_fpid = p1->p_pid; - } - if (trace_vfork) { - p1->p_vfpid = p2->p_pid; - p2->p_vfpid = p1->p_pid; } LIST_INSERT_AFTER(p1, p2, p_pglist); @@ -605,7 +595,9 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, */ if (tracefork(p1, flags) || tracevfork(p1, flags)) { mutex_enter(p1->p_lock); - eventswitch(TRAP_CHLD); + eventswitch(TRAP_CHLD, + tracefork(p1, flags) ? PTRACE_FORK : PTRACE_VFORK, + retval[0]); mutex_enter(proc_lock); } @@ -621,8 +613,7 @@ fork1(struct lwp *l1, int flags, int exitsig, void *stack, size_t stacksize, */ if (tracevforkdone(p1, flags)) { mutex_enter(p1->p_lock); - p1->p_vfpid_done = retval[0]; - eventswitch(TRAP_CHLD); + eventswitch(TRAP_CHLD, PTRACE_VFORK_DONE, retval[0]); } else mutex_exit(proc_lock); @@ -645,9 +636,10 @@ child_return(void *arg) mutex_exit(proc_lock); goto my_tracer_is_gone; } - mutex_enter(p->p_lock); - eventswitch(TRAP_CHLD); + eventswitch(TRAP_CHLD, + ISSET(p->p_lflag, PL_PPWAIT) ? PTRACE_VFORK : PTRACE_FORK, + p->p_opptr->p_pid); } my_tracer_is_gone: diff --git a/sys/kern/kern_lwp.c b/sys/kern/kern_lwp.c index a7ecd53c8922..ab3a958c82f6 100644 --- a/sys/kern/kern_lwp.c +++ b/sys/kern/kern_lwp.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_lwp.c,v 1.202 2019/06/04 11:54:03 kamil Exp $ */ +/* $NetBSD: kern_lwp.c,v 1.203 2019/09/30 21:13:33 kamil Exp $ */ /*- * Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc. @@ -211,7 +211,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.202 2019/06/04 11:54:03 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.203 2019/09/30 21:13:33 kamil Exp $"); #include "opt_ddb.h" #include "opt_lockdebug.h" @@ -239,6 +239,7 @@ __KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.202 2019/06/04 11:54:03 kamil Exp $") #include #include #include +#include #include #include #include @@ -1091,8 +1092,7 @@ lwp_exit(struct lwp *l) * about a terminating LWP as it would deadlock. */ } else { - p->p_lwp_exited = l->l_lid; - eventswitch(TRAP_LWP); + eventswitch(TRAP_LWP, PTRACE_LWP_EXIT, l->l_lid); mutex_enter(proc_lock); } } diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index d2dbd6c28285..774c46f6e268 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $NetBSD: kern_sig.c,v 1.364 2019/06/21 04:28:12 kamil Exp $ */ +/* $NetBSD: kern_sig.c,v 1.365 2019/09/30 21:13:33 kamil Exp $ */ /*- * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -70,7 +70,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.364 2019/06/21 04:28:12 kamil Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.365 2019/09/30 21:13:33 kamil Exp $"); #include "opt_ptrace.h" #include "opt_dtrace.h" @@ -1560,7 +1560,7 @@ proc_stop_done(struct proc *p, int ppmask) * an event specific to a traced process only. */ void -eventswitch(int code) +eventswitch(int code, int pe_report_event, int entity) { struct lwp *l = curlwp; struct proc *p = l->l_proc; @@ -1605,8 +1605,12 @@ eventswitch(int code) KSI_INIT_TRAP(&ksi); ksi.ksi_lid = l->l_lid; - ksi.ksi_info._signo = signo; - ksi.ksi_info._code = code; + ksi.ksi_signo = signo; + ksi.ksi_code = code; + ksi.ksi_pe_report_event = pe_report_event; + + CTASSERT(sizeof(ksi.ksi_pe_other_pid) == sizeof(ksi.ksi_pe_lwp)); + ksi.ksi_pe_other_pid = entity; /* Needed for ktrace */ ps = p->p_sigacts; diff --git a/sys/kern/sys_lwp.c b/sys/kern/sys_lwp.c index a4eaec05402b..be7844bd1b86 100644 --- a/sys/kern/sys_lwp.c +++ b/sys/kern/sys_lwp.c @@ -1,4 +1,4 @@ -/* $NetBSD: sys_lwp.c,v 1.69 2019/07/10 17:52:22 maxv Exp $ */ +/* $NetBSD: sys_lwp.c,v 1.70 2019/09/30 21:13:33 kamil Exp $ */ /*- * Copyright (c) 2001, 2006, 2007, 2008 The NetBSD Foundation, Inc. @@ -35,7 +35,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v 1.69 2019/07/10 17:52:22 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v 1.70 2019/09/30 21:13:33 kamil Exp $"); #include #include @@ -45,6 +45,7 @@ __KERNEL_RCSID(0, "$NetBSD: sys_lwp.c,v 1.69 2019/07/10 17:52:22 maxv Exp $"); #include #include #include +#include #include #include #include @@ -91,8 +92,7 @@ mi_startlwp(void *arg) } mutex_enter(p->p_lock); - p->p_lwp_created = l->l_lid; - eventswitch(TRAP_LWP); + eventswitch(TRAP_LWP, PTRACE_LWP_CREATE, l->l_lid); } } diff --git a/sys/kern/sys_ptrace_common.c b/sys/kern/sys_ptrace_common.c index 163439a49e79..daad56be2d34 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.58 2019/07/18 20:10:46 kamil Exp $ */ +/* $NetBSD: sys_ptrace_common.c,v 1.59 2019/09/30 21:13:33 kamil Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -694,27 +694,25 @@ ptrace_get_process_state(struct proc *t, void *addr, size_t data) DPRINTF(("%s: %zu != %zu\n", __func__, data, sizeof(ps))); return EINVAL; } - memset(&ps, 0, sizeof(ps)); - - if (t->p_fpid) { - ps.pe_report_event = PTRACE_FORK; - ps.pe_other_pid = t->p_fpid; - } else if (t->p_vfpid) { - ps.pe_report_event = PTRACE_VFORK; - ps.pe_other_pid = t->p_vfpid; - } else if (t->p_vfpid_done) { - ps.pe_report_event = PTRACE_VFORK_DONE; - ps.pe_other_pid = t->p_vfpid_done; - } else if (t->p_lwp_created) { - ps.pe_report_event = PTRACE_LWP_CREATE; - ps.pe_lwp = t->p_lwp_created; - } 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; + + if (t->p_sigctx.ps_info._signo != SIGTRAP || + (t->p_sigctx.ps_info._code != TRAP_CHLD && + t->p_sigctx.ps_info._code != TRAP_LWP)) { + return EINVAL; } + + ps.pe_report_event = + t->p_sigctx.ps_info._reason._ptrace_state._pe_report_event; + + CTASSERT(sizeof(ps.pe_other_pid) == + sizeof(t->p_sigctx.ps_info._reason._ptrace_state._option._pe_other_pid)); + CTASSERT(sizeof(ps.pe_lwp) == + sizeof(t->p_sigctx.ps_info._reason._ptrace_state._option._pe_other_pid)); + CTASSERT(sizeof(ps.pe_other_pid) == sizeof(ps.pe_lwp)); + + ps.pe_other_pid = + t->p_sigctx.ps_info._reason._ptrace_state._option._pe_other_pid; + DPRINTF(("%s: lwp=%d event=%#x pid=%d lwp=%d\n", __func__, t->p_sigctx.ps_lwp, ps.pe_report_event, ps.pe_other_pid, ps.pe_lwp)); @@ -894,13 +892,6 @@ ptrace_sendsig(struct proc *t, struct lwp *lt, int signo, int resume_all) { ksiginfo_t ksi; - t->p_fpid = 0; - t->p_vfpid = 0; - 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) { /* diff --git a/sys/sys/siginfo.h b/sys/sys/siginfo.h index 50d82c4ac78b..d1144c52ce9e 100644 --- a/sys/sys/siginfo.h +++ b/sys/sys/siginfo.h @@ -1,4 +1,4 @@ -/* $NetBSD: siginfo.h,v 1.33 2019/05/06 08:05:03 kamil Exp $ */ +/* $NetBSD: siginfo.h,v 1.34 2019/09/30 21:13:33 kamil Exp $ */ /*- * Copyright (c) 2002 The NetBSD Foundation, Inc. @@ -84,6 +84,14 @@ struct _ksiginfo { int _error; uint64_t _args[8]; /* SYS_MAXSYSARGS */ } _syscall; + + struct { + int _pe_report_event; + union { + pid_t _pe_other_pid; + lwpid_t _pe_lwp; + } _option; + } _ptrace_state; } _reason; }; @@ -167,6 +175,10 @@ typedef union siginfo { #define si_error _info._reason._syscall._error #define si_args _info._reason._syscall._args +#define si_pe_report_event _info._reason._ptrace_state._pe_report_event +#define si_pe_other_pid _info._reason._ptrace_state._option._pe_other_pid +#define si_pe_lwp _info._reason._ptrace_state._option._pe_lwp + #ifdef _KERNEL /** Field access macros */ #define ksi_signo ksi_info._signo @@ -192,6 +204,10 @@ typedef union siginfo { #define ksi_retval ksi_info._reason._syscall._retval #define ksi_error ksi_info._reason._syscall._error #define ksi_args ksi_info._reason._syscall._args + +#define ksi_pe_report_event ksi_info._reason._ptrace_state._pe_report_event +#define ksi_pe_other_pid ksi_info._reason._ptrace_state._option._pe_other_pid +#define ksi_pe_lwp ksi_info._reason._ptrace_state._option._pe_lwp #endif /* _KERNEL */ /** si_code */ diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h index 3ea1b988f185..748429357df9 100644 --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -136,7 +136,7 @@ void killproc(struct proc *, const char *); void setsigvec(struct proc *, int, struct sigaction *); int killpg1(struct lwp *, struct ksiginfo *, int, int); void proc_unstop(struct proc *p); -void eventswitch(int); +void eventswitch(int, int, int); void sigswitch(int, int, bool);