Author: jhb
Date: Mon Aug 15 21:10:41 2016
New Revision: 304188
URL: https://svnweb.freebsd.org/changeset/base/304188

Log:
  MFC 302900,302902,302921,303461,304009:
  Add a mask of optional ptrace() events.
  
  302900:
  Add a test for user signal delivery.
  
  This test verifies we get the correct ptrace event details when a signal
  is posted to a traced process from userland.
  
  302902:
  Add a mask of optional ptrace() events.
  
  ptrace() now stores a mask of optional events in p_ptevents.  Currently
  this mask is a single integer, but it can be expanded into an array of
  integers in the future.
  
  Two new ptrace requests can be used to manipulate the event mask:
  PT_GET_EVENT_MASK fetches the current event mask and PT_SET_EVENT_MASK
  sets the current event mask.
  
  The current set of events include:
  - PTRACE_EXEC: trace calls to execve().
  - PTRACE_SCE: trace system call entries.
  - PTRACE_SCX: trace syscam call exits.
  - PTRACE_FORK: trace forks and auto-attach to new child processes.
  - PTRACE_LWP: trace LWP events.
  
  The S_PT_SCX and S_PT_SCE events in the procfs p_stops flags have
  been replaced by PTRACE_SCE and PTRACE_SCX.  PTRACE_FORK replaces
  P_FOLLOW_FORK and PTRACE_LWP replaces P2_LWP_EVENTS.
  
  The PT_FOLLOW_FORK and PT_LWP_EVENTS ptrace requests remain for
  compatibility but now simply toggle corresponding flags in the
  event mask.
  
  While here, document that PT_SYSCALL, PT_TO_SCE, and PT_TO_SCX both
  modify the event mask and continue the traced process.
  
  302921:
  Rename PTRACE_SYSCALL to LINUX_PTRACE_SYSCALL.
  
  303461:
  Note that not all optional ptrace events use SIGTRAP.
  
  New child processes attached due to PTRACE_FORK use SIGSTOP instead of
  SIGTRAP.  All other ptrace events use SIGTRAP.
  
  304009:
  Remove description of P_FOLLOWFORK as this flag was removed.

Modified:
  stable/10/bin/ps/ps.1
  stable/10/lib/libc/sys/ptrace.2
  stable/10/sys/i386/linux/linux_ptrace.c
  stable/10/sys/kern/kern_exec.c
  stable/10/sys/kern/kern_exit.c
  stable/10/sys/kern/kern_fork.c
  stable/10/sys/kern/kern_sig.c
  stable/10/sys/kern/kern_thr.c
  stable/10/sys/kern/subr_syscall.c
  stable/10/sys/kern/sys_process.c
  stable/10/sys/sys/proc.h
  stable/10/sys/sys/ptrace.h
  stable/10/tests/sys/kern/ptrace_test.c
Directory Properties:
  stable/10/   (props changed)

Changes in other areas also in this revision:
Modified:
  stable/11/bin/ps/ps.1
  stable/11/lib/libc/sys/ptrace.2
  stable/11/sys/i386/linux/linux_ptrace.c
  stable/11/sys/kern/kern_exec.c
  stable/11/sys/kern/kern_exit.c
  stable/11/sys/kern/kern_fork.c
  stable/11/sys/kern/kern_sig.c
  stable/11/sys/kern/kern_thr.c
  stable/11/sys/kern/subr_syscall.c
  stable/11/sys/kern/sys_process.c
  stable/11/sys/sys/proc.h
  stable/11/sys/sys/ptrace.h
  stable/11/tests/sys/kern/ptrace_test.c
Directory Properties:
  stable/11/   (props changed)

Modified: stable/10/bin/ps/ps.1
==============================================================================
--- stable/10/bin/ps/ps.1       Mon Aug 15 20:38:02 2016        (r304187)
+++ stable/10/bin/ps/ps.1       Mon Aug 15 21:10:41 2016        (r304188)
@@ -29,7 +29,7 @@
 .\"     @(#)ps.1       8.3 (Berkeley) 4/18/94
 .\" $FreeBSD$
 .\"
-.Dd December 9, 2014
+.Dd August 12, 2016
 .Dt PS 1
 .Os
 .Sh NAME
@@ -310,7 +310,6 @@ the include file
 .It Dv "P_ADVLOCK" Ta No "0x00001" Ta "Process may hold a POSIX advisory lock"
 .It Dv "P_CONTROLT" Ta No "0x00002" Ta "Has a controlling terminal"
 .It Dv "P_KTHREAD" Ta No "0x00004" Ta "Kernel thread"
-.It Dv "P_FOLLOWFORK" Ta No "0x00008" Ta "Attach debugger to new children"
 .It Dv "P_PPWAIT" Ta No "0x00010" Ta "Parent is waiting for child to exec/exit"
 .It Dv "P_PROFIL" Ta No "0x00020" Ta "Has started profiling"
 .It Dv "P_STOPPROF" Ta No "0x00040" Ta "Has thread in requesting to stop prof"

Modified: stable/10/lib/libc/sys/ptrace.2
==============================================================================
--- stable/10/lib/libc/sys/ptrace.2     Mon Aug 15 20:38:02 2016        
(r304187)
+++ stable/10/lib/libc/sys/ptrace.2     Mon Aug 15 21:10:41 2016        
(r304188)
@@ -2,7 +2,7 @@
 .\"    $NetBSD: ptrace.2,v 1.2 1995/02/27 12:35:37 cgd Exp $
 .\"
 .\" This file is in the public domain.
