aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/process.c
diff options
context:
space:
mode:
authorPaul Mackerras <paulus@samba.org>2007-02-18 19:42:42 -0500
committerPaul Mackerras <paulus@samba.org>2007-03-07 23:31:43 -0500
commitbb72c481e970dc1b4034ddccbe8302ff39e0d948 (patch)
tree4fa19698d82308c0b293bd3968bfd3b7a5e59ba7 /arch/powerpc/kernel/process.c
parent99ddef9bfe714c3273e3fce4c6b6a2a99e7d0bf8 (diff)
[POWERPC] Harden validate_sp against stack corruption
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>
Diffstat (limited to 'arch/powerpc/kernel/process.c')
-rw-r--r--arch/powerpc/kernel/process.c43
1 files changed, 30 insertions, 13 deletions
diff --git a/arch/powerpc/kernel/process.c b/arch/powerpc/kernel/process.c
index f3d4dd580dd6..972b2acbe713 100644
--- a/arch/powerpc/kernel/process.c
+++ b/arch/powerpc/kernel/process.c
@@ -818,6 +818,35 @@ out:
818 return error; 818 return error;
819} 819}
820 820
821#ifdef CONFIG_IRQSTACKS
822static inline int valid_irq_stack(unsigned long sp, struct task_struct *p,
823 unsigned long nbytes)
824{
825 unsigned long stack_page;
826 unsigned long cpu = task_cpu(p);
827
828 /*
829 * Avoid crashing if the stack has overflowed and corrupted
830 * task_cpu(p), which is in the thread_info struct.
831 */
832 if (cpu < NR_CPUS && cpu_possible(cpu)) {
833 stack_page = (unsigned long) hardirq_ctx[cpu];
834 if (sp >= stack_page + sizeof(struct thread_struct)
835 && sp <= stack_page + THREAD_SIZE - nbytes)
836 return 1;
837
838 stack_page = (unsigned long) softirq_ctx[cpu];
839 if (sp >= stack_page + sizeof(struct thread_struct)
840 && sp <= stack_page + THREAD_SIZE - nbytes)
841 return 1;
842 }
843 return 0;
844}
845
846#else
847#define valid_irq_stack(sp, p, nb) 0
848#endif /* CONFIG_IRQSTACKS */
849
821int validate_sp(unsigned long sp, struct task_struct *p, 850int validate_sp(unsigned long sp, struct task_struct *p,
822 unsigned long nbytes) 851 unsigned long nbytes)
823{ 852{
@@ -827,19 +856,7 @@ int validate_sp(unsigned long sp, struct task_struct *p,
827 && sp <= stack_page + THREAD_SIZE - nbytes) 856 && sp <= stack_page + THREAD_SIZE - nbytes)
828 return 1; 857 return 1;
829 858
830#ifdef CONFIG_IRQSTACKS 859 return valid_irq_stack(sp, p, nbytes);
831 stack_page = (unsigned long) hardirq_ctx[task_cpu(p)];
832 if (sp >= stack_page + sizeof(struct thread_struct)
833 && sp <= stack_page + THREAD_SIZE - nbytes)
834 return 1;
835
836 stack_page = (unsigned long) softirq_ctx[task_cpu(p)];
837 if (sp >= stack_page + sizeof(struct thread_struct)
838 && sp <= stack_page + THREAD_SIZE - nbytes)
839 return 1;
840#endif
841
842 return 0;
843} 860}
844 861
845#ifdef CONFIG_PPC64 862#ifdef CONFIG_PPC64