Commit ac9c8901 authored by Nicholas Miehlbradt's avatar Nicholas Miehlbradt Committed by Michael Ellerman
Browse files

powerpc: Implement arch_within_stack_frames



Walks the stack when copy_{to,from}_user address is in the stack to
ensure that the object being copied is entirely a single stack frame and
does not contain stack metadata.

Substantially similar to the x86 implementation. The back chain is used
to traverse the stack and identify stack frame boundaries.

Signed-off-by: default avatarNicholas Miehlbradt <nicholas@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230228054355.300628-1-nicholas@linux.ibm.com
parent 2500763d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -200,6 +200,7 @@ config PPC
	select HAVE_ARCH_KCSAN            	if PPC_BOOK3S_64
	select HAVE_ARCH_KFENCE			if ARCH_SUPPORTS_DEBUG_PAGEALLOC
	select HAVE_ARCH_RANDOMIZE_KSTACK_OFFSET
	select HAVE_ARCH_WITHIN_STACK_FRAMES
	select HAVE_ARCH_KGDB
	select HAVE_ARCH_MMAP_RND_BITS
	select HAVE_ARCH_MMAP_RND_COMPAT_BITS	if COMPAT
+8 −0
Original line number Diff line number Diff line
@@ -837,4 +837,12 @@ END_FTR_SECTION_NESTED(CPU_FTR_CELL_TB_BUG, CPU_FTR_CELL_TB_BUG, 96)
#define BTB_FLUSH(reg)
#endif /* CONFIG_PPC_E500 */

#if defined(CONFIG_PPC64_ELF_ABI_V1)
#define STACK_FRAME_PARAMS 48
#elif defined(CONFIG_PPC64_ELF_ABI_V2)
#define STACK_FRAME_PARAMS 32
#elif defined(CONFIG_PPC32)
#define STACK_FRAME_PARAMS 8
#endif

#endif /* _ASM_POWERPC_PPC_ASM_H */
+38 −0
Original line number Diff line number Diff line
@@ -45,6 +45,7 @@
#include <linux/cache.h>
#include <asm/processor.h>
#include <asm/accounting.h>
#include <asm/ppc_asm.h>

#define SLB_PRELOAD_NR	16U
/*
@@ -186,6 +187,43 @@ static inline bool test_thread_local_flags(unsigned int flags)
#define is_elf2_task() (0)
#endif

/*
 * Walks up the stack frames to make sure that the specified object is
 * entirely contained by a single stack frame.
 *
 * Returns:
 *	GOOD_FRAME	if within a frame
 *	BAD_STACK	if placed across a frame boundary (or outside stack)
 */
static inline int arch_within_stack_frames(const void * const stack,
					   const void * const stackend,
					   const void *obj, unsigned long len)
{
	const void *params;
	const void *frame;

	params = *(const void * const *)current_stack_pointer + STACK_FRAME_PARAMS;
	frame = **(const void * const * const *)current_stack_pointer;

	/*
	 * low -----------------------------------------------------------> high
	 * [backchain][metadata][params][local vars][saved registers][backchain]
	 *                      ^------------------------------------^
	 *                      |  allows copies only in this region |
	 *                      |                                    |
	 *                    params                               frame
	 * The metadata region contains the saved LR, CR etc.
	 */
	while (stack <= frame && frame < stackend) {
		if (obj + len <= frame)
			return obj >= params ? GOOD_FRAME : BAD_STACK;
		params = frame + STACK_FRAME_PARAMS;
		frame = *(const void * const *)frame;
	}

	return BAD_STACK;
}

#endif	/* !__ASSEMBLY__ */

#endif /* __KERNEL__ */