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: Nicholas Miehlbradt <nicholas@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20230228054355.300628-1-nicholas@linux.ibm.com
This commit is contained in:
Nicholas Miehlbradt 2023-02-28 05:43:55 +00:00 committed by Michael Ellerman
parent 2500763dd3
commit ac9c8901cb
3 changed files with 47 additions and 0 deletions

View File

@ -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

View File

@ -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 */

View File

@ -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__ */