Commit bb72c481 authored by Paul Mackerras's avatar Paul Mackerras
Browse files

[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: default avatarPaul Mackerras <paulus@samba.org>
parent 99ddef9b
Loading
Loading
Loading
Loading
+30 −13
Original line number Diff line number Diff line
@@ -818,28 +818,45 @@ int sys_execve(unsigned long a0, unsigned long a1, unsigned long a2,
	return error;
}

int validate_sp(unsigned long sp, struct task_struct *p,
#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)task_stack_page(p);
	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;

#ifdef CONFIG_IRQSTACKS
	stack_page = (unsigned long) hardirq_ctx[task_cpu(p)];
		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)
{
	unsigned long stack_page = (unsigned long)task_stack_page(p);

	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