diff options
author | Oleg Nesterov <oleg@redhat.com> | 2009-06-18 01:27:31 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-18 22:03:51 +0200 |
commit | b79b7ba93df14a1fc0b8d4d6d78a0e097de03bbd (patch) | |
tree | 65ce7c7335fc1dd0a91a3224466c4eaa0ec489f4 | |
parent | ptrace: do not use task->ptrace directly in core kernel (diff) | |
download | linux-b79b7ba93df14a1fc0b8d4d6d78a0e097de03bbd.tar.xz linux-b79b7ba93df14a1fc0b8d4d6d78a0e097de03bbd.zip |
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 <oleg@redhat.com>
Cc: Chris Wright <chrisw@sous-sol.org>
Acked-by: Roland McGrath <roland@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | kernel/ptrace.c | 19 |
1 files changed, 10 insertions, 9 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index f6d8b8cb5e34..9439bd3331a6 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); |