Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/sys Introduce new ptrace(2) operations: PT_SET_SIGPASS a...



details:   https://anonhg.NetBSD.org/src/rev/92299a4265bc
branches:  trunk
changeset: 932712:92299a4265bc
user:      kamil <kamil%NetBSD.org@localhost>
date:      Thu May 14 13:32:15 2020 +0000

description:
Introduce new ptrace(2) operations: PT_SET_SIGPASS and PT_GET_SIGPASS

They deliver the logic of bypassing selected signals directly to the
debuggee, without informing the debugger.

This can be used to implement the QPassSignals GDB/LLDB protocol.

This call can be useful to avoid signal races in ATF ptrace tests.

diffstat:

 lib/libc/sys/ptrace.2        |  29 +++++++++++++++++++-
 sys/kern/kern_sig.c          |  30 +++++++++++++--------
 sys/kern/sys_ptrace_common.c |  60 ++++++++++++++++++++++++++++++++++++++++++-
 sys/sys/ptrace.h             |   8 ++++-
 sys/sys/signalvar.h          |   3 +-
 5 files changed, 111 insertions(+), 19 deletions(-)

diffs (truncated from 332 to 300 lines):

diff -r d5b2926ed966 -r 92299a4265bc lib/libc/sys/ptrace.2
--- a/lib/libc/sys/ptrace.2     Thu May 14 13:25:40 2020 +0000
+++ b/lib/libc/sys/ptrace.2     Thu May 14 13:32:15 2020 +0000
@@ -1,7 +1,7 @@
-.\"    $NetBSD: ptrace.2,v 1.83 2020/01/04 04:40:17 kamil Exp $
+.\"    $NetBSD: ptrace.2,v 1.84 2020/05/14 13:32:15 kamil Exp $
 .\"
 .\" This file is in the public domain.
-.Dd January 4, 2019
+.Dd May 14, 2020
 .Dt PTRACE 2
 .Os
 .Sh NAME
@@ -623,6 +623,31 @@
 .Fa data
 argument should be set to
 .Li sizeof(struct ptrace_siginfo) .
+.It Dv PT_SET_SIGPASS
+This request can be used to specify mask of signals that should be passed
+directly to the debuggee, without reporting to the tracer.
+A pointer to sigset_t is passed in
+.Fa addr .
+The
+.Fa data
+argument should be set to
+.Li sizeof(sigset_t) .
+.Pp
+It is not permitted to mask SIGSTOP and SIGKILL.
+All debugger related signals
+(SIGTRAP, SIGILL, SIGSEGV, SIGBUS, SIGFPE)
+are reported to the tracer without interruption,
+unless they were emitted by a non-crash source.
+.It Dv PT_GET_SIGPASS
+This request can be used to determine mask of signals passed directly to the debuggee.
+A pointer to sigset_t is passed in
+.Fa addr .
+The
+.Fa data
+argument should be set to
+.Li sizeof(sigset_t) .
+.Pp
+Upon debugger attach the sigpass mask shall be empty.
 .It Dv PT_RESUME
 Allow execution of a specified thread,
 change its state from suspended to continued.
diff -r d5b2926ed966 -r 92299a4265bc sys/kern/kern_sig.c
--- a/sys/kern/kern_sig.c       Thu May 14 13:25:40 2020 +0000
+++ b/sys/kern/kern_sig.c       Thu May 14 13:32:15 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_sig.c,v 1.388 2020/05/07 20:02:34 kamil Exp $     */
+/*     $NetBSD: kern_sig.c,v 1.389 2020/05/14 13:32:15 kamil Exp $     */
 
 /*-
  * Copyright (c) 2006, 2007, 2008, 2019 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.388 2020/05/07 20:02:34 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_sig.c,v 1.389 2020/05/14 13:32:15 kamil Exp $");
 
 #include "opt_ptrace.h"
 #include "opt_dtrace.h"
@@ -1302,6 +1302,7 @@
        lwpid_t lid;
        sig_t action;
        bool toall;
+       bool traced;
        int error = 0;
 
        KASSERT(!cpu_intr_p());
@@ -1329,11 +1330,13 @@
        prop = sigprop[signo];
        toall = ((prop & SA_TOALL) != 0);
        lid = toall ? 0 : ksi->ksi_lid;
+       traced = ISSET(p->p_slflag, PSL_TRACED) &&
+           !sigismember(&p->p_sigctx.ps_sigpass, signo);
 
        /*
         * If proc is traced, always give parent a chance.
         */
