ptrace_attach: fix possible deadlock schenario with irqs
authorLinus Torvalds <torvalds@g5.osdl.org>
Thu, 11 May 2006 18:08:49 +0000 (11:08 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Thu, 11 May 2006 18:08:49 +0000 (11:08 -0700)
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>
kernel/ptrace.c

index b0f8da80d7d487665b2cbf9b4f34ac8b011ae64a..921c22ad16e40e898b2cdceda7db6ea13babb36f 100644 (file)
@@ -155,8 +155,26 @@ int ptrace_attach(struct task_struct *task)
        if (task->tgid == current->tgid)
                goto out;
 
-       write_lock_irq(&tasklist_lock);
+repeat:
+       /*
+        * Nasty, nasty.
+        *
+        * We want to hold both the task-lock and the
+        * tasklist_lock for writing at the same time.
+        * But that's against the rules (tasklist_lock
+        * is taken for reading by interrupts on other
+        * cpu's that may have task_lock).
+        */
        task_lock(task);
+       local_irq_disable();
+       if (!write_trylock(&tasklist_lock)) {
+               local_irq_enable();
+               task_unlock(task);
+               do {
+                       cpu_relax();
+               } while (!write_can_lock(&tasklist_lock));
+               goto repeat;
+       }
 
        /* the same process cannot be attached many times */
        if (task->ptrace & PT_PTRACED)