From tijl@kalimero.kotnet.org  Mon Aug 13 15:23:32 2007
Return-Path: <tijl@kalimero.kotnet.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 1470616A419
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 13 Aug 2007 15:23:32 +0000 (UTC)
	(envelope-from tijl@kalimero.kotnet.org)
Received: from mailrelay008.isp.belgacom.be (mailrelay008.isp.belgacom.be [195.238.6.174])
	by mx1.freebsd.org (Postfix) with ESMTP id A986C13C45D
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 13 Aug 2007 15:23:31 +0000 (UTC)
	(envelope-from tijl@kalimero.kotnet.org)
Received: from 67.215-245-81.adsl-dyn.isp.belgacom.be (HELO kalimero.kotnet.org) ([81.245.215.67])
  by mailrelay008.isp.belgacom.be with ESMTP; 13 Aug 2007 17:23:25 +0200
Received: from kalimero.kotnet.org (localhost [127.0.0.1])
	by kalimero.kotnet.org (8.14.1/8.14.1) with ESMTP id l7DFNOaW004432
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 13 Aug 2007 17:23:24 +0200 (CEST)
	(envelope-from tijl@kalimero.kotnet.org)
Received: (from tijl@localhost)
	by kalimero.kotnet.org (8.14.1/8.14.1/Submit) id l7DFNORI004431;
	Mon, 13 Aug 2007 17:23:24 +0200 (CEST)
	(envelope-from tijl)
Message-Id: <200708131523.l7DFNORI004431@kalimero.kotnet.org>
Date: Mon, 13 Aug 2007 17:23:24 +0200 (CEST)
From: Tijl Coosemans <tijl@ulyssis.org>
Reply-To: Tijl Coosemans <tijl@ulyssis.org>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [patch] ptrace(2) signal delivery broken
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         115469
>Category:       kern
>Synopsis:       [kernel] [patch] ptrace(2) signal delivery broken
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Aug 13 15:30:01 GMT 2007
>Closed-Date:    Tue Oct 09 00:12:01 GMT 2007
>Last-Modified:  Tue Oct 09 00:12:01 GMT 2007
>Originator:     Tijl Coosemans
>Release:        FreeBSD 7.0-CURRENT i386
>Organization:
>Environment:
>Description:
In kern_sig.c:issignal(), when a thread receives a signal and the
process is being traced, ptracestop() is called, which suspends all
threads in the process and notifies the parent. When the threads
are resumed, ptracestop() returns td->td_xsig, the signal to be
actually delivered to the process.

Resuming the process is done by the parent calling
ptrace(PT_CONTINUE, sig) which stores sig in td->td_xsig but
currently also calls psignal(). The latter causes the signal to be
queued again and the process stops on it again when it is handled.
>How-To-Repeat:
You can hit on this problem when debugging a process that has its
own signal handlers. In that case when a signal is sent to the
process, the process stops and gdb notifies you of the signal. When
you let the process continue and deal with the signal, the signal
handler is called, but then when the process returns from the
handler, it stops again and again and again...
>Fix:
If a process is stopped ptrace should use td_xsig to deliver the
signal and otherwise (PT_ATTACH case) it should use psignal(),
which is what the following patch does.

--- patch-ptrace begins here ---
--- sys/kern/sys_process.c.orig	2007-08-02 15:53:10.000000000 +0200
+++ sys/kern/sys_process.c	2007-08-02 19:49:56.000000000 +0200
@@ -779,14 +779,15 @@
 			sx_xunlock(&proctree_lock);
 			proctree_locked = 0;
 		}
