aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/ptrace.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-05-11 14:08:49 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-05-11 14:08:49 -0400
commitf358166a9405e4f1d8e50d8f415c26d95505b6de (patch)
tree7f5349d9e8b59633b9f8a7bd9bcd45ace1d21a41 /kernel/ptrace.c
parent0e44dc383787b472a7f13564c6bd8a44cc07d408 (diff)
ptrace_attach: fix possible deadlock schenario with irqs
Eric Biederman points out that we can't take the task_lock while holding tasklist_lock for writing, because another CPU that holds the task lock might take an interrupt that then tries to take tasklist_lock for writing. Which would be a nasty deadlock, with one CPU spinning forever in an interrupt handler (although admittedly you need to really work at triggering it ;) Since the ptrace_attach() code is special and very unusual, just make it be extra careful, and use trylock+repeat to avoid the possible deadlock. Cc: Oleg Nesterov <oleg@tv-sign.ru> Cc: Eric W. Biederman <ebiederm@xmission.com> Cc: Roland McGrath <roland@redhat.com> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'kernel/ptrace.c')
-rw-r--r--kernel/ptrace.c20
1 files changed, 19 insertions, 1 deletions
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index b0f8da80d7d4..921c22ad16e4 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -155,8 +155,26 @@ int ptrace_attach(struct task_struct *task)
155 if (task->tgid == current->tgid) 155 if (task->tgid == current->tgid)
156 goto out; 156 goto out;
157 157
158 write_lock_irq(&tasklist_lock); 158repeat:
159 /*
160 * Nasty, nasty.
161 *
162 * We want to hold both the task-lock and the
163 * tasklist_lock for writing at the same time.
164 * But that's against the rules (tasklist_lock
165 * is taken for reading by interrupts on other
166 * cpu's that may have task_lock).
167 */
159 task_lock(task); 168 task_lock(task);
169 local_irq_disable();
170 if (!write_trylock(&tasklist_lock)) {
171 local_irq_enable();
172 task_unlock(task);
173 do {
174 cpu_relax();
175 } while (!write_can_lock(&tasklist_lock));
176 goto repeat;
177 }
160 178
161 /* the same process cannot be attached many times */ 179 /* the same process cannot be attached many times */
162 if (task->ptrace & PT_PTRACED) 180 if (task->ptrace & PT_PTRACED)