From: Roland McGrath <roland@redhat.com>

This makes any ptrace operation that finds the target in TASK_STOPPED state
morph it into TASK_TRACED state before doing anything.  This necessitates
reverting the last_siginfo accesses to check instead of assume last_siginfo
is set, since it's no longer impossible to be in TASK_TRACED without being
stopped in ptrace_stop (though there are no associated races to worry
about).

Signed-off-by: Andrew Morton <akpm@osdl.org>
---

 25-akpm/kernel/ptrace.c |   19 ++++++++++++++-----
 1 files changed, 14 insertions(+), 5 deletions(-)

diff -puN kernel/ptrace.c~ptrace-api-preservation kernel/ptrace.c
--- 25/kernel/ptrace.c~ptrace-api-preservation	2004-08-31 20:18:59.150506816 -0700
+++ 25-akpm/kernel/ptrace.c	2004-08-31 20:18:59.155506056 -0700
@@ -81,13 +81,20 @@ int ptrace_check_attach(struct task_stru
 	 * be changed by us so it's not changing right after this.
 	 */
 	read_lock(&tasklist_lock);
-	if ((child->ptrace & PT_PTRACED) && child->parent == current)
+	if ((child->ptrace & PT_PTRACED) && child->parent == current &&
+	    child->signal != NULL) {
 		ret = 0;
+		spin_lock_irq(&child->sighand->siglock);
+		if (child->state == TASK_STOPPED) {
+			child->state = TASK_TRACED;
+		} else if (child->state != TASK_TRACED && !kill) {
+			ret = -ESRCH;
+		}
+		spin_unlock_irq(&child->sighand->siglock);
+	}
 	read_unlock(&tasklist_lock);
 
 	if (!ret && !kill) {
-		if (child->state != TASK_TRACED)
-			return -ESRCH;
 		wait_task_inactive(child);
 	}
 
@@ -298,13 +305,15 @@ static int ptrace_setoptions(struct task
 
 static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data)
 {
-	BUG_ON(child->last_siginfo == NULL);
+	if (child->last_siginfo == NULL)
+		return -EINVAL;
 	return copy_siginfo_to_user(data, child->last_siginfo);
 }
 
 static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)
 {
-	BUG_ON(child->last_siginfo == NULL);
+	if (child->last_siginfo == NULL)
+		return -EINVAL;
 	if (copy_from_user(child->last_siginfo, data, sizeof (siginfo_t)) != 0)
 		return -EFAULT;
 	return 0;
_