ptrace: add an option to not kill debuggees on debugger exit

Requested by:	markj
Reviewed by:	jhb (previous version)
Tested by:	pho
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differrential revision:	https://reviews.freebsd.org/D30351
This commit is contained in:
Konstantin Belousov 2021-05-18 19:26:22 +03:00
parent d7a7ea5be6
commit fd3ac06f45
2 changed files with 46 additions and 5 deletions

View File

@ -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 May 4, 2021
.Dd May 20, 2021
.Dt PTRACE 2
.Os
.Sh NAME
@ -99,6 +99,30 @@ will report a
signal.
All other additional signal stops use
.Dv SIGTRAP .
.Sh DETACH AND TERMINATION
.Pp
Normally, exiting tracing process should wait for all pending
debugging events and then detach from all alive traced processes
before exiting using
.Dv PT_DETACH
request.
If tracing process exits without detaching, for instance due to abnormal
termination, the destiny of the traced children processes is determined
by the
.Dv kern.kill_on_debugger_exit
sysctl control.
.Pp
If the control is set to the default value 1, such traced processes
are terminated.
If set to zero, kernel implicitly detaches traced processes.
Traced processes are un-stopped if needed, and then continue the execution
without tracing.
Kernel drops any
.Dv SIGTRAP
signals queued to the traced children, which could be either generated by
not yet consumed debug events, or sent by other means, the later should
not be done anyway.
.Sh TRACING EVENTS
.Pp
Each traced process has a tracing event mask.
An event in the traced process only reports a
@ -216,6 +240,7 @@ includes only
.Dv PTRACE_EXEC
events.
All other event flags are disabled.
.Sh PTRACE REQUESTS
.Pp
The
.Fa request

View File

@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sched.h>
#include <sys/sx.h>
#include <sys/syscallsubr.h>
#include <sys/sysctl.h>
#include <sys/syslog.h>
#include <sys/ptrace.h>
#include <sys/acct.h> /* for acct_process() function prototype */
@ -99,6 +100,11 @@ dtrace_execexit_func_t dtrace_fasttrap_exit;
SDT_PROVIDER_DECLARE(proc);
SDT_PROBE_DEFINE1(proc, , , exit, "int");
static int kern_kill_on_dbg_exit = 1;
SYSCTL_INT(_kern, OID_AUTO, kill_on_debugger_exit, CTLFLAG_RWTUN,
&kern_kill_on_dbg_exit, 0,
"Kill ptraced processes when debugger exits");
struct proc *
proc_realparent(struct proc *child)
{
@ -504,8 +510,9 @@ exit1(struct thread *td, int rval, int signo)
}
} else {
/*
* Traced processes are killed since their existence
* means someone is screwing up.
* Traced processes are killed by default
* since their existence means someone is
* screwing up.
*/
t = proc_realparent(q);
if (t == p) {
@ -522,14 +529,23 @@ exit1(struct thread *td, int rval, int signo)
* orphan link for q now while q is locked.
*/
proc_clear_orphan(q);
q->p_flag &= ~(P_TRACED | P_STOPPED_TRACE);
q->p_flag &= ~P_TRACED;
q->p_flag2 &= ~P2_PTRACE_FSTP;
q->p_ptevents = 0;
p->p_xthread = NULL;
FOREACH_THREAD_IN_PROC(q, tdt) {
tdt->td_dbgflags &= ~(TDB_SUSPEND | TDB_XSIG |
TDB_FSTP);
tdt->td_xsig = 0;
}
if (kern_kill_on_dbg_exit) {
q->p_flag &= ~P_STOPPED_TRACE;
kern_psignal(q, SIGKILL);
} else if ((q->p_flag & (P_STOPPED_TRACE |
P_STOPPED_SIG)) != 0) {
sigqueue_delete_proc(q, SIGTRAP);
ptrace_unsuspend(q);
}
kern_psignal(q, SIGKILL);
}
PROC_UNLOCK(q);
if (ksi != NULL)