From: Prasanna Meda 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 Signed-off-by: Andrew Morton --- 25-akpm/kernel/ptrace.c | 38 +++++++++++++++++++++++++------------- 1 files changed, 25 insertions(+), 13 deletions(-) diff -puN kernel/ptrace.c~ptracelast_siginfo-also-needs-tasklist_lock kernel/ptrace.c --- 25/kernel/ptrace.c~ptracelast_siginfo-also-needs-tasklist_lock Thu Jan 27 13:41:00 2005 +++ 25-akpm/kernel/ptrace.c Thu Jan 27 13:41:00 2005 @@ -320,32 +320,44 @@ static int ptrace_setoptions(struct task 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, _