[PATCH 22/22] [PATCH] ptrace_attach: fix possible deadlock schenario with irqs

Chris Wright
2006-05-17T22:18:16Z

[-- Attachment #1: ptrace_attach-fix-possible-deadlock-schenario-with-irqs.patch --]
[-- Type: text/plain, Size: 1748 bytes --]

-stable review patch. If anyone has any objections, please let us know.
------------------

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>
Signed-off-by: Chris Wright <chrisw@sous-sol.org>
---

kernel/ptrace.c | 20 +++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)

--- linux-2.6.16.16.orig/kernel/ptrace.c
+++ linux-2.6.16.16/kernel/ptrace.c
@@ -156,8 +156,26 @@ int ptrace_attach(struct task_struct *ta
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)

--