[POWERPC] Harden validate_sp against stack corruption
authorPaul Mackerras <paulus@samba.org>
Mon, 19 Feb 2007 00:42:42 +0000 (11:42 +1100)
committerPaul Mackerras <paulus@samba.org>
Thu, 8 Mar 2007 04:31:43 +0000 (15:31 +1100)
If something has overflowed or corrupted the stack and causes an oops,
and we try to print a stack trace, that will call validate_sp, which
can itself cause an oops if the cpu field of the thread_info struct at
the bottom of the stack has been corrupted (if CONFIG_IRQSTACKS is
set).  This makes debugging harder.

To avoid the second oops, this adds a check to make sure that the cpu
number is reasonable before using it to check whether the stack is on
the softirq or hardirq stack.

Signed-off-by: Paul Mackerras <paulus@samba.org>
arch/powerpc/kernel/process.c

index f3d4dd580dd69fe20a04dd4762866ad0f82d51ea..972b2acbe713079c285bfdca796e9502dc2a8b60 100644 (file)
@@ -818,6 +818,35 @@ out:
        return error;
 }
 
+#ifdef CONFIG_IRQSTACKS
+static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
+                                 unsigned long nbytes)
+{
+       unsigned long stack_page;
+       unsigned long cpu = task_cpu(p);
+
+       /*
+        * Avoid crashing if the stack has overflowed and corrupted
+        * task_cpu(p), which is in the thread_info struct.
+        */
+       if (cpu < NR_CPUS && cpu_possible(cpu)) {
+               stack_page = (unsigned long) hardirq_ctx[cpu];
+               if (sp >= stack_page + sizeof(struct thread_struct)
+                   && sp <= stack_page + THREAD_SIZE - nbytes)
+                       return 1;
+
+               stack_page = (unsigned long) softirq_ctx[cpu];
+               if (sp >= stack_page + sizeof(struct thread_struct)
+                   && sp <= stack_page + THREAD_SIZE - nbytes)
+                       return 1;
+       }
+       return 0;
+}
+
+#else
+#define valid_irq_stack(sp, p, nb)     0
+#endif /* CONFIG_IRQSTACKS */
+
 int validate_sp(unsigned long sp, struct task_struct *p,
                       unsigned long nbytes)
 {
@@ -827,19 +856,7 @@ int validate_sp(unsigned long sp, struct task_struct *p,
            && sp <= stack_page + THREAD_SIZE - nbytes)
                return 1;
 
-#ifdef CONFIG_IRQSTACKS
-       stack_page = (unsigned long) hardirq_ctx[task_cpu(p)];
-       if (sp >= stack_page + sizeof(struct thread_struct)
-           && sp <= stack_page + THREAD_SIZE - nbytes)
-               return 1;
-
-       stack_page = (unsigned long) softirq_ctx[task_cpu(p)];
-       if (sp >= stack_page + sizeof(struct thread_struct)
-           && sp <= stack_page + THREAD_SIZE - nbytes)
-               return 1;
-#endif
-
-       return 0;
+       return valid_irq_stack(sp, p, nbytes);
 }
 
 #ifdef CONFIG_PPC64