summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorPrasanna Meda <pmeda@akamai.com>2005-02-01 16:29:45 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-02-01 16:29:45 -0800
commitc04f9ab59c7c2831af922b949bf3dfa0a5a93c0b (patch)
tree1548658dfd72439dd0c4031753b8fb286716e867 /kernel
parent9011847b6d4738ec28d1b549ecc5ca5169065cae (diff)
[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: Prasanna Meda <pmeda@akamai.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/ptrace.c38
1 files changed, 25 insertions, 13 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 136a8feba91e..88b306c4e841 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -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)
{
siginfo_t lastinfo;
+ int error = -ESRCH;
- spin_lock_irq(&child->sighand->siglock);
- if (likely(child->last_siginfo != NULL)) {
- memcpy(&lastinfo, child->last_siginfo, sizeof (siginfo_t));
+ read_lock(&tasklist_lock);
+ if (likely(child->sighand != NULL)) {
+ 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);
- return copy_siginfo_to_user(data, &lastinfo);
}
- spin_unlock_irq(&child->sighand->siglock);
- return -EINVAL;
+ read_unlock(&tasklist_lock);
+ if (!error)
+ return copy_siginfo_to_user(data, &lastinfo);
+ return error;
}
static int ptrace_setsiginfo(struct task_struct *child, siginfo_t __user * data)
{
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;
- spin_lock_irq(&child->sighand->siglock);
- if (likely(child->last_siginfo != NULL)) {
- memcpy(child->last_siginfo, &newinfo, sizeof (siginfo_t));
+ read_lock(&tasklist_lock);
+ if (likely(child->sighand != NULL)) {
+ 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);
- return 0;
}
- spin_unlock_irq(&child->sighand->siglock);
- return -EINVAL;
+ read_unlock(&tasklist_lock);
+ return error;
}
int ptrace_request(struct task_struct *child, long request,