-.Dd December 29, 2015
+.Dd July 28, 2016
 .Dt PTRACE 2
 .Os
 .Sh NAME
@@ -58,8 +58,9 @@ The signal may be a normal process signa
 traced process behavior, or use of the
 .Xr kill 2
 system call; alternatively, it may be generated by the tracing facility
-as a result of attaching, system calls, or stepping by the tracing
-process.
+as a result of attaching, stepping by the tracing
+process,
+or an event in the traced process.
 The tracing process may choose to intercept the signal, using it to
 observe process behavior (such as
 .Dv SIGTRAP ) ,
@@ -69,6 +70,121 @@ The
 system call
 is the mechanism by which all this happens.
 .Pp
+A traced process may report additional signal stops corresponding to
+events in the traced process.
+These additional signal stops are reported as
+.Dv SIGTRAP
+or
+.Dv SIGSTOP
+signals.
+The tracing process can use the
+.Dv PT_LWPINFO
+request to determine which events are associated with a
+.Dv SIGTRAP
+or
+.Dv SIGSTOP
+signal.
+Note that multiple events may be associated with a single signal.
+For example, events indicated by the
+.Dv PL_FLAG_BORN ,
+.Dv PL_FLAG_FORKED ,
+and
+.Dv PL_FLAG_EXEC
+flags are also reported as a system call exit event
+.Pq Dv PL_FLAG_SCX .
+The signal stop for a new child process enabled via
+.Dv PTRACE_FORK
+will report a
+.Dv SIGSTOP
+signal.
+All other additional signal stops use
+.Dv SIGTRAP .
+.Pp
+Each traced process has a tracing event mask.
+An event in the traced process only reports a
+signal stop if the corresponding flag is set in the tracing event mask.
+The current set of tracing event flags include:
+.Bl -tag -width ".Dv PTRACE_SYSCALL"
+.It Dv PTRACE_EXEC
+Report a stop for a successful invocation of
+.Xr execve 2 .
+This event is indicated by the
+.Dv PL_FLAG_EXEC
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SCE
+Report a stop on each system call entry.
+This event is indicated by the
+.Dv PL_FLAG_SCE
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SCX
+Report a stop on each system call exit.
+This event is indicated by the
+.Dv PL_FLAG_SCX
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+.It Dv PTRACE_SYSCALL
+Report stops for both system call entry and exit.
+.It Dv PTRACE_FORK
+This event flag controls tracing for new child processes of a traced process.
+.Pp
+When this event flag is enabled,
+new child processes will enable tracing and stop before executing their
+first instruction.
+The new child process will include the
+.Dv PL_FLAG_CHILD
+flag in the
+.Va pl_flags
+member of
+.Vt "struct ptrace_lwpinfo" .
+The traced process will report a stop that includes the
+.Dv PL_FLAG_FORKED
+flag.
+The process ID of the new child process will also be present in the
+.Va pl_child_pid
+member of
+.Vt "struct ptrace_lwpinfo" .
+Note that new child processes will be attached with the default
+tracing event mask;
+they do not inherit the event mask of the traced process.
+.Pp
+When this event flag is not enabled,
+new child processes will execute without tracing enabled.
+.It Dv PTRACE_LWP
+This event flag controls tracing of LWP
+.Pq kernel thread
+creation and destruction.
+When this event is enabled, 
+new LWPs will stop and report an event with
+.Dv PL_FLAG_BORN
+set before executing their first instruction,
+and exiting LWPs will stop and report an event with
+.Dv PL_FLAG_EXITED
+set before completing their termination.
+.Pp
+Note that new processes do not report an event for the creation of their
+initial thread,
+and exiting processes do not report an event for the termination of the
+last thread.
+.El
+.Pp
+The default tracing event mask when attaching to a process via
+.Dv PT_ATTACH ,
+.Dv PT_TRACE_ME ,
+or
+.Dv PTRACE_FORK
+includes only
+.Dv PTRACE_EXEC
+events.
+All other event flags are disabled. 
+.Pp
 The
 .Fa request
 argument specifies what operation is being performed; the meaning of
@@ -368,21 +484,20 @@ The process identifier of the new proces
 member of
 .Vt "struct ptrace_lwpinfo" .
 .It PL_FLAG_CHILD
-The flag is set for first event reported from a new child, which is
-automatically attached due to
-.Dv PT_FOLLOW_FORK
-enabled.
+The flag is set for first event reported from a new child which is
+automatically attached when
+.Dv PTRACE_FORK
+is enabled.
 .It PL_FLAG_BORN
-This flag is set for the first event reported from a new LWP when LWP
-events are enabled via
-.Dv PT_LWP_EVENTS .
+This flag is set for the first event reported from a new LWP when
+.Dv PTRACE_LWP
+is enabled.
 It is reported along with
-.Dv PL_FLAG_SCX
-and is always reported if LWP events are enabled.
+.Dv PL_FLAG_SCX .
 .It PL_FLAG_EXITED
 This flag is set for the last event reported by an exiting LWP when
-LWP events are enabled via
-.Dv PT_LWP_EVENTS .
+.Dv PTRACE_LWP
+is enabled.
 Note that this event is not reported when the last LWP in a process exits.
 The termination of the last thread is reported via a normal process exit
 event.
@@ -456,50 +571,72 @@ This request will suspend the specified 
 .It PT_RESUME
 This request will resume the specified thread.
 .It PT_TO_SCE
