Subject: kern/14443: Debugged processes may not indicate exit to parent
To: None <gnats-bugs@gnats.netbsd.org>
From: None <David.Sainty@dtsp.co.nz>
List: netbsd-bugs
Date: 11/03/2001 13:14:31
>Number:         14443
>Category:       kern
>Synopsis:       Debugged processes may not indicate exit to parent
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Nov 03 05:08:00 PST 2001
>Closed-Date:
>Last-Modified:
>Originator:     David Sainty
>Release:        NetBSD 1.5Y
>Organization:
Dynamic Technology Services and Products Ltd (NZ)
>Environment:
System: NetBSD chartreuse.dave.dtsp.co.nz 1.5Y NetBSD 1.5Y (CHARTREUSE) #4: Sun Nov  4 01:22:46 NZDT 2001     dave@tequila.dave.dtsp.co.nz:/vol/tequila/userD/NetBSD-current/src/sys/arch/i386/compile/CHARTREUSE i386
Architecture: i386
Machine: i386
>Description:
	If the debugger misbehaves and fails to wait() on a debugged zombie
	before exiting, the process will be inherited by 'init' and the
	original parent will never be notified of the dead child.

>How-To-Repeat:
	% sleep 100&
	[1] 377
	gdb /bin/sleep
	(gdb) attach 377

	% ps
	20890 p3 S+   0:00.02 gdb /bin/sleep 
	% kill -9 20890

	... notice the shell never notices the dead job.  The problem is worse
	if the shell was running the dead process in the foreground (you don't
	get control back...)

	You can also repeat this using the gdb 'kill' command, that variant
	may be a gdb bug or a separate kernel bug...

>Fix:
	Here is one solution that seems reasonable.  If the process was being
	traced, instead of reparenting to 'init', it reparents back to the
	original parent.  Pretty much straight from wait4().

--- src/sys/kern/kern_exit.c.orig	Sat Jul 28 22:51:05 2001
+++ src/sys/kern/kern_exit.c	Sun Nov  4 01:22:08 2001
@@ -245,14 +245,27 @@
 		wakeup((caddr_t)initproc);
 	for (; q != 0; q = nq) {
 		nq = q->p_sibling.le_next;
-		proc_reparent(q, initproc);
+
 		/*
-		 * Traced processes are killed
-		 * since their existence means someone is screwing up.
+		 * Traced processes are killed since their existence
+		 * means someone is screwing up.  Since we reset the
+		 * trace flags the logic in wait4() will not be
+		 * triggered to reparent the process to its original
+		 * parent, so we must do this here also.
 		 */
 		if (q->p_flag & P_TRACED) {
+			if (q->p_oppid != q->p_pptr->p_pid) {
+				struct proc	*t;
+				t = pfind(q->p_oppid);
+				proc_reparent(q, t ? t : initproc);
+				q->p_oppid = 0;
+			} else {
+				proc_reparent(q, initproc);
+			}
 			q->p_flag &= ~(P_TRACED|P_WAITED|P_FSTRACE);
 			psignal(q, SIGKILL);
+		} else {
+			proc_reparent(q, initproc);
 		}
 	}
 
>Release-Note:
>Audit-Trail:
>Unformatted: