From nobody@FreeBSD.org  Thu Feb 21 02:26:23 2002
Return-Path: <nobody@FreeBSD.org>
Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21])
	by hub.freebsd.org (Postfix) with ESMTP id CE2D637B400
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 21 Feb 2002 02:26:22 -0800 (PST)
Received: (from nobody@localhost)
	by freefall.freebsd.org (8.11.6/8.11.6) id g1LAQMl55184;
	Thu, 21 Feb 2002 02:26:22 -0800 (PST)
	(envelope-from nobody)
Message-Id: <200202211026.g1LAQMl55184@freefall.freebsd.org>
Date: Thu, 21 Feb 2002 02:26:22 -0800 (PST)
From: Peter Edwards <peter.edwards@openet-telecom.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: ptrace(PT_DETACH, ....) doesn't do signals as advertised
X-Send-Pr-Version: www-1.0

>Number:         35175
>Category:       kern
>Synopsis:       ptrace(PT_DETACH, ....) doesn't do signals as advertised
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    obrien
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Feb 21 02:30:00 PST 2002
>Closed-Date:    Sat Jun 26 05:31:33 GMT 2004
>Last-Modified:  Sat Jun 26 05:31:33 GMT 2004
>Originator:     Peter Edwards
>Release:        4.5-STABLE
>Organization:
>Environment:
FreeBSD rocklobster 4.5-STABLE FreeBSD 4.5-STABLE #21: Wed Feb 20 11:59:40 GMT 2002     petere@rocklobster:/pub/FreeBSD/work/src/sys/compile/ROCKLOBSTER  i386

>Description:
I brought this up on -hackers, but no one seemed interested. I'll preserve it here for posterity :-)
      
I noticed that PT_DETACH() isn't working as documented: The signal argument is effectively being ignored, and a combination of 
ptrace(PT_ATTACH, pid, 0, 0)
	followed by
ptrace(PT_DETACH, pid, (caddr_t)1, 0)

results in the target process getting stopped.

This seems to be less than satisfactory: I would have thought the
ptrace() call should be capable of at least attaching and detaching
from the process without causing such spurious signals to be delivered
to its victim. It also disagrees with the documentation: Even if you
attempt to send a signal on PT_DETACH, it's not sent, and the stop
still happens

This apparent mis-handling of this signal argument to ptrace() appears
to occur in issignal(): (Im discussing line numbers from kern_sig.c,
1.72.2.14)

On ptrace(PT_ATTACH, ...), the target process gets to the stop() on
line 1254, with p->p_xstat == SIGSTOP.

On ptrace(PT_DETACH, pid, (caddr_t)1, mySig), the parent kicks the
stopped child, after clearing the P_TRACE flag.

The child wakes up, with the new signal, mySig, set in p->p_xstat, and
the old signal still present in p->p_siglist from the "psignal()" call
on line 1252. It then notices that the P_TRACED flag has been switched
off, and starts all over again, discarding the new signal, and
re-finding the original SSTOP that was sent by the ptrace(PT_ATTACH)
call. ie, the process gets sent the signal that the ptrace() call 
explicitly tried to replace.

My understanding of the issues is probably incomplete, but I've
attached a patch that fixes this by moving the check for the dropping
of PT_ATTACH until after the old signal is removed and the new signal
is inserted into p->p_siglist.

>How-To-Repeat:
Write a program that calls
	ptrace(PT_ATTACH, pid, 0, 0);
and then
	ptrace(PT_DETACH, pid, (caddr_t)1, 0);

The victim, pid, will end up stopped.



>Fix:
Index: kern_sig.c
===================================================================
RCS file: /pub/FreeBSD/development/FreeBSD-CVS/src/sys/kern/kern_sig.c,v
retrieving revision 1.72.2.14
diff -u -r1.72.2.14 kern_sig.c
--- kern_sig.c  14 Dec 2001 03:05:32 -0000      1.72.2.14
+++ kern_sig.c  12 Feb 2002 09:22:52 -0000
@@ -1257,14 +1257,6 @@
                                 && p->p_flag & P_TRACED);

                        /*
-                        * If the traced bit got turned off, go back up
-                        * to the top to rescan signals.  This ensures
-                        * that p_sig* and ps_sigact are consistent.
-                        */
-                       if ((p->p_flag & P_TRACED) == 0)
-                               continue;
-
-                       /*
                         * If parent wants us to take the signal,
                         * then it will leave it in p->p_xstat;
                         * otherwise we just look for signals again.
@@ -1275,10 +1267,21 @@
                                continue;

                        /*
-                        * Put the new signal into p_siglist.  If the
-                        * signal is being masked, look for other signals.
+                        * Put the new signal into p_siglist.
                         */
                        SIGADDSET(p->p_siglist, sig);
+
+                       /*
+                        * If the traced bit got turned off, go back up
+                        * to the top to rescan signals.  This ensures
+                        * that p_sig* and ps_sigact are consistent.
+                        */
+                       if ((p->p_flag & P_TRACED) == 0)
+                               continue;
+                       /*
+                        * If the signal is being masked, look for other
+                        * signals.
+                        */
                        if (SIGISMEMBER(p->p_sigmask, sig))
                                continue;
                }
>Release-Note:
>Audit-Trail:

