Re: [PATCH] cleanup ptrace stops and remove notify_parent

From: Roland McGrath
Date: Tue Aug 31 2004 - 20:57:36 EST


I don't have a program like yours to test that it was broken with my patch
(now in 2.6.9-rc1-mm2). But the following additional patch relative to
2.6.9-rc1-mm2 should do it. I've tested that it doesn't create any new
problems. I don't have something right handy that tests the case in
question, but you've said that you do.

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).


Thanks,
Roland

--- linux-2.6.9-rc1-mm2/kernel/ptrace.c.~1~ 2004-08-31 18:18:10.000000000 -0700
+++ linux-2.6.9-rc1-mm2/kernel/ptrace.c 2004-08-31 18:51:46.922556896 -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;
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/