diff options
| author | kamil <kamil@NetBSD.org> | 2019-10-09 13:19:43 +0000 |
|---|---|---|
| committer | kamil <kamil@NetBSD.org> | 2019-10-09 13:19:43 +0000 |
| commit | ad86e77fe886efb52ae85cd797797c642fc99962 (patch) | |
| tree | 319bf3a9f065a5fa432eb922468a9b6878f9c2de /sys | |
| parent | 375a0006a7b6d1ef06a03dbf5de9afc1072724cb (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.c | 48 | ||||
| -rw-r--r-- | sys/sys/ptrace.h | 3 |
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 */ |
