From owner-freebsd-bugs Thu Feb 21 2:30:12 2002 Delivered-To: freebsd-bugs@hub.freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id D0B1037B402 for ; Thu, 21 Feb 2002 02:30:00 -0800 (PST) Received: (from gnats@localhost) by freefall.freebsd.org (8.11.6/8.11.6) id g1LAU0k56057; Thu, 21 Feb 2002 02:30:00 -0800 (PST) (envelope-from gnats) Received: from freefall.freebsd.org (freefall.FreeBSD.org [216.136.204.21]) by hub.freebsd.org (Postfix) with ESMTP id CE2D637B400 for ; 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 To: freebsd-gnats-submit@FreeBSD.org X-Send-Pr-Version: www-1.0 Subject: kern/35175: ptrace(PT_DETACH, ....) doesn't do signals as advertised Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk List-ID: List-Archive: (Web Archive) List-Help: (List Instructions) List-Subscribe: List-Unsubscribe: X-Loop: FreeBSD.org >Number: 35175 >Category: kern >Synopsis: ptrace(PT_DETACH, ....) doesn't do signals as advertised >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Thu Feb 21 02:30:00 PST 2002 >Closed-Date: >Last-Modified: >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: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message