From: Linus Torvalds Date: Thu, 11 May 2006 18:08:49 +0000 (-0700) Subject: [PATCH] ptrace_attach: fix possible deadlock schenario with irqs X-Git-Tag: v2.6.16.17~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f91962f90eb89684ecbfb3f6b8578b3ebd6937df;p=thirdparty%2Fkernel%2Fstable.git [PATCH] 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 Cc: Eric W. Biederman Cc: Roland McGrath Signed-off-by: Linus Torvalds Signed-off-by: Chris Wright Signed-off-by: Greg Kroah-Hartman --- diff --git a/kernel/ptrace.c b/kernel/ptrace.c index 99f9fa4550c7e..48453c358dfd3 100644 --- a/kernel/ptrace.c +++ b/kernel/ptrace.c @@ -156,8 +156,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)