[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>
This commit is contained in:
@@ -818,6 +818,35 @@ out:
|
|||||||
return error;
|
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,
|
int validate_sp(unsigned long sp, struct task_struct *p,
|
||||||
unsigned long nbytes)
|
unsigned long nbytes)
|
||||||
{
|
{
|
||||||
@@ -827,19 +856,7 @@ int validate_sp(unsigned long sp, struct task_struct *p,
|
|||||||
&& sp <= stack_page + THREAD_SIZE - nbytes)
|
&& sp <= stack_page + THREAD_SIZE - nbytes)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
#ifdef CONFIG_IRQSTACKS
|
return valid_irq_stack(sp, p, nbytes);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PPC64
|
#ifdef CONFIG_PPC64
|
||||||
|
Reference in New Issue
Block a user