diff options
author | Oleg Nesterov <oleg@redhat.com> | 2009-06-17 19:27:31 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-06-18 16:03:51 -0400 |
commit | b79b7ba93df14a1fc0b8d4d6d78a0e097de03bbd (patch) | |
tree | 65ce7c7335fc1dd0a91a3224466c4eaa0ec489f4 | |
parent | 5cb11446892833e50970fb2277a9f7563b0a8bd3 (diff) |
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) | |||
172 | audit_ptrace(task); | 172 | audit_ptrace(task); |
173 | 173 | ||
174 | retval = -EPERM; | 174 | retval = -EPERM; |
175 | if (unlikely(task->flags & PF_KTHREAD)) | ||
176 | goto out; | ||
175 | if (same_thread_group(task, current)) | 177 | if (same_thread_group(task, current)) |
176 | goto out; | 178 | goto out; |
177 | 179 | ||
@@ -182,8 +184,6 @@ int ptrace_attach(struct task_struct *task) | |||
182 | retval = mutex_lock_interruptible(&task->cred_guard_mutex); | 184 | retval = mutex_lock_interruptible(&task->cred_guard_mutex); |
183 | if (retval < 0) | 185 | if (retval < 0) |
184 | goto out; | 186 | goto out; |
185 | |||
186 | retval = -EPERM; | ||
187 | repeat: | 187 | repeat: |
188 | /* | 188 | /* |
189 | * Nasty, nasty. | 189 | * Nasty, nasty. |
@@ -203,23 +203,24 @@ repeat: | |||
203 | goto repeat; | 203 | goto repeat; |
204 | } | 204 | } |
205 | 205 | ||
206 | if (!task->mm) | ||
207 | goto bad; | ||
208 | /* the same process cannot be attached many times */ | ||
209 | if (task->ptrace & PT_PTRACED) | ||
210 | goto bad; | ||
211 | retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); | 206 | retval = __ptrace_may_access(task, PTRACE_MODE_ATTACH); |
212 | if (retval) | 207 | if (retval) |
213 | goto bad; | 208 | goto bad; |
214 | 209 | ||
215 | /* Go */ | 210 | retval = -EPERM; |
211 | if (unlikely(task->exit_state)) | ||
212 | goto bad; | ||
213 | if (task->ptrace & PT_PTRACED) | ||
214 | goto bad; | ||
215 | |||
216 | task->ptrace |= PT_PTRACED; | 216 | task->ptrace |= PT_PTRACED; |
217 | if (capable(CAP_SYS_PTRACE)) | 217 | if (capable(CAP_SYS_PTRACE)) |
218 | task->ptrace |= PT_PTRACE_CAP; | 218 | task->ptrace |= PT_PTRACE_CAP; |
219 | 219 | ||
220 | __ptrace_link(task, current); | 220 | __ptrace_link(task, current); |
221 | |||
222 | send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); | 221 | send_sig_info(SIGSTOP, SEND_SIG_FORCED, task); |
222 | |||
223 | retval = 0; | ||
223 | bad: | 224 | bad: |
224 | write_unlock_irqrestore(&tasklist_lock, flags); | 225 | write_unlock_irqrestore(&tasklist_lock, flags); |
225 | task_unlock(task); | 226 | task_unlock(task); |