mirror of
https://github.com/torvalds/linux.git
synced 2024-11-23 12:42:02 +00:00
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:
parent
2500763dd3
commit
ac9c8901cb
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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__ */
|
||||
|
Loading…
Reference in New Issue
Block a user