From b79b7ba93df14a1fc0b8d4d6d78a0e097de03bbd Mon Sep 17 00:00:00 2001 From: Oleg Nesterov Date: Wed, 17 Jun 2009 16:27:31 -0700 Subject: [PATCH] ptrace: ptrace_attach: check PF_KTHREAD + exit_state instead of ->mm - Add PF_KTHREAD check to prevent attaching to the kernel thread with a borrowed ->mm. With or without this change we can race with daemonize() which can set PF_KTHREAD or clear ->mm after ptrace_attach() does the check, but this doesn't matter because reparent_to_kthreadd() does ptrace_unlink(). - Kill "!task->mm" check. We don't really care about ->mm != NULL, and the task can call exit_mm() right after we drop task_lock(). What we need is to make sure we can't attach after exit_notify(), check task->exit_state != 0 instead. Also, move the "already traced" check down for cosmetic reasons. Signed-off-by: Oleg Nesterov Cc: Chris Wright Acked-by: Roland McGrath Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- kernel/ptrace.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/kernel/ptrace.c b/kernel/ptrace.c index f6d8b8cb5e3..9439bd3331a 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -172,6 +172,8 @@ int ptrace_attach(struct task_struct *task) audit_ptrace(task); retval = -EPERM; + if (unlikely(task->flags & PF_KTHREAD)) + goto out; if (same_thread_group(task, current)) goto out; @@ -182,8 +184,6 @@ int ptrace_attach(struct task_struct *task) retval = mutex_lock_interruptible(&task->cred_guard_mutex); if (retval < 0) goto out; - - retval = -EPERM; repeat: /* * Nasty, nasty. @@ -203,23 +203,24 @@ repeat: goto repeat; } - if (!task->mm) - goto bad; - /* the same process cannot be attached many times */ - if (task->ptrace & PT_PTRACED) - goto bad; retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); if (retval) goto bad; - /* Go */ + retval = -EPERM; + if (unlikely(task->exit_state)) + goto bad; + if (task->ptrace & PT_PTRACED) + goto bad; + task->ptrace |= PT_PTRACED; if (capable(CAP_SYS_PTRACE)) task->ptrace |= PT_PTRACE_CAP; __ptrace_link(task, current); - send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); + + retval = 0; bad: write_unlock_irqrestore(&tasklist_lock, flags); task_unlock(task);