-		/* deliver or queue signal */
-		thread_lock(td2);
-		td2->td_flags &= ~TDF_XSIG;
-		thread_unlock(td2);
-		td2->td_xsig = data;
 		p->p_xstat = data;
 		p->p_xthread = NULL;
 		if ((p->p_flag & (P_STOPPED_SIG | P_STOPPED_TRACE)) != 0) {
+			/* deliver or queue signal */
+			thread_lock(td2);
+			td2->td_flags &= ~TDF_XSIG;
+			thread_unlock(td2);
+			td2->td_xsig = data;
+
 			PROC_SLOCK(p);
 			if (req == PT_DETACH) {
 				struct thread *td3;
@@ -809,11 +810,10 @@
 			p->p_flag &= ~(P_STOPPED_TRACE|P_STOPPED_SIG|P_WAITED);
 			thread_unsuspend(p);
 			PROC_SUNLOCK(p);
+		} else {
+			if (data)
+				psignal(p, data);
 		}
-
-		if (data)
-			psignal(p, data);
-
 		break;
 
 	case PT_WRITE_I:
--- patch-ptrace ends here ---
>Release-Note:
>Audit-Trail:

From: Tijl Coosemans <tijl@ulyssis.org>
To: bug-followup@freebsd.org
Cc:  
Subject: Re: kern/115469: [kernel] [patch] ptrace(2) signal delivery broken
Date: Fri, 24 Aug 2007 22:38:10 +0200

 The following session shows the problem. The sample code is
 FreeBSD/i386 specific, but it can be easily adopted to other platforms.
 
 tijl@kalimero gdbsignal% cat segv.c
 #include <sys/ucontext.h>
 #include <signal.h>
 #include <stdio.h>
 
 int sayhi = 0;
 
 void sig_handler( int sig, siginfo_t *si, void *context ) {
         ucontext_t *uctx = context;
         /* skip faulting instruction (assumed to be mov (%eax),%al) */
         uctx->uc_mcontext.mc_eip += 2;
         sayhi = 1;
 }
 
 int main( int argc, char **argv ) {
         char c;
         struct sigaction sa;
         sa.sa_sigaction = &sig_handler;
         sa.sa_flags = SA_SIGINFO;
         sigfillset( &sa.sa_mask );
         sigaction( SIGSEGV, &sa, NULL );
         c = *(( char * ) NULL );
         if( sayhi ) {
                 printf( "hello world!\n" );
         }
         return 0;
 }
 tijl@kalimero gdbsignal% cc -Wall -ggdb -O0 -march=i486 -o segv segv.c
 tijl@kalimero gdbsignal% ./segv
 hello world!
 tijl@kalimero gdbsignal% gdb segv
 GNU gdb 6.1.1 [FreeBSD]
 Copyright 2004 Free Software Foundation, Inc.
 GDB is free software, covered by the GNU General Public License, and you are
 welcome to change it and/or distribute copies of it under certain conditions.
 Type "show copying" to see the conditions.
 There is absolutely no warranty for GDB.  Type "show warranty" for details.
 This GDB was configured as "i386-marcel-freebsd"...
 (gdb) r
 Starting program: /home/tijl/tests/gdbsignal/segv
 
 Program received signal SIGSEGV, Segmentation fault.
 0x080484a9 in main () at segv.c:21
 21              c = *(( char * ) NULL );
 (gdb) c
 Continuing.
 
 Program received signal SIGSEGV, Segmentation fault.
 0x080484ab in main () at segv.c:21
 21              c = *(( char * ) NULL );
 (gdb) c
 Continuing.
 
 Program received signal SIGSEGV, Segmentation fault.
 0x080484ad in main () at segv.c:21
 21              c = *(( char * ) NULL );
 (gdb) c
 Continuing.
 
 Program received signal SIGSEGV, Segmentation fault.
 0x080484af in main () at segv.c:22
 22              if( sayhi ) {
 (gdb) c
 Continuing.
 
 Program received signal SIGSEGV, Segmentation fault.
 0x080484b1 in main () at segv.c:22
 22              if( sayhi ) {
 (gdb) and so on...
 
 
 
 With the patch the gdb session becomes:
 
 tijl@kalimero gdbsignal% gdb segv
 GNU gdb 6.1.1 [FreeBSD]
 Copyright 2004 Free Software Foundation, Inc.
 GDB is free software, covered by the GNU General Public License, and you are
 welcome to change it and/or distribute copies of it under certain conditions.
 Type "show copying" to see the conditions.
 There is absolutely no warranty for GDB.  Type "show warranty" for details.
 This GDB was configured as "i386-marcel-freebsd"...
 (gdb) r
 Starting program: /home/tijl/tests/gdbsignal/segv
 
 Program received signal SIGSEGV, Segmentation fault.
 0x080484a9 in main () at segv.c:21
 21              c = *(( char * ) NULL );
 (gdb) c
 Continuing.
 hello world!
 
 Program exited normally.
 (gdb)
 
 
 
 Since this affects debugging/devlopment in general, maybe this PR
 should get a higher priority than low.
State-Changed-From-To: open->closed 
State-Changed-By: jeff 
State-Changed-When: Tue Oct 9 00:11:29 UTC 2007 
State-Changed-Why:  
Fix committed to 7.0-CURRENT.  Thanks. 

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