diff --git a/sys/kern/kern_exit.c b/sys/kern/kern_exit.c --- a/sys/kern/kern_exit.c +++ b/sys/kern/kern_exit.c @@ -504,8 +504,9 @@ } } 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 +523,20 @@ * 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; FOREACH_THREAD_IN_PROC(q, tdt) { tdt->td_dbgflags &= ~(TDB_SUSPEND | TDB_XSIG | TDB_FSTP); } - kern_psignal(q, SIGKILL); + 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) { + ptrace_unsuspend(q); + } } PROC_UNLOCK(q); if (ksi != NULL) diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -163,6 +163,11 @@ "Fetch sigfastblock word on each syscall entry for proper " "blocking semantic"); +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"); + SYSINIT(signal, SI_SUB_P1003_1B, SI_ORDER_FIRST+3, sigqueue_start, NULL); /* diff --git a/sys/kern/sys_process.c b/sys/kern/sys_process.c --- a/sys/kern/sys_process.c +++ b/sys/kern/sys_process.c @@ -610,6 +610,19 @@ p->p_ptevents = PTRACE_DEFAULT; } +void +ptrace_unsuspend(struct proc *p) +{ + PROC_LOCK_ASSERT(p, MA_OWNED); + + PROC_SLOCK(p); + p->p_flag &= ~(P_STOPPED_TRACE | P_STOPPED_SIG | P_WAITED); + thread_unsuspend(p); + PROC_SUNLOCK(p); + itimer_proc_continue(p); + kqtimer_proc_continue(p); +} + static int proc_can_ptrace(struct thread *td, struct proc *p) { @@ -1164,12 +1177,7 @@ * suspended, use PT_SUSPEND to suspend it before * continuing the process. */ - PROC_SLOCK(p); - p->p_flag &= ~(P_STOPPED_TRACE | P_STOPPED_SIG | P_WAITED); - thread_unsuspend(p); - PROC_SUNLOCK(p); - itimer_proc_continue(p); - kqtimer_proc_continue(p); + ptrace_unsuspend(p); break; case PT_WRITE_I: diff --git a/sys/sys/ptrace.h b/sys/sys/ptrace.h --- a/sys/sys/ptrace.h +++ b/sys/sys/ptrace.h @@ -240,6 +240,9 @@ int proc_read_dbregs32(struct thread *_td, struct dbreg32 *_dbreg32); int proc_write_dbregs32(struct thread *_td, struct dbreg32 *_dbreg32); #endif + +void ptrace_unsuspend(struct proc *p); + #else /* !_KERNEL */ #include diff --git a/sys/sys/signalvar.h b/sys/sys/signalvar.h --- a/sys/sys/signalvar.h +++ b/sys/sys/signalvar.h @@ -274,6 +274,7 @@ #ifdef _KERNEL extern sigset_t fastblock_mask; extern bool sigfastblock_fetch_always; +extern int kern_kill_on_dbg_exit; /* Return nonzero if process p has an unmasked pending signal. */ #define SIGPENDING(td) \