-       if (p->p_slflag & PSL_TRACED) {
+       if (traced) {
                action = SIG_DFL;
 
                if (lid == 0) {
@@ -1428,7 +1431,7 @@
         * or for an SA process.
         */
        if (p->p_stat == SACTIVE && (p->p_sflag & PS_STOPPING) == 0) {
-               if ((p->p_slflag & PSL_TRACED) != 0)
+               if (traced)
                        goto deliver;
 
                /*
@@ -1444,7 +1447,7 @@
                 * - If traced, then no action is needed, unless killing.
                 * - Run the process only if sending SIGCONT or SIGKILL.
                 */
-               if ((p->p_slflag & PSL_TRACED) != 0 && signo != SIGKILL) {
+               if (traced && signo != SIGKILL) {
                        goto out;
                }
                if ((prop & SA_CONT) != 0 || signo == SIGKILL) {
@@ -1456,7 +1459,7 @@
                                p->p_pptr->p_nstopchild--;
                        p->p_stat = SACTIVE;
                        p->p_sflag &= ~PS_STOPPING;
-                       if (p->p_slflag & PSL_TRACED) {
+                       if (traced) {
                                KASSERT(signo == SIGKILL);
                                goto deliver;
                        }
@@ -1487,7 +1490,7 @@
        /*
         * Make signal pending.
         */
-       KASSERT((p->p_slflag & PSL_TRACED) == 0);
+       KASSERT(!traced);
        if ((error = sigput(&p->p_sigpend, p, kp)) != 0)
                goto out;
 deliver:
@@ -1844,6 +1847,7 @@
        int siglwp, signo, prop;
        sigpend_t *sp;
        sigset_t ss;
+       bool traced;
 
        p = l->l_proc;
        sp = NULL;
@@ -1910,6 +1914,9 @@
                        }
                }
 
+               traced = ISSET(p->p_slflag, PSL_TRACED) &&
+                   !sigismember(&p->p_sigctx.ps_sigpass, signo);
+
                if (sp) {
                        /* Overwrite process' signal context to correspond
                         * to the currently reported LWP.  This is necessary
@@ -1937,7 +1944,7 @@
                 * we are being traced.
                 */
                if (sigismember(&p->p_sigctx.ps_sigignore, signo) &&
-                   (p->p_slflag & PSL_TRACED) == 0) {
+                   !traced) {
                        /* Discard the signal. */
                        continue;
                }
@@ -1947,7 +1954,7 @@
                 * by the debugger.  If the our parent is our debugger waiting
                 * for us and we vforked, don't hang as we could deadlock.
                 */
-               if (ISSET(p->p_slflag, PSL_TRACED) && signo != SIGKILL &&
+               if (traced && signo != SIGKILL &&
                    !(ISSET(p->p_lflag, PL_PPWAIT) &&
                     (p->p_pptr == p->p_opptr))) {
                        /*
@@ -2004,7 +2011,7 @@
                                 * XXX Don't hold proc_lock for p_lflag,
                                 * but it's not a big deal.
                                 */
-                               if ((ISSET(p->p_slflag, PSL_TRACED) &&
+                               if ((traced &&
                                     !(ISSET(p->p_lflag, PL_PPWAIT) &&
                                     (p->p_pptr == p->p_opptr))) ||
                                    ((p->p_lflag & PL_ORPHANPG) != 0 &&
@@ -2035,8 +2042,7 @@
                         * to take action on an ignored signal other
                         * than SIGCONT, unless process is traced.
                         */
-                       if ((prop & SA_CONT) == 0 &&
-                           (p->p_slflag & PSL_TRACED) == 0)
+                       if ((prop & SA_CONT) == 0 && !traced)
                                printf_nolog("issignal\n");
 #endif
                        continue;
diff -r d5b2926ed966 -r 92299a4265bc sys/kern/sys_ptrace_common.c
--- a/sys/kern/sys_ptrace_common.c      Thu May 14 13:25:40 2020 +0000
+++ b/sys/kern/sys_ptrace_common.c      Thu May 14 13:32:15 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: sys_ptrace_common.c,v 1.79 2020/05/08 10:35:51 kamil Exp $     */
+/*     $NetBSD: sys_ptrace_common.c,v 1.80 2020/05/14 13:32:15 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.79 2020/05/08 10:35:51 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.80 2020/05/14 13:32:15 kamil Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ptrace.h"
@@ -290,6 +290,8 @@
        case PT_STOP:
        case PT_LWPSTATUS:
        case PT_LWPNEXT:
+       case PT_SET_SIGPASS:
+       case PT_GET_SIGPASS:
                result = KAUTH_RESULT_ALLOW;
                break;
 
@@ -500,6 +502,8 @@
        case PT_STOP:
        case PT_LWPSTATUS:
        case PT_LWPNEXT:
+       case PT_SET_SIGPASS:
+       case PT_GET_SIGPASS:
                /*
                 * You can't do what you want to the process if:
                 *      (1) It's not being traced at all,
@@ -622,6 +626,47 @@
 }
 
 static int
+ptrace_get_sigpass(struct proc *t, void *addr, size_t data)
+{
+       sigset_t set;
+
+       if (data > sizeof(set) || data <= 0) {
+               DPRINTF(("%s: invalid data: %zu < %zu <= 0\n",
+                       __func__, sizeof(set), data));
+               return EINVAL;
+       }
+
+       set = t->p_sigctx.ps_sigpass;
+
+       return copyout(&set, addr, data);
+}
+
+static int
+ptrace_set_sigpass(struct proc *t, void *addr, size_t data)
+{
+       sigset_t set;
+       int error;
+
+       if (data > sizeof(set) || data <= 0) {
+               DPRINTF(("%s: invalid data: %zu < %zu <= 0\n",
+                       __func__, sizeof(set), data));
+               return EINVAL;
+       }
+
+       memset(&set, 0, sizeof(set));
+
+       if ((error = copyin(addr, &set, data)))
+               return error;
+
+       /* We catch SIGSTOP and cannot intercept SIGKILL. */
+       sigminusset(&sigcantmask, &set);
+
+       t->p_sigctx.ps_sigpass = set;
+
+       return 0;
+}
+
+static int
 ptrace_get_event_mask(struct proc *t, void *addr, size_t data)
 {
        struct ptrace_event pe;
@@ -1395,6 +1440,9 @@
                        CLR(t->p_slflag,
                            PSL_TRACED|PSL_TRACEDCHILD|PSL_SYSCALL);
 
+                       /* clear sigpass mask */
+                       sigemptyset(&t->p_sigctx.ps_sigpass);
+
                        /* give process back to original parent or init */
                        if (t->p_opptr != t->p_pptr) {
                                struct proc *pp = t->p_opptr;
@@ -1499,6 +1547,14 @@
                error = ptrace_lwpstatus(t, ptm, &lt, addr, data, true);
                break;
 
+       case PT_SET_SIGPASS:
+               error = ptrace_set_sigpass(t, addr, data);
+               break;
+
+       case PT_GET_SIGPASS:
+               error = ptrace_get_sigpass(t, addr, data);
+               break;
+
 #ifdef PT_REGISTERS
        case_PT_SETREGS
        case_PT_GETREGS
diff -r d5b2926ed966 -r 92299a4265bc sys/sys/ptrace.h
--- a/sys/sys/ptrace.h  Thu May 14 13:25:40 2020 +0000
+++ b/sys/sys/ptrace.h  Thu May 14 13:32:15 2020 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: ptrace.h,v 1.69 2019/12/26 08:52:38 kamil Exp $        */
+/*     $NetBSD: ptrace.h,v 1.70 2020/05/14 13:32:15 kamil Exp $        */
 
 /*-
  * Copyright (c) 1984, 1993
@@ -63,6 +63,8 @@
 #define        PT_STOP                 23      /* stop the child process */
 #define        PT_LWPSTATUS            24      /* get info about the LWP */
 #define        PT_LWPNEXT              25      /* get info about next LWP */
+#define        PT_SET_SIGPASS          26      /* set signals to pass to debuggee */



Home | Main Index | Thread Index | Old Index