diff options
author | Paul Mackerras <paulus@samba.org> | 2007-02-18 19:42:42 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-03-07 23:31:43 -0500 |
commit | bb72c481e970dc1b4034ddccbe8302ff39e0d948 (patch) | |
tree | 4fa19698d82308c0b293bd3968bfd3b7a5e59ba7 /arch/powerpc/kernel/process.c | |
parent | 99ddef9bfe714c3273e3fce4c6b6a2a99e7d0bf8 (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.c | 43 |
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 | ||
822 | static 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 | |||
821 | int validate_sp(unsigned long sp, struct task_struct *p, | 850 | int 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 |