--- /dev/null
+From nobody Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@g5.osdl.org>
+Date: Sun May 7 10:49:33 2006 -0700
+Subject: [PATCH] Fix ptrace_attach()/ptrace_traceme()/de_thread() race
+
+This holds the task lock (and, for ptrace_attach, the tasklist_lock)
+over the actual attach event, which closes a race between attacking to a
+thread that is either doing a PTRACE_TRACEME or getting de-threaded.
+
+Thanks to Oleg Nesterov for reminding me about this, and Chris Wright
+for noticing a lost return value in my first version.
+
+Signed-off-by: Linus Torvalds <torvalds@osdl.org>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+
+ kernel/ptrace.c | 39 +++++++++++++++++++++------------------
+ 1 file changed, 21 insertions(+), 18 deletions(-)
+
+--- linux-2.6.16.16.orig/kernel/ptrace.c
++++ linux-2.6.16.16/kernel/ptrace.c
+@@ -149,12 +149,16 @@ int ptrace_may_attach(struct task_struct
+ int ptrace_attach(struct task_struct *task)
+ {
+ int retval;
+- task_lock(task);
++
+ retval = -EPERM;
+ if (task->pid <= 1)
+- goto bad;
++ goto out;
+ if (task->tgid == current->tgid)
+- goto bad;
++ goto out;
++
++ write_lock_irq(&tasklist_lock);
++ task_lock(task);
++
+ /* the same process cannot be attached many times */
+ if (task->ptrace & PT_PTRACED)
+ goto bad;
+@@ -167,17 +171,15 @@ int ptrace_attach(struct task_struct *ta
+ ? PT_ATTACHED : 0);
+ if (capable(CAP_SYS_PTRACE))
+ task->ptrace |= PT_PTRACE_CAP;
+- task_unlock(task);
+
+- write_lock_irq(&tasklist_lock);
+ __ptrace_link(task, current);
+- write_unlock_irq(&tasklist_lock);
+
+ force_sig_specific(SIGSTOP, task);
+- return 0;
+
+ bad:
++ write_unlock_irq(&tasklist_lock);
+ task_unlock(task);
++out:
+ return retval;
+ }
+
+@@ -418,21 +420,22 @@ int ptrace_request(struct task_struct *c
+ */
+ int ptrace_traceme(void)
+ {
+- int ret;
++ int ret = -EPERM;
+
+ /*
+ * Are we already being traced?
+ */
+- if (current->ptrace & PT_PTRACED)
+- return -EPERM;
+- ret = security_ptrace(current->parent, current);
+- if (ret)
+- return -EPERM;
+- /*
+- * Set the ptrace bit in the process ptrace flags.
+- */
+- current->ptrace |= PT_PTRACED;
+- return 0;
++ task_lock(current);
++ if (!(current->ptrace & PT_PTRACED)) {
++ ret = security_ptrace(current->parent, current);
++ /*
++ * Set the ptrace bit in the process ptrace flags.
++ */
++ if (!ret)
++ current->ptrace |= PT_PTRACED;
++ }
++ task_unlock(current);
++ return ret;
+ }
+
+ /**
--- /dev/null
+From nobody Mon Sep 17 00:00:00 2001
+From: Linus Torvalds <torvalds@g5.osdl.org>
+Date: Thu May 11 11:08:49 2006 -0700
+Subject: [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 <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)