Properly reparent traced processes when the tracer dies.

Previously they were uncoditionally reparented to init. In effect
it was possible that tracee was never returned to original parent.

Reviewed by:	kib
MFC after:	1 week
This commit is contained in:
mjg 2014-08-24 09:02:16 +00:00
parent 79d2bf4036
commit eda187d10a

View File

@ -156,7 +156,8 @@ sys_sys_exit(struct thread *td, struct sys_exit_args *uap)
void
exit1(struct thread *td, int rv)
{
struct proc *p, *nq, *q;
struct proc *p, *nq, *q, *t;
struct thread *tdt;
struct vnode *ttyvp = NULL;
mtx_assert(&Giant, MA_NOTOWNED);
@ -437,7 +438,9 @@ exit1(struct thread *td, int rv)
WITNESS_WARN(WARN_PANIC, NULL, "process (pid %d) exiting", p->p_pid);
/*
* Reparent all of our children to init.
* Reparent all children processes:
* - traced ones to the original parent (or init if we are that parent)
* - the rest to init
*/
sx_xlock(&proctree_lock);
q = LIST_FIRST(&p->p_children);
@ -446,15 +449,23 @@ exit1(struct thread *td, int rv)
for (; q != NULL; q = nq) {
nq = LIST_NEXT(q, p_sibling);
PROC_LOCK(q);
proc_reparent(q, initproc);
q->p_sigparent = SIGCHLD;
/*
* Traced processes are killed
* since their existence means someone is screwing up.
*/
if (q->p_flag & P_TRACED) {
struct thread *temp;
if (!(q->p_flag & P_TRACED)) {
proc_reparent(q, initproc);
} else {
/*
* Traced processes are killed since their existence
* means someone is screwing up.
*/
t = proc_realparent(q);
if (t == p) {
proc_reparent(q, initproc);
} else {
PROC_LOCK(t);
proc_reparent(q, t);
PROC_UNLOCK(t);
}
/*
* Since q was found on our children list, the
* proc_reparent() call moved q to the orphan
@ -463,8 +474,8 @@ exit1(struct thread *td, int rv)
*/
clear_orphan(q);
q->p_flag &= ~(P_TRACED | P_STOPPED_TRACE);
FOREACH_THREAD_IN_PROC(q, temp)
temp->td_dbgflags &= ~TDB_SUSPEND;
FOREACH_THREAD_IN_PROC(q, tdt)
tdt->td_dbgflags &= ~TDB_SUSPEND;
kern_psignal(q, SIGKILL);
}
PROC_UNLOCK(q);