Commit c04f9ab5 authored by Prasanna Meda's avatar Prasanna Meda Committed by Linus Torvalds

[PATCH] ptrace: last_siginfo also needs tasklist_lock

Looks like we fixed only part of the problem earlier.  When the child moves
away from ptrace notify and resets the last_siginfo, sighand lock helps.
But if the child goes further in exit and releases the sighand, we need to
test that case too.  See ptrace_check_attach() and exit_sighand().  They
also use the tasklist_lock.

Followed Roland's suggestions on lock primitive and struct assignment.
Signed-Off-by: default avatarPrasanna Meda <pmeda@akamai.com>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 9011847b
...@@ -320,32 +320,44 @@ static int ptrace_setoptions(struct task_struct *child, long data) ...@@ -320,32 +320,44 @@ 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)
{ {
siginfo_t lastinfo; siginfo_t lastinfo;
int error = -ESRCH;
spin_lock_irq(&child->sighand->siglock); read_lock(&tasklist_lock);
if (likely(child->last_siginfo != NULL)) { if (likely(child->sighand != NULL)) {
memcpy(&lastinfo, child->last_siginfo, sizeof (siginfo_t)); error = -EINVAL;
spin_lock_irq(&child->sighand->siglock);
if (likely(child->last_siginfo != NULL)) {
lastinfo = *child->last_siginfo;
error = 0;
}
spin_unlock_irq(&child->sighand->siglock); spin_unlock_irq(&child->sighand->siglock);
return copy_siginfo_to_user(data, &lastinfo);
} }
spin_unlock_irq(&child->sighand->siglock); read_unlock(&tasklist_lock);
return -EINVAL; if (!error)
return copy_siginfo_to_user(data, &lastinfo);
return error;
} }
static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data) static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)
{ {
siginfo_t newinfo; siginfo_t newinfo;
int error = -ESRCH;
if (copy_from_user(&newinfo, data, sizeof (siginfo_t)) != 0) if (copy_from_user(&newinfo, data, sizeof (siginfo_t)))
return -EFAULT; return -EFAULT;
spin_lock_irq(&child->sighand->siglock); read_lock(&tasklist_lock);
if (likely(child->last_siginfo != NULL)) { if (likely(child->sighand != NULL)) {
memcpy(child->last_siginfo, &newinfo, sizeof (siginfo_t)); error = -EINVAL;
spin_lock_irq(&child->sighand->siglock);
if (likely(child->last_siginfo != NULL)) {
*child->last_siginfo = newinfo;
error = 0;
}
spin_unlock_irq(&child->sighand->siglock); spin_unlock_irq(&child->sighand->siglock);
return 0;
} }
spin_unlock_irq(&child->sighand->siglock); read_unlock(&tasklist_lock);
return -EINVAL; return error;
} }
int ptrace_request(struct task_struct *child, long request, int ptrace_request(struct task_struct *child, long request,
......
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