-This request will trace the specified process on each system call entry.
+This request will set the
+.Dv PTRACE_SCE
+event flag to trace all future system call entries and continue the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
 .It PT_TO_SCX
-This request will trace the specified process on each system call exit.
+This request will set the
+.Dv PTRACE_SCX
+event flag to trace all future system call exits and continue the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
 .It PT_SYSCALL
-This request will trace the specified process
-on each system call entry and exit.
+This request will set the
+.Dv PTRACE_SYSCALL
+event flag to trace all future system call entries and exits and continue
+the process.
+The
+.Fa addr
+and
+.Fa data
+arguments are used the same as for
+.Dv PT_CONTINUE.
 .It PT_FOLLOW_FORK
 This request controls tracing for new child processes of a traced process.
 If
 .Fa data
 is non-zero,
-then new child processes will enable tracing and stop before executing their
-first instruction.
+.Dv PTRACE_FORK
+is set in the traced process's event tracing mask.
 If
 .Fa data
-is zero, then new child processes will execute without tracing enabled.
-By default, tracing is not enabled for new child processes.
-Child processes do not inherit this property.
-The traced process will set the
-.Dv PL_FLAG_FORKED
-flag upon exit from a system call that creates a new process.
+is zero,
+.Dv PTRACE_FORK
+is cleared from the traced process's event tracing mask.
 .It PT_LWP_EVENTS
 This request controls tracing of LWP creation and destruction.
 If
 .Fa data
 is non-zero,
-then LWPs will stop to report creation and destruction events.
+.Dv PTRACE_LWP
+is set in the traced process's event tracing mask.
 If
 .Fa data
 is zero,
-then LWP creation and destruction events will not be reported.
-By default, tracing is not enabled for LWP events.
-Child processes do not inherit this property.
-New LWPs will stop to report an event with
-.Dv PL_FLAG_BORN
-set before executing their first instruction.
-Exiting LWPs will stop to report an event with
-.Dv PL_FLAG_EXITED
-set before completing their termination.
-.Pp
-Note that new processes do not report an event for the creation of their
-initial thread,
-and exiting processes do not report an event for the termination of the
-last thread.
+.Dv PTRACE_LWP
+is cleared from the traced process's event tracing mask.
+.It PT_GET_EVENT_MASK
+This request reads the traced process's event tracing mask into the
+integer pointed to by
+.Fa addr .
+The size of the integer must be passed in
+.Fa data .
+.It PT_SET_EVENT_MASK
+This request sets the traced process's event tracing mask from the
+integer pointed to by
+.Fa addr .
+The size of the integer must be passed in
+.Fa data .
 .It PT_VM_TIMESTAMP
 This request returns the generation number or timestamp of the memory map of
 the traced process as the return value from

Modified: stable/10/sys/i386/linux/linux_ptrace.c
==============================================================================
--- stable/10/sys/i386/linux/linux_ptrace.c     Mon Aug 15 20:38:02 2016        
(r304187)
+++ stable/10/sys/i386/linux/linux_ptrace.c     Mon Aug 15 21:10:41 2016        
(r304188)
@@ -69,7 +69,7 @@ __FBSDID("$FreeBSD$");
 #define PTRACE_ATTACH          16
 #define PTRACE_DETACH          17
 
-#define        PTRACE_SYSCALL          24
+#define        LINUX_PTRACE_SYSCALL    24
 
 #define PTRACE_GETREGS         12
 #define PTRACE_SETREGS         13
@@ -473,7 +473,7 @@ linux_ptrace(struct thread *td, struct l
 
                break;
        }
-       case PTRACE_SYSCALL:
+       case LINUX_PTRACE_SYSCALL:
                /* fall through */
        default:
                printf("linux: ptrace(%u, ...) not implemented\n",

Modified: stable/10/sys/kern/kern_exec.c
==============================================================================
--- stable/10/sys/kern/kern_exec.c      Mon Aug 15 20:38:02 2016        
(r304187)
+++ stable/10/sys/kern/kern_exec.c      Mon Aug 15 21:10:41 2016        
(r304188)
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/priv.h>
 #include <sys/proc.h>
 #include <sys/pioctl.h>
+#include <sys/ptrace.h>
 #include <sys/namei.h>
 #include <sys/resourcevar.h>
 #include <sys/rwlock.h>
@@ -899,7 +900,8 @@ exec_fail_dealloc:
 
        if (error == 0) {
                PROC_LOCK(p);
-               td->td_dbgflags |= TDB_EXEC;
+               if (p->p_ptevents & PTRACE_EXEC)
+                       td->td_dbgflags |= TDB_EXEC;
                PROC_UNLOCK(p);
 
                /*

Modified: stable/10/sys/kern/kern_exit.c
==============================================================================
--- stable/10/sys/kern/kern_exit.c      Mon Aug 15 20:38:02 2016        
(r304187)
+++ stable/10/sys/kern/kern_exit.c      Mon Aug 15 21:10:41 2016        
(r304188)
@@ -336,6 +336,7 @@ exit1(struct thread *td, int rv)
        rv = p->p_xstat;        /* Event handler could change exit status */
        stopprofclock(p);
        p->p_flag &= ~(P_TRACED | P_PPWAIT | P_PPTRACE);
+       p->p_ptevents = 0;
 
        /*
         * Stop the real interval timer.  If the handler is currently
@@ -519,6 +520,7 @@ exit1(struct thread *td, int rv)
                         */
                        clear_orphan(q);
                        q->p_flag &= ~(P_TRACED | P_STOPPED_TRACE);
+                       q->p_ptevents = 0;
                        FOREACH_THREAD_IN_PROC(q, tdt)
                                tdt->td_dbgflags &= ~TDB_SUSPEND;
                        kern_psignal(q, SIGKILL);

Modified: stable/10/sys/kern/kern_fork.c
==============================================================================
--- stable/10/sys/kern/kern_fork.c      Mon Aug 15 20:38:02 2016        
(r304187)
+++ stable/10/sys/kern/kern_fork.c      Mon Aug 15 21:10:41 2016        
(r304188)
@@ -411,6 +411,7 @@ do_fork(struct thread *td, int flags, st
            __rangeof(struct proc, p_startzero, p_endzero));
        p2->p_treeflag = 0;
        p2->p_filemon = NULL;
+       p2->p_ptevents = 0;
 
        /* Tell the prison that we exist. */
        prison_proc_hold(p2->p_ucred->cr_prison);
@@ -710,8 +711,7 @@ do_fork(struct thread *td, int flags, st
        if ((flags & RFMEM) == 0 && dtrace_fasttrap_fork)
                dtrace_fasttrap_fork(p1, p2);
 #endif
-       if ((p1->p_flag & (P_TRACED | P_FOLLOWFORK)) == (P_TRACED |
-           P_FOLLOWFORK)) {
+       if (p1->p_ptevents & PTRACE_FORK) {
                /*
                 * Arrange for debugger to receive the fork event.
                 *
@@ -1057,14 +1057,14 @@ fork_return(struct thread *td, struct tr
        if (td->td_dbgflags & TDB_STOPATFORK) {
                sx_xlock(&proctree_lock);
                PROC_LOCK(p);
-               if ((p->p_pptr->p_flag & (P_TRACED | P_FOLLOWFORK)) ==
-                   (P_TRACED | P_FOLLOWFORK)) {
+               if (p->p_pptr->p_ptevents & PTRACE_FORK) {
                        /*
                         * If debugger still wants auto-attach for the
                         * parent's children, do it now.
                         */
                        dbg = p->p_pptr->p_pptr;
                        p->p_flag |= P_TRACED;
+                       p->p_ptevents = PTRACE_DEFAULT;
                        p->p_oppid = p->p_pptr->p_pid;
                        CTR2(KTR_PTRACE,
                    "fork_return: attaching to new child pid %d: oppid %d",
@@ -1091,7 +1091,7 @@ fork_return(struct thread *td, struct tr
                PROC_LOCK(p);
                td->td_dbgflags |= TDB_SCX;
                _STOPEVENT(p, S_SCX, td->td_dbg_sc_code);
-               if ((p->p_stops & S_PT_SCX) != 0 ||
+               if ((p->p_ptevents & PTRACE_SCX) != 0 ||
                    (td->td_dbgflags & TDB_BORN) != 0)
                        ptracestop(td, SIGTRAP);
                td->td_dbgflags &= ~(TDB_SCX | TDB_BORN);

Modified: stable/10/sys/kern/kern_sig.c
==============================================================================
--- stable/10/sys/kern/kern_sig.c       Mon Aug 15 20:38:02 2016        
(r304187)
+++ stable/10/sys/kern/kern_sig.c       Mon Aug 15 21:10:41 2016        
(r304188)
@@ -2175,9 +2175,10 @@ tdsendsignal(struct proc *p, struct thre
            !((prop & SA_CONT) && (p->p_flag & P_STOPPED_SIG)))
                return (ret);
        /*
-        * SIGKILL: Remove procfs STOPEVENTs.
+        * SIGKILL: Remove procfs STOPEVENTs and ptrace events.
         */
        if (sig == SIGKILL) {
+               p->p_ptevents = 0;
                /* from procfs_ioctl.c: PIOCBIC */
                p->p_stops = 0;
                /* from procfs_ioctl.c: PIOCCONT */

Modified: stable/10/sys/kern/kern_thr.c
==============================================================================
--- stable/10/sys/kern/kern_thr.c       Mon Aug 15 20:38:02 2016        
(r304187)
+++ stable/10/sys/kern/kern_thr.c       Mon Aug 15 21:10:41 2016        
(r304188)
@@ -36,6 +36,7 @@ __FBSDID("$FreeBSD$");
 #include <sys/priv.h>
 #include <sys/proc.h>
 #include <sys/posix4.h>
+#include <sys/ptrace.h>
 #include <sys/racct.h>
 #include <sys/resourcevar.h>
 #include <sys/rwlock.h>
@@ -252,7 +253,7 @@ thread_create(struct thread *td, struct 
        thread_unlock(td);
        if (P_SHOULDSTOP(p))
                newtd->td_flags |= TDF_ASTPENDING | TDF_NEEDSUSPCHK;
-       if (p->p_flag2 & P2_LWP_EVENTS)
+       if (p->p_ptevents & PTRACE_LWP)
                newtd->td_dbgflags |= TDB_BORN;
        PROC_UNLOCK(p);
 
@@ -343,7 +344,7 @@ kern_thr_exit(struct thread *td)
 
        p->p_pendingexits++;
        td->td_dbgflags |= TDB_EXIT;
-       if (p->p_flag & P_TRACED && p->p_flag2 & P2_LWP_EVENTS)
+       if (p->p_ptevents & PTRACE_LWP)
                ptracestop(td, SIGTRAP);
        PROC_UNLOCK(p);
        tidhash_remove(td);

Modified: stable/10/sys/kern/subr_syscall.c
==============================================================================
--- stable/10/sys/kern/subr_syscall.c   Mon Aug 15 20:38:02 2016        
(r304187)
+++ stable/10/sys/kern/subr_syscall.c   Mon Aug 15 21:10:41 2016        
(r304188)
@@ -88,7 +88,7 @@ syscallenter(struct thread *td, struct s
                        PROC_LOCK(p);
                        td->td_dbg_sc_code = sa->code;
                        td->td_dbg_sc_narg = sa->narg;
-                       if (p->p_stops & S_PT_SCE)
+                       if (p->p_ptevents & PTRACE_SCE)
                                ptracestop((td), SIGTRAP);
                        PROC_UNLOCK(p);
                }
@@ -215,7 +215,7 @@ syscallret(struct thread *td, int error,
                 */
                if (traced &&
                    ((td->td_dbgflags & (TDB_FORK | TDB_EXEC)) != 0 ||
-                   (p->p_stops & S_PT_SCX) != 0))
+                   (p->p_ptevents & PTRACE_SCX) != 0))
                        ptracestop(td, SIGTRAP);
                td->td_dbgflags &= ~(TDB_SCX | TDB_EXEC | TDB_FORK);
                PROC_UNLOCK(p);

Modified: stable/10/sys/kern/sys_process.c
==============================================================================
--- stable/10/sys/kern/sys_process.c    Mon Aug 15 20:38:02 2016        
(r304187)
+++ stable/10/sys/kern/sys_process.c    Mon Aug 15 21:10:41 2016        
(r304188)
@@ -542,6 +542,7 @@ sys_ptrace(struct thread *td, struct ptr
                struct ptrace_lwpinfo32 pl32;
                struct ptrace_vm_entry32 pve32;
 #endif
+               int ptevents;
        } r;
        void *addr;
        int error = 0;
@@ -556,6 +557,7 @@ sys_ptrace(struct thread *td, struct ptr
        AUDIT_ARG_VALUE(uap->data);
        addr = &r;
        switch (uap->req) {
+       case PT_GET_EVENT_MASK:
        case PT_GETREGS:
        case PT_GETFPREGS:
        case PT_GETDBREGS:
@@ -570,6 +572,12 @@ sys_ptrace(struct thread *td, struct ptr
        case PT_SETDBREGS:
                error = COPYIN(uap->addr, &r.dbreg, sizeof r.dbreg);
                break;
+       case PT_SET_EVENT_MASK:
+               if (uap->data != sizeof(r.ptevents))
+                       error = EINVAL;
+               else
+                       error = copyin(uap->addr, &r.ptevents, uap->data);
+               break;
        case PT_IO:
                error = COPYIN(uap->addr, &r.piod, sizeof r.piod);
                break;
@@ -603,7 +611,12 @@ sys_ptrace(struct thread *td, struct ptr
        case PT_GETDBREGS:
                error = COPYOUT(&r.dbreg, uap->addr, sizeof r.dbreg);
                break;
+       case PT_GET_EVENT_MASK:
+               /* NB: The size in uap->data is validated in kern_ptrace(). */
+               error = copyout(&r.ptevents, uap->addr, uap->data);
+               break;
        case PT_LWPINFO:
+               /* NB: The size in uap->data is validated in kern_ptrace(). */
                error = copyout(&r.pl, uap->addr, uap->data);
                break;
        }
@@ -667,6 +680,8 @@ kern_ptrace(struct thread *td, int req, 
        case PT_SYSCALL:
        case PT_FOLLOW_FORK:
        case PT_LWP_EVENTS:
+       case PT_GET_EVENT_MASK:
+       case PT_SET_EVENT_MASK:
        case PT_DETACH:
                sx_xlock(&proctree_lock);
                proctree_locked = 1;
@@ -842,6 +857,7 @@ kern_ptrace(struct thread *td, int req, 
        case PT_TRACE_ME:
                /* set my trace flag and "owner" so it can read/write me */
                p->p_flag |= P_TRACED;
+               p->p_ptevents = PTRACE_DEFAULT;
                if (p->p_flag & P_PPWAIT)
                        p->p_flag |= P_PPTRACE;
                p->p_oppid = p->p_pptr->p_pid;
@@ -860,6 +876,7 @@ kern_ptrace(struct thread *td, int req, 
                 * on a "detach".
                 */
                p->p_flag |= P_TRACED;
+               p->p_ptevents = PTRACE_DEFAULT;
                p->p_oppid = p->p_pptr->p_pid;
                if (p->p_pptr != td->td_proc) {
                        proc_reparent(p, td->td_proc);
@@ -898,24 +915,50 @@ kern_ptrace(struct thread *td, int req, 
 
        case PT_FOLLOW_FORK:
                CTR3(KTR_PTRACE, "PT_FOLLOW_FORK: pid %d %s -> %s", p->p_pid,
-                   p->p_flag & P_FOLLOWFORK ? "enabled" : "disabled",
+                   p->p_ptevents & PTRACE_FORK ? "enabled" : "disabled",
                    data ? "enabled" : "disabled");
                if (data)
-                       p->p_flag |= P_FOLLOWFORK;
+                       p->p_ptevents |= PTRACE_FORK;
                else
-                       p->p_flag &= ~P_FOLLOWFORK;
+                       p->p_ptevents &= ~PTRACE_FORK;
                break;
 
        case PT_LWP_EVENTS:
                CTR3(KTR_PTRACE, "PT_LWP_EVENTS: pid %d %s -> %s", p->p_pid,
-                   p->p_flag2 & P2_LWP_EVENTS ? "enabled" : "disabled",
+                   p->p_ptevents & PTRACE_LWP ? "enabled" : "disabled",
                    data ? "enabled" : "disabled");
                if (data)
-                       p->p_flag2 |= P2_LWP_EVENTS;
+                       p->p_ptevents |= PTRACE_LWP;
                else
-                       p->p_flag2 &= ~P2_LWP_EVENTS;
+                       p->p_ptevents &= ~PTRACE_LWP;
+               break;
+
+       case PT_GET_EVENT_MASK:
+               if (data != sizeof(p->p_ptevents)) {
+                       error = EINVAL;
+                       break;
+               }
+               CTR2(KTR_PTRACE, "PT_GET_EVENT_MASK: pid %d mask %#x", p->p_pid,
+                   p->p_ptevents);
+               *(int *)addr = p->p_ptevents;
                break;
 
+       case PT_SET_EVENT_MASK:
+               if (data != sizeof(p->p_ptevents)) {
+                       error = EINVAL;
+                       break;
+               }
+               tmp = *(int *)addr;
+               if ((tmp & ~(PTRACE_EXEC | PTRACE_SCE | PTRACE_SCX |
+                   PTRACE_FORK | PTRACE_LWP)) != 0) {
+                       error = EINVAL;
+                       break;
+               }
+               CTR3(KTR_PTRACE, "PT_SET_EVENT_MASK: pid %d mask %#x -> %#x",
+                   p->p_pid, p->p_ptevents, tmp);
+               p->p_ptevents = tmp;
+               break;
+               
        case PT_STEP:
        case PT_CONTINUE:
        case PT_TO_SCE:
@@ -948,24 +991,24 @@ kern_ptrace(struct thread *td, int req, 
                        }
                        switch (req) {
                        case PT_TO_SCE:
-                               p->p_stops |= S_PT_SCE;
+                               p->p_ptevents |= PTRACE_SCE;
                                CTR4(KTR_PTRACE,
-                   "PT_TO_SCE: pid %d, stops = %#x, PC = %#lx, sig = %d",
-                                   p->p_pid, p->p_stops,
+                   "PT_TO_SCE: pid %d, events = %#x, PC = %#lx, sig = %d",
+                                   p->p_pid, p->p_ptevents,
                                    (u_long)(uintfptr_t)addr, data);
                                break;
                        case PT_TO_SCX:
-                               p->p_stops |= S_PT_SCX;
+                               p->p_ptevents |= PTRACE_SCX;
                                CTR4(KTR_PTRACE,
-                   "PT_TO_SCX: pid %d, stops = %#x, PC = %#lx, sig = %d",
-                                   p->p_pid, p->p_stops,
+                   "PT_TO_SCX: pid %d, events = %#x, PC = %#lx, sig = %d",
+                                   p->p_pid, p->p_ptevents,
                                    (u_long)(uintfptr_t)addr, data);
                                break;
                        case PT_SYSCALL:
-                               p->p_stops |= S_PT_SCE | S_PT_SCX;
+                               p->p_ptevents |= PTRACE_SYSCALL;
                                CTR4(KTR_PTRACE,
-                   "PT_SYSCALL: pid %d, stops = %#x, PC = %#lx, sig = %d",
-                                   p->p_pid, p->p_stops,
+                   "PT_SYSCALL: pid %d, events = %#x, PC = %#lx, sig = %d",
+                                   p->p_pid, p->p_ptevents,
                                    (u_long)(uintfptr_t)addr, data);
                                break;
                        case PT_CONTINUE:
@@ -984,7 +1027,7 @@ kern_ptrace(struct thread *td, int req, 
                         * parent.  Otherwise the debugee will be set
                         * as an orphan of the debugger.
                         */
-                       p->p_flag &= ~(P_TRACED | P_WAITED | P_FOLLOWFORK);
+                       p->p_flag &= ~(P_TRACED | P_WAITED);
                        if (p->p_oppid != p->p_pptr->p_pid) {
                                PROC_LOCK(p->p_pptr);
                                sigqueue_take(p->p_ksi);
@@ -1001,7 +1044,7 @@ kern_ptrace(struct thread *td, int req, 
                                CTR2(KTR_PTRACE, "PT_DETACH: pid %d, sig %d",
                                    p->p_pid, data);
                        p->p_oppid = 0;
-                       p->p_stops = 0;
+                       p->p_ptevents = 0;
 
                        /* should we send SIGCHLD? */
                        /* childproc_continued(p); */

Modified: stable/10/sys/sys/proc.h
==============================================================================
--- stable/10/sys/sys/proc.h    Mon Aug 15 20:38:02 2016        (r304187)
+++ stable/10/sys/sys/proc.h    Mon Aug 15 21:10:41 2016        (r304188)
@@ -611,6 +611,7 @@ struct proc {
                                               our subtree. */
        struct pgrp     *p_pgrp;        /* (c + e) Pointer to process group. */
        struct filemon  *p_filemon;     /* (c) filemon-specific data. */
+       u_int           p_ptevents;     /* (c) ptrace() event mask. */
 };
 
 #define        p_session       p_pgrp->pg_session
@@ -638,7 +639,7 @@ struct proc {
 #define        P_ADVLOCK       0x00001 /* Process may hold a POSIX advisory 
lock. */
 #define        P_CONTROLT      0x00002 /* Has a controlling terminal. */
 #define        P_KTHREAD       0x00004 /* Kernel thread (*). */
-#define        P_FOLLOWFORK    0x00008 /* Attach parent debugger to children. 
*/
+#define        P_UNUSED3       0x00008 /* --available-- */
 #define        P_PPWAIT        0x00010 /* Parent is waiting for child to 
exec/exit. */
 #define        P_PROFIL        0x00020 /* Has started profiling. */
 #define        P_STOPPROF      0x00040 /* Has thread requesting to stop 
profiling. */
@@ -677,7 +678,6 @@ struct proc {
 #define        P2_NOTRACE      0x00000002      /* No ptrace(2) attach or 
coredumps. */
 #define        P2_NOTRACE_EXEC 0x00000004      /* Keep P2_NOPTRACE on exec(2). 
*/
 #define        P2_AST_SU       0x00000008      /* Handles SU ast for kthreads. 
*/
-#define        P2_LWP_EVENTS   0x00000010      /* Report LWP events via 
ptrace(2). */
 
 /* Flags protected by proctree_lock, kept in p_treeflags. */
 #define        P_TREE_ORPHANED         0x00000001      /* Reparented, on 
orphan list */

Modified: stable/10/sys/sys/ptrace.h
==============================================================================
--- stable/10/sys/sys/ptrace.h  Mon Aug 15 20:38:02 2016        (r304187)
+++ stable/10/sys/sys/ptrace.h  Mon Aug 15 21:10:41 2016        (r304188)
@@ -66,6 +66,9 @@
 #define        PT_FOLLOW_FORK  23
 #define        PT_LWP_EVENTS   24      /* report LWP birth and exit */
 
+#define        PT_GET_EVENT_MASK 25    /* get mask of optional events */
+#define        PT_SET_EVENT_MASK 26    /* set mask of optional events */
+
 #define PT_GETREGS      33     /* get general-purpose registers */
 #define PT_SETREGS      34     /* set general-purpose registers */
 #define PT_GETFPREGS    35     /* get floating-point registers */
@@ -79,6 +82,16 @@
 #define PT_FIRSTMACH    64     /* for machine-specific requests */
 #include <machine/ptrace.h>    /* machine-specific requests, if any */
 
+/* Events used with PT_GET_EVENT_MASK and PT_SET_EVENT_MASK */
+#define        PTRACE_EXEC     0x0001
+#define        PTRACE_SCE      0x0002
+#define        PTRACE_SCX      0x0004
+#define        PTRACE_SYSCALL  (PTRACE_SCE | PTRACE_SCX)
+#define        PTRACE_FORK     0x0008
+#define        PTRACE_LWP      0x0010
+
+#define        PTRACE_DEFAULT  (PTRACE_EXEC)
+
 struct ptrace_io_desc {
        int     piod_op;        /* I/O operation */
        void    *piod_offs;     /* child offset */
@@ -136,13 +149,6 @@ struct ptrace_vm_entry {
 
 #ifdef _KERNEL
 
-/*
- * The flags below are used for ptrace(2) tracing and have no relation
- * to procfs.  They are stored in struct proc's p_stops member.
- */
-#define        S_PT_SCE        0x000010000
-#define        S_PT_SCX        0x000020000
-
 int    ptrace_set_pc(struct thread *_td, unsigned long _addr);
 int    ptrace_single_step(struct thread *_td);
 int    ptrace_clear_single_step(struct thread *_td);

Modified: stable/10/tests/sys/kern/ptrace_test.c
==============================================================================
--- stable/10/tests/sys/kern/ptrace_test.c      Mon Aug 15 20:38:02 2016        
(r304187)
+++ stable/10/tests/sys/kern/ptrace_test.c      Mon Aug 15 21:10:41 2016        
(r304188)
@@ -1269,6 +1269,200 @@ ATF_TC_BODY(ptrace__lwp_events_exec, tc)
        ATF_REQUIRE(errno == ECHILD);
 }
 
+static void
+handler(int sig __unused)
+{
+}
+
+static void
+signal_main(void)
+{
+
+       signal(SIGINFO, handler);
+       raise(SIGINFO);
+       exit(0);
+}
+
+/*
+ * Verify that the expected ptrace event is reported for a signal.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__siginfo);
+ATF_TC_BODY(ptrace__siginfo, tc)
+{
+       struct ptrace_lwpinfo pl;
+       pid_t fpid, wpid;
+       int status;
+
+       ATF_REQUIRE((fpid = fork()) != -1);
+       if (fpid == 0) {
+               trace_me();
+               signal_main();
+       }
+
+       /* The first wait() should report the stop from SIGSTOP. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(wpid == fpid);
+       ATF_REQUIRE(WIFSTOPPED(status));
+       ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+       /* The next event should be for the SIGINFO. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(WIFSTOPPED(status));
+       ATF_REQUIRE(WSTOPSIG(status) == SIGINFO);
+
+       ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+       ATF_REQUIRE(pl.pl_event == PL_EVENT_SIGNAL);
+       ATF_REQUIRE(pl.pl_flags & PL_FLAG_SI);
+       ATF_REQUIRE(pl.pl_siginfo.si_code == SI_LWP);
+       ATF_REQUIRE(pl.pl_siginfo.si_pid == wpid);
+
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+       /* The last event should be for the child process's exit. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(WIFEXITED(status));
+       ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+       wpid = wait(&status);
+       ATF_REQUIRE(wpid == -1);
+       ATF_REQUIRE(errno == ECHILD);
+}
+
+/*
+ * Verify that the expected ptrace events are reported for PTRACE_EXEC.
+ */
+ATF_TC_WITHOUT_HEAD(ptrace__ptrace_exec_disable);
+ATF_TC_BODY(ptrace__ptrace_exec_disable, tc)
+{
+       pid_t fpid, wpid;
+       int events, status;
+
+       ATF_REQUIRE((fpid = fork()) != -1);
+       if (fpid == 0) {
+               trace_me();
+               exec_thread(NULL);
+       }
+
+       /* The first wait() should report the stop from SIGSTOP. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(wpid == fpid);
+       ATF_REQUIRE(WIFSTOPPED(status));
+       ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+       events = 0;
+       ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events,
+           sizeof(events)) == 0);
+
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+       /* Should get one event at exit. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(WIFEXITED(status));
+       ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+       wpid = wait(&status);
+       ATF_REQUIRE(wpid == -1);
+       ATF_REQUIRE(errno == ECHILD);
+}
+
+ATF_TC_WITHOUT_HEAD(ptrace__ptrace_exec_enable);
+ATF_TC_BODY(ptrace__ptrace_exec_enable, tc)
+{
+       struct ptrace_lwpinfo pl;
+       pid_t fpid, wpid;
+       int events, status;
+
+       ATF_REQUIRE((fpid = fork()) != -1);
+       if (fpid == 0) {
+               trace_me();
+               exec_thread(NULL);
+       }
+
+       /* The first wait() should report the stop from SIGSTOP. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(wpid == fpid);
+       ATF_REQUIRE(WIFSTOPPED(status));
+       ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+       events = PTRACE_EXEC;
+       ATF_REQUIRE(ptrace(PT_SET_EVENT_MASK, fpid, (caddr_t)&events,
+           sizeof(events)) == 0);
+
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+       /* The next event should be for the child process's exec. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(WIFSTOPPED(status));
+       ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP);
+
+       ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1);
+       ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) ==
+           (PL_FLAG_EXEC | PL_FLAG_SCX));
+
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+       /* The last event should be for the child process's exit. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(WIFEXITED(status));
+       ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+       wpid = wait(&status);
+       ATF_REQUIRE(wpid == -1);
+       ATF_REQUIRE(errno == ECHILD);
+}
+
+ATF_TC_WITHOUT_HEAD(ptrace__event_mask);
+ATF_TC_BODY(ptrace__event_mask, tc)
+{
+       pid_t fpid, wpid;
+       int events, status;
+
+       ATF_REQUIRE((fpid = fork()) != -1);
+       if (fpid == 0) {
+               trace_me();
+               exit(0);
+       }
+
+       /* The first wait() should report the stop from SIGSTOP. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(wpid == fpid);
+       ATF_REQUIRE(WIFSTOPPED(status));
+       ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP);
+
+       /* PT_FOLLOW_FORK should toggle the state of PTRACE_FORK. */
+       ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, fpid, NULL, 1) != -1);
+       ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
+           sizeof(events)) == 0);
+       ATF_REQUIRE(events & PTRACE_FORK);
+       ATF_REQUIRE(ptrace(PT_FOLLOW_FORK, fpid, NULL, 0) != -1);
+       ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
+           sizeof(events)) == 0);
+       ATF_REQUIRE(!(events & PTRACE_FORK));
+
+       /* PT_LWP_EVENTS should toggle the state of PTRACE_LWP. */
+       ATF_REQUIRE(ptrace(PT_LWP_EVENTS, fpid, NULL, 1) != -1);
+       ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
+           sizeof(events)) == 0);
+       ATF_REQUIRE(events & PTRACE_LWP);
+       ATF_REQUIRE(ptrace(PT_LWP_EVENTS, fpid, NULL, 0) != -1);
+       ATF_REQUIRE(ptrace(PT_GET_EVENT_MASK, fpid, (caddr_t)&events,
+           sizeof(events)) == 0);
+       ATF_REQUIRE(!(events & PTRACE_LWP));
+
+       ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0);
+
+       /* Should get one event at exit. */
+       wpid = waitpid(fpid, &status, 0);
+       ATF_REQUIRE(WIFEXITED(status));
+       ATF_REQUIRE(WEXITSTATUS(status) == 0);
+
+       wpid = wait(&status);
+       ATF_REQUIRE(wpid == -1);
+       ATF_REQUIRE(errno == ECHILD);
+}
+
 ATF_TP_ADD_TCS(tp)
 {
 
@@ -1289,6 +1483,10 @@ ATF_TP_ADD_TCS(tp)
        ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_thread);
        ATF_TP_ADD_TC(tp, ptrace__lwp_events);
        ATF_TP_ADD_TC(tp, ptrace__lwp_events_exec);
+       ATF_TP_ADD_TC(tp, ptrace__siginfo);
+       ATF_TP_ADD_TC(tp, ptrace__ptrace_exec_disable);
+       ATF_TP_ADD_TC(tp, ptrace__ptrace_exec_enable);
+       ATF_TP_ADD_TC(tp, ptrace__event_mask);
 
        return (atf_no_error());
 }
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to