Commit 5ecfbae093f0c37311e89b29bfc0c9d586eace87
Committed by
Linus Torvalds
1 parent
dadac81b1b
Exists in
master
and in
4 other branches
[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>
Showing 3 changed files with 17 additions and 11 deletions Side-by-side Diff
fs/exec.c
include/linux/ptrace.h
... | ... | @@ -84,6 +84,7 @@ |
84 | 84 | extern int ptrace_writedata(struct task_struct *tsk, char __user *src, unsigned long dst, int len); |
85 | 85 | extern int ptrace_attach(struct task_struct *tsk); |
86 | 86 | extern int ptrace_detach(struct task_struct *, unsigned int); |
87 | +extern void __ptrace_detach(struct task_struct *, unsigned int); | |
87 | 88 | extern void ptrace_disable(struct task_struct *); |
88 | 89 | extern int ptrace_check_attach(struct task_struct *task, int kill); |
89 | 90 | extern int ptrace_request(struct task_struct *child, long request, long addr, long data); |
kernel/ptrace.c
... | ... | @@ -72,8 +72,8 @@ |
72 | 72 | */ |
73 | 73 | void __ptrace_unlink(task_t *child) |
74 | 74 | { |
75 | - if (!child->ptrace) | |
76 | - BUG(); | |
75 | + BUG_ON(!child->ptrace); | |
76 | + | |
77 | 77 | child->ptrace = 0; |
78 | 78 | if (!list_empty(&child->ptrace_list)) { |
79 | 79 | list_del_init(&child->ptrace_list); |
80 | 80 | |
81 | 81 | |
82 | 82 | |
... | ... | @@ -184,22 +184,27 @@ |
184 | 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 | 197 | int ptrace_detach(struct task_struct *child, unsigned int data) |
188 | 198 | { |
189 | 199 | if (!valid_signal(data)) |
190 | - return -EIO; | |
200 | + return -EIO; | |
191 | 201 | |
192 | 202 | /* Architecture-specific hardware disable .. */ |
193 | 203 | ptrace_disable(child); |
194 | 204 | |
195 | - /* .. re-parent .. */ | |
196 | - child->exit_code = data; | |
197 | - | |
198 | 205 | write_lock_irq(&tasklist_lock); |
199 | - __ptrace_unlink(child); | |
200 | - /* .. and wake it up. */ | |
201 | - if (child->exit_state != EXIT_ZOMBIE) | |
202 | - wake_up_process(child); | |
206 | + if (child->ptrace) | |
207 | + __ptrace_detach(child, data); | |
203 | 208 | write_unlock_irq(&tasklist_lock); |
204 | 209 | |
205 | 210 | return 0; |