From: Chris Wright Date: Wed, 17 May 2006 21:55:15 +0000 (-0700) Subject: ptrace race fixes X-Git-Tag: v2.6.16.17~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=439177f95b366046b62f5d513e6e6ae6f5df8929;p=thirdparty%2Fkernel%2Fstable-queue.git ptrace race fixes --- diff --git a/queue-2.6.16/fix-ptrace_attach-ptrace_traceme-de_thread-race.patch b/queue-2.6.16/fix-ptrace_attach-ptrace_traceme-de_thread-race.patch new file mode 100644 index 00000000000..5a760ab99e2 --- /dev/null +++ b/queue-2.6.16/fix-ptrace_attach-ptrace_traceme-de_thread-race.patch @@ -0,0 +1,95 @@ +From nobody Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +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 +Signed-off-by: Chris Wright +--- + + 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; + } + + /** diff --git a/queue-2.6.16/ptrace_attach-fix-possible-deadlock-schenario-with-irqs.patch b/queue-2.6.16/ptrace_attach-fix-possible-deadlock-schenario-with-irqs.patch new file mode 100644 index 00000000000..1bb2a0f57fd --- /dev/null +++ b/queue-2.6.16/ptrace_attach-fix-possible-deadlock-schenario-with-irqs.patch @@ -0,0 +1,56 @@ +From nobody Mon Sep 17 00:00:00 2001 +From: Linus Torvalds +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 +Cc: Eric W. Biederman +Cc: Roland McGrath +Signed-off-by: Linus Torvalds +Signed-off-by: Chris Wright +--- + + 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) diff --git a/queue-2.6.16/series b/queue-2.6.16/series index 75767d8d3c0..d84b4691861 100644 --- a/queue-2.6.16/series +++ b/queue-2.6.16/series @@ -18,3 +18,5 @@ i386-x86_64-Force-pci-noacpi-on-HP-XW9300.patch remove-cond_resched-in-gather_stats.patch add-migratepage-address-space-op-to-shmem.patch page-migration-Fix-fallback-behavior-for-dirty-pages.patch +fix-ptrace_attach-ptrace_traceme-de_thread-race.patch +ptrace_attach-fix-possible-deadlock-schenario-with-irqs.patch