summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorkamil <kamil@NetBSD.org>2019-10-09 13:19:43 +0000
committerkamil <kamil@NetBSD.org>2019-10-09 13:19:43 +0000
commitad86e77fe886efb52ae85cd797797c642fc99962 (patch)
tree319bf3a9f065a5fa432eb922468a9b6878f9c2de /sys
parent375a0006a7b6d1ef06a03dbf5de9afc1072724cb (diff)
Introduce new ptrace(2) operation PT_STOP
It works like: - kill(SIGSTOP) for unstopped tracee - ptrace(PT_CONTINUE,SIGSTOP) for stopped tracee The child will be stopped and always possible to be waited (with wait(2) like calls). For stopped traccee kill(SIGSTOP) has no effect. PT_CONTINUE+SIGSTOP cannot be used on an unstopped process (EBUSY). This operation is modeled after PT_KILL that is similar for the SIGKILL call. While there, allow PT_KILL on unstopped traced child. This operation is useful in an abnormal exit of a debugger from a signal handler, usually followed by waitpid(2) and ptrace(PT_DETACH).
Diffstat (limited to 'sys')
-rw-r--r--sys/kern/sys_ptrace_common.c48
-rw-r--r--sys/sys/ptrace.h3
2 files changed, 30 insertions, 21 deletions
diff --git a/sys/kern/sys_ptrace_common.c b/sys/kern/sys_ptrace_common.c
index 24811f9ac95..62abd746bc5 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.65 2019/10/08 12:29:57 kamil Exp $ */
+/* $NetBSD: sys_ptrace_common.c,v 1.66 2019/10/09 13:19:43 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.65 2019/10/08 12:29:57 kamil Exp $");
+__KERNEL_RCSID(0, "$NetBSD: sys_ptrace_common.c,v 1.66 2019/10/09 13:19:43 kamil Exp $");
#ifdef _KERNEL_OPT
#include "opt_ptrace.h"
@@ -286,6 +286,7 @@ ptrace_listener_cb(kauth_cred_t cred, kauth_action_t action, void *cookie,
case PT_DUMPCORE:
case PT_RESUME:
case PT_SUSPEND:
+ case PT_STOP:
result = KAUTH_RESULT_ALLOW;
break;
@@ -493,6 +494,7 @@ ptrace_allowed(struct lwp *l, int req, struct proc *t, struct proc *p,
case PT_GET_PROCESS_STATE:
case PT_RESUME:
case PT_SUSPEND:
+ case PT_STOP:
/*
* You can't do what you want to the process if:
* (1) It's not being traced at all,
@@ -511,8 +513,11 @@ ptrace_allowed(struct lwp *l, int req, struct proc *t, struct proc *p,
/*
* (3) it's not currently stopped.
+ *
+ * As an exception allow PT_KILL and PT_STOP here.
*/
- if (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */) {
+ if (req != PT_KILL && req != PT_STOP &&
+ (t->p_stat != SSTOP || !t->p_waited /* XXXSMP */)) {
DPRINTF(("stat %d flag %d\n", t->p_stat,
!t->p_waited));
return EBUSY;
@@ -540,6 +545,7 @@ ptrace_needs_hold(int req)
case PT_TRACE_ME:
case PT_GET_SIGINFO:
case PT_SET_SIGINFO:
+ case PT_STOP:
return 1;
default:
return 0;
@@ -891,7 +897,7 @@ ptrace_regs(struct lwp *l, struct lwp **lt, int rq, struct ptrace_methods *ptm,
#endif
static int
-ptrace_sendsig(struct proc *t, struct lwp *lt, int signo, int resume_all)
+ptrace_sendsig(struct lwp *l, int req, struct proc *t, struct lwp *lt, int signo, int resume_all)
{
ksiginfo_t ksi;
@@ -919,23 +925,20 @@ ptrace_sendsig(struct proc *t, struct lwp *lt, int signo, int resume_all)
return 0;
}
- KSI_INIT_EMPTY(&ksi);
- if (t->p_sigctx.ps_faked) {
- if (signo != t->p_sigctx.ps_info._signo)
- return EINVAL;
- t->p_sigctx.ps_faked = false;
- ksi.ksi_info = t->p_sigctx.ps_info;
- ksi.ksi_lid = t->p_sigctx.ps_lwp;
- } else if (signo == 0) {
- return 0;
- } else {
- ksi.ksi_signo = signo;
- }
+ KASSERT(req == PT_KILL || req == PT_STOP || req == PT_ATTACH);
+
+ KSI_INIT(&ksi);
+ ksi.ksi_signo = signo;
+ ksi.ksi_code = SI_USER;
+ ksi.ksi_pid = l->l_proc->p_pid;
+ ksi.ksi_uid = kauth_cred_geteuid(l->l_cred);
+
+ t->p_sigctx.ps_faked = false;
+
DPRINTF(("%s: pid=%d.%d signal=%d resume_all=%d\n", __func__, t->p_pid,
- t->p_sigctx.ps_lwp, signo, resume_all));
+ lt->l_lid, signo, resume_all));
- kpsignal2(t, &ksi);
- return 0;
+ return kpsignal2(t, &ksi);
}
static int
@@ -1328,7 +1331,7 @@ do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid,
CLR(lt->l_pflag, LP_SINGLESTEP);
}
sendsig:
- error = ptrace_sendsig(t, lt, signo, resume_all);
+ error = ptrace_sendsig(l, req, t, lt, signo, resume_all);
break;
case PT_SYSCALLEMU:
@@ -1361,6 +1364,11 @@ do_ptrace(struct ptrace_methods *ptm, struct lwp *l, int req, pid_t pid,
signo = SIGKILL;
goto sendsig; /* in PT_CONTINUE, above. */
+ case PT_STOP:
+ /* just send the process a STOP signal. */
+ signo = SIGSTOP;
+ goto sendsig; /* in PT_CONTINUE, above. */
+
case PT_ATTACH:
/*
* Go ahead and set the trace flag.
diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h
index fcc9f75fd68..b531fa33a4b 100644
--- a/sys/sys/ptrace.h
+++ b/sys/sys/ptrace.h
@@ -1,4 +1,4 @@
-/* $NetBSD: ptrace.h,v 1.65 2019/06/11 23:18:55 kamil Exp $ */
+/* $NetBSD: ptrace.h,v 1.66 2019/10/09 13:19:43 kamil Exp $ */
/*-
* Copyright (c) 1984, 1993
@@ -57,6 +57,7 @@
#define PT_GET_SIGINFO 20 /* get signal state, defined below */
#define PT_RESUME 21 /* allow execution of the LWP */
#define PT_SUSPEND 22 /* prevent execution of the LWP */
+#define PT_STOP 23 /* stop the child process */
#define PT_FIRSTMACH 32 /* for machine-specific requests */
#include <machine/ptrace.h> /* machine-specific requests, if any */