diff options
author | Paul Mackerras <paulus@samba.org> | 2007-02-19 11:42:42 +1100 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-03-08 15:31:43 +1100 |
commit | bb72c481e970dc1b4034ddccbe8302ff39e0d948 (patch) | |
tree | 4fa19698d82308c0b293bd3968bfd3b7a5e59ba7 | |
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>
-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 f3d4dd580dd..972b2acbe71 100644 --- a/arch/powerpc/kernel/process.c +++ b/arch/powerpc/kernel/process.c @@ -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 |