Commit 4cefb0f6 authored by Nicholas Piggin's avatar Nicholas Piggin Committed by Michael Ellerman
Browse files

powerpc: split validate_sp into two functions



Most callers just want to validate an arbitrary kernel stack pointer,
some need a particular size. Make the size case the exceptional one
with an extra function.

Signed-off-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20221127124942.1665522-15-npiggin@gmail.com
parent edbd0387
Loading
Loading
Loading
Loading
+12 −3
Original line number Diff line number Diff line
@@ -374,8 +374,17 @@ static inline unsigned long __pack_fe01(unsigned int fpmode)

#endif

/* Check that a certain kernel stack pointer is valid in task_struct p */
int validate_sp(unsigned long sp, struct task_struct *p,
/*
 * Check that a certain kernel stack pointer is a valid (minimum sized)
 * stack frame in task_struct p.
 */
int validate_sp(unsigned long sp, struct task_struct *p);

/*
 * validate the stack frame of a particular minimum size, used for when we are
 * looking at a certain object in the stack beyond the minimum.
 */
int validate_sp_size(unsigned long sp, struct task_struct *p,
		     unsigned long nbytes);

/*
+14 −9
Original line number Diff line number Diff line
@@ -2157,8 +2157,11 @@ static inline int valid_emergency_stack(unsigned long sp, struct task_struct *p,
	return 0;
}


int validate_sp(unsigned long sp, struct task_struct *p,
/*
 * validate the stack frame of a particular minimum size, used for when we are
 * looking at a certain object in the stack beyond the minimum.
 */
int validate_sp_size(unsigned long sp, struct task_struct *p,
		     unsigned long nbytes)
{
	unsigned long stack_page = (unsigned long)task_stack_page(p);
@@ -2175,7 +2178,10 @@ int validate_sp(unsigned long sp, struct task_struct *p,
	return valid_emergency_stack(sp, p, nbytes);
}

EXPORT_SYMBOL(validate_sp);
int validate_sp(unsigned long sp, struct task_struct *p)
{
	return validate_sp_size(sp, p, STACK_FRAME_OVERHEAD);
}

static unsigned long ___get_wchan(struct task_struct *p)
{
@@ -2183,13 +2189,12 @@ static unsigned long ___get_wchan(struct task_struct *p)
	int count = 0;

	sp = p->thread.ksp;
	if (!validate_sp(sp, p, STACK_FRAME_OVERHEAD))
	if (!validate_sp(sp, p))
		return 0;

	do {
		sp = READ_ONCE_NOCHECK(*(unsigned long *)sp);
		if (!validate_sp(sp, p, STACK_FRAME_OVERHEAD) ||
		    task_is_running(p))
		if (!validate_sp(sp, p) || task_is_running(p))
			return 0;
		if (count > 0) {
			ip = READ_ONCE_NOCHECK(((unsigned long *)sp)[STACK_FRAME_LR_SAVE]);
@@ -2243,7 +2248,7 @@ void __no_sanitize_address show_stack(struct task_struct *tsk,
	lr = 0;
	printk("%sCall Trace:\n", loglvl);
	do {
		if (!validate_sp(sp, tsk, STACK_FRAME_OVERHEAD))
		if (!validate_sp(sp, tsk))
			break;

		stack = (unsigned long *) sp;
@@ -2270,7 +2275,7 @@ void __no_sanitize_address show_stack(struct task_struct *tsk,
		 * could hold a pt_regs, if that does not fit then it can't
		 * have regs.
		 */
		if (validate_sp(sp, tsk, STACK_SWITCH_FRAME_SIZE)
		if (validate_sp_size(sp, tsk, STACK_SWITCH_FRAME_SIZE)
		    && stack[STACK_INT_FRAME_MARKER_LONGS] == STACK_FRAME_REGS_MARKER) {
			struct pt_regs *regs = (struct pt_regs *)
				(sp + STACK_INT_FRAME_REGS);
+1 −1
Original line number Diff line number Diff line
@@ -43,7 +43,7 @@ void __no_sanitize_address arch_stack_walk(stack_trace_consume_fn consume_entry,
		unsigned long *stack = (unsigned long *) sp;
		unsigned long newsp, ip;

		if (!validate_sp(sp, task, STACK_FRAME_OVERHEAD))
		if (!validate_sp(sp, task))
			return;

		newsp = stack[0];
+3 −3
Original line number Diff line number Diff line
@@ -27,7 +27,7 @@ static int valid_next_sp(unsigned long sp, unsigned long prev_sp)
{
	if (sp & 0xf)
		return 0;		/* must be 16-byte aligned */
	if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
	if (!validate_sp(sp, current))
		return 0;
	if (sp >= prev_sp + STACK_FRAME_MIN_SIZE)
		return 1;
@@ -53,7 +53,7 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re
	sp = regs->gpr[1];
	perf_callchain_store(entry, perf_instruction_pointer(regs));

	if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
	if (!validate_sp(sp, current))
		return;

	for (;;) {
@@ -61,7 +61,7 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re
		next_sp = fp[0];

		if (next_sp == sp + STACK_INT_FRAME_SIZE &&
		    validate_sp(sp, current, STACK_INT_FRAME_SIZE) &&
		    validate_sp_size(sp, current, STACK_INT_FRAME_SIZE) &&
		    fp[STACK_INT_FRAME_MARKER_LONGS] == STACK_FRAME_REGS_MARKER) {
			/*
			 * This looks like an interrupt frame for an