Commit fad0738b authored by Roland McGrath's avatar Roland McGrath Committed by Linus Torvalds

[PATCH] ptrace userspace API preservation

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: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent cece79ae
...@@ -81,13 +81,20 @@ int ptrace_check_attach(struct task_struct *child, int kill) ...@@ -81,13 +81,20 @@ int ptrace_check_attach(struct task_struct *child, int kill)
* be changed by us so it's not changing right after this. * be changed by us so it's not changing right after this.
*/ */
read_lock(&tasklist_lock); 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; 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); read_unlock(&tasklist_lock);
if (!ret && !kill) { if (!ret && !kill) {
if (child->state != TASK_TRACED)
return -ESRCH;
wait_task_inactive(child); wait_task_inactive(child);
} }
...@@ -298,13 +305,15 @@ static int ptrace_setoptions(struct task_struct *child, long data) ...@@ -298,13 +305,15 @@ static int ptrace_setoptions(struct task_struct *child, long data)
static int ptrace_getsiginfo(struct task_struct *child, siginfo_t __user * data) 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); return copy_siginfo_to_user(data, child->last_siginfo);
} }
static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data) 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) if (copy_from_user(child->last_siginfo, data, sizeof (siginfo_t)) != 0)
return -EFAULT; return -EFAULT;
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment