From: Roland McGrath 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 --- 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; _