From: Mark Kettenis <kettenis@chello.nl>
To: freebsd-gnats-submit@FreeBSD.org
Cc: peter.edwards@openet-telecom.com
Subject: Re: kern/35175: ptrace(PT_DETACH, ...) doesn't do signals as advertised
Date: Mon, 1 Apr 2002 13:52:14 +0200 (CEST)

 I can confirm that this is a real bug.  It's easy to reproduce this
 with GDB.  Simply attach to a process, and then immediately detach.
 The process will be suspended.  Even worse, if you let the process run
 under control of GDB before the detach, it'll almost certainly die
 with a Trace/BPT trap on detaching.  Didn't notice this before since
 the part of GDB's regression testsuite that tests the attach/detach
 functionality wasn't run on FreeBSD until recently.
 
 Anyway, I agree with Peter's analysis.  Some archaeology revealed that
 the bug was already present in the 4.4-lite sources and that it has
 been fixed in NetBSD and OpenBSD several years ago.  Attached is an
 alternative patch that bright the FreeBSD code more in line with
 OpenBSD (NetBSD has diverged quite a bit since the bug was fixed).
 The patch is against 4.4-RELEASE, but I think it should apply against
 -STABLE without too much problems.  Fixing -CURRENT along the same
 lines should be doable too.  I'm certainly willing to help out there.
 
 Would be great of someone could take a look at this...  As GDB FreeBSD
 maintainer I'd really like to see this bug go.
 
 Mark
 
 
 --- /usr/src/sys/kern/kern_sig.c.orig	Fri Jul 27 16:06:01 2001
 +++ /usr/src/sys/kern/kern_sig.c	Mon Apr  1 12:59:37 2002
 @@ -1230,7 +1230,7 @@ issignal(p)
  		if (!SIGNOTEMPTY(mask))	 	/* no signal to send */
  			return (0);
  		sig = sig_ffs(&mask);
 -		prop = sigprop(sig);
 +		SIGDELSET(p->p_siglist, sig);	/* take the signal! */
  
  		STOPEVENT(p, S_SIG, sig);
  
 @@ -1238,10 +1238,9 @@ issignal(p)
  		 * We should see pending but ignored signals
  		 * only if P_TRACED was on when they were posted.
  		 */
 -		if (SIGISMEMBER(p->p_sigignore, sig) && (traced == 0)) {
 -			SIGDELSET(p->p_siglist, sig);
 +		if (SIGISMEMBER(p->p_sigignore, sig) && (traced == 0))
  			continue;
 -		}
 +
  		if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0) {
  			/*
  			 * If traced, always stop, and stay
 @@ -1256,32 +1255,24 @@ issignal(p)
  				 && p->p_flag & P_TRACED);
  
  			/*
 -			 * If the traced bit got turned off, go back up
 -			 * to the top to rescan signals.  This ensures
 -			 * that p_sig* and ps_sigact are consistent.
 +			 * If we are no longer being traced, or the parent
 +			 * didn't give us a signal, look for more signals.
  			 */
 -			if ((p->p_flag & P_TRACED) == 0)
 +			if ((p->p_flag & P_TRACED) == 0 || p->p_xstat == 0)
  				continue;
  
  			/*
 -			 * If parent wants us to take the signal,
 -			 * then it will leave it in p->p_xstat;
 -			 * otherwise we just look for signals again.
 +			 * If the new signal is being masked, look for other
 +			 * signals.
  			 */
 -			SIGDELSET(p->p_siglist, sig);	/* clear old signal */
  			sig = p->p_xstat;
 -			if (sig == 0)
 -				continue;
 -
 -			/*
 -			 * Put the new signal into p_siglist.  If the
 -			 * signal is being masked, look for other signals.
 -			 */
 -			SIGADDSET(p->p_siglist, sig);
  			if (SIGISMEMBER(p->p_sigmask, sig))
  				continue;
 +			SIGDELSET(p->p_siglist, sig);	/* take the signal! */
  		}
  
 +		prop = sigprop(sig);
 +
  		/*
  		 * Decide whether the signal should be returned.
  		 * Return the signal's number, or fall through
 @@ -1329,7 +1320,7 @@ issignal(p)
  				 */
  				break;		/* == ignore */
  			} else
 -				return (sig);
 +				goto keep;
  			/*NOTREACHED*/
  
  		case (int)SIG_IGN:
 @@ -1348,11 +1339,14 @@ issignal(p)
  			 * This signal has an action, let
  			 * postsig() process it.
  			 */
 -			return (sig);
 +			goto keep;
  		}
 -		SIGDELSET(p->p_siglist, sig);		/* take the signal! */
  	}
  	/* NOTREACHED */
 +
 +keep:
 +	SIGADDSET(p->p_siglist, sig);	/* leave the signal for later */
 +	return (sig);
  }
  
  /*

From: Mark Kettenis <kettenis@chello.nl>
To: freebsd-gnats-submit@freebsd.org
Cc: peter.edwards@openet-telecom.com
Subject: Re: kern/35175: ptrace(PT_DETACH, ...) doesn't do signals as advertised
Date: Mon, 14 Oct 2002 23:57:52 +0200 (CEST)

 I recently installed FreeBSD 5.0-CURRENT, which allowed me to create
 and test a patch against -CURRENT for the problem that Peter
 origionally reported.  Turned out that Peter's patch didn't fix all
 problems with ptrace(2).  Therefore I filed a new problem report with
 a more accurate problem description and a new patch.  It has the ID
 kern/44011.
 
 Please forget about my alternative patch here.  It's way too
 complicated and I don't think that keeping the differences with
 OpenBSD as small as possible is an important goal.
 
 Mark
Responsible-Changed-From-To: freebsd-bugs->obrien 
Responsible-Changed-By: obrien 
Responsible-Changed-When: Tue Sep 9 08:44:41 PDT 2003 
Responsible-Changed-Why:  


http://www.freebsd.org/cgi/query-pr.cgi?pr=35175 
State-Changed-From-To: open->closed 
State-Changed-By: csjp 
State-Changed-When: Sat Jun 26 05:30:40 GMT 2004 
State-Changed-Why:  
This problem was fixed with PR 44011 

http://www.freebsd.org/cgi/query-pr.cgi?pr=35175 
>Unformatted:
