diff options
| author | Oleg Nesterov <oleg@tv-sign.ru> | 2006-02-15 14:50:10 -0500 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-02-15 14:05:43 -0500 |
| commit | 5ecfbae093f0c37311e89b29bfc0c9d586eace87 (patch) | |
| tree | eabd0a145af64e26c900578c95175ab313828661 /kernel | |
| parent | dadac81b1b86196fcc48fb87620403c4a7174f06 (diff) | |
[PATCH] fix zap_thread's ptrace related problems
1. The tracee can go from ptrace_stop() to do_signal_stop()
after __ptrace_unlink(p).
2. It is unsafe to __ptrace_unlink(p) while p->parent may wait
for tasklist_lock in ptrace_detach().
Signed-off-by: Oleg Nesterov <oleg@tv-sign.ru>
Cc: Roland McGrath <roland@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/ptrace.c | 25 |
1 files changed, 15 insertions, 10 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c index d2cf144d0af5..d95a72c9279d 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c | |||
| @@ -72,8 +72,8 @@ void ptrace_untrace(task_t *child) | |||
| 72 | */ | 72 | */ |
| 73 | void __ptrace_unlink(task_t *child) | 73 | void __ptrace_unlink(task_t *child) |
| 74 | { | 74 | { |
| 75 | if (!child->ptrace) | 75 | BUG_ON(!child->ptrace); |
| 76 | BUG(); | 76 | |
| 77 | child->ptrace = 0; | 77 | child->ptrace = 0; |
| 78 | if (!list_empty(&child->ptrace_list)) { | 78 | if (!list_empty(&child->ptrace_list)) { |
| 79 | list_del_init(&child->ptrace_list); | 79 | list_del_init(&child->ptrace_list); |
| @@ -184,22 +184,27 @@ bad: | |||
| 184 | return retval; | 184 | return retval; |
| 185 | } | 185 | } |
| 186 | 186 | ||
| 187 | void __ptrace_detach(struct task_struct *child, unsigned int data) | ||
| 188 | { | ||
| 189 | child->exit_code = data; | ||
| 190 | /* .. re-parent .. */ | ||
| 191 | __ptrace_unlink(child); | ||
| 192 | /* .. and wake it up. */ | ||
| 193 | if (child->exit_state != EXIT_ZOMBIE) | ||
| 194 | wake_up_process(child); | ||
| 195 | } | ||
| 196 | |||
| 187 | int ptrace_detach(struct task_struct *child, unsigned int data) | 197 | int ptrace_detach(struct task_struct *child, unsigned int data) |
| 188 | { | 198 | { |
| 189 | if (!valid_signal(data)) | 199 | if (!valid_signal(data)) |
| 190 | return -EIO; | 200 | return -EIO; |
| 191 | 201 | ||
| 192 | /* Architecture-specific hardware disable .. */ | 202 | /* Architecture-specific hardware disable .. */ |
| 193 | ptrace_disable(child); | 203 | ptrace_disable(child); |
| 194 | 204 | ||
| 195 | /* .. re-parent .. */ | ||
| 196 | child->exit_code = data; | ||
| 197 | |||
| 198 | write_lock_irq(&tasklist_lock); | 205 | write_lock_irq(&tasklist_lock); |
| 199 | __ptrace_unlink(child); | 206 | if (child->ptrace) |
| 200 | /* .. and wake it up. */ | 207 | __ptrace_detach(child, data); |
| 201 | if (child->exit_state != EXIT_ZOMBIE) | ||
| 202 | wake_up_process(child); | ||
| 203 | write_unlock_irq(&tasklist_lock); | 208 | write_unlock_irq(&tasklist_lock); |
| 204 | 209 | ||
| 205 | return 0; | 210 | return 0; |
