From 2f82ec19757f58549467db568c56e7dfff8af283 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 8 Mar 2022 04:27:33 +1000 Subject: powerpc/64: Bump SIGSTKSZ and MINSIGSTKSZ The sad tale of SIGSTKSZ and MINSIGSTKSZ is documented in glibc.git commit f7c399cff5bd ("PowerPC SIGSTKSZ"), which explains why glibc does not use the kernel defines for these constants. Since then in fact there has been a further expansion of the signal stack frame size on little-endian with linux commit 573ebfa6601f ("powerpc: Increase stack redzone for 64-bit userspace to 512 bytes"), which has caused it to exceed even the glibc defines. See kernel commit 63dee5df43a3 ("powerpc: Allow 4224 bytes of stack expansion for the signal frame") for more details of the history of the expansion. Increase MINSIGSTKSZ to 8192 which is double the current glibc value and fits the current stack frame with room to grow. SIGSTKSZ is set to 4x the minimum as convention. glibc will have to be updated as well. Reviewed-by: Tulio Magno Quites Machado Filho Signed-off-by: Nicholas Piggin Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20220307182734.289289-1-npiggin@gmail.com --- arch/powerpc/include/uapi/asm/signal.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'arch/powerpc/include/uapi') diff --git a/arch/powerpc/include/uapi/asm/signal.h b/arch/powerpc/include/uapi/asm/signal.h index 37d41d87c45b..a5dfe84f50ab 100644 --- a/arch/powerpc/include/uapi/asm/signal.h +++ b/arch/powerpc/include/uapi/asm/signal.h @@ -62,8 +62,13 @@ typedef struct { #define SA_RESTORER 0x04000000U +#ifdef __powerpc64__ +#define MINSIGSTKSZ 8192 +#define SIGSTKSZ 32768 +#else #define MINSIGSTKSZ 2048 #define SIGSTKSZ 8192 +#endif #include -- cgit v1.2.3 From 2896b2dff49d0377e4372f470dcddbcb26f2be59 Mon Sep 17 00:00:00 2001 From: Nicholas Piggin Date: Tue, 8 Mar 2022 04:27:34 +1000 Subject: powerpc/signal: Report minimum signal frame size to userspace via AT_MINSIGSTKSZ Implement the AT_MINSIGSTKSZ AUXV entry, allowing userspace to dynamically size stack allocations in a manner forward-compatible with new processor state saved in the signal frame For now these statically find the maximum signal frame size rather than doing any runtime testing of features to minimise the size. glibc 2.34 will take advantage of this, as will applications that use use _SC_MINSIGSTKSZ and _SC_SIGSTKSZ. Reviewed-by: Tulio Magno Quites Machado Filho Signed-off-by: Nicholas Piggin References: 94b07c1f8c39 ("arm64: signal: Report signal frame size to userspace via auxv") Signed-off-by: Michael Ellerman Link: https://lore.kernel.org/r/20220307182734.289289-2-npiggin@gmail.com --- arch/powerpc/include/asm/elf.h | 14 +++++++++++++- arch/powerpc/include/asm/signal.h | 5 +++++ arch/powerpc/include/uapi/asm/auxvec.h | 4 +++- arch/powerpc/kernel/signal.c | 15 +++++++++++++++ arch/powerpc/kernel/signal_32.c | 6 ++++++ arch/powerpc/kernel/signal_64.c | 5 +++++ 6 files changed, 47 insertions(+), 2 deletions(-) (limited to 'arch/powerpc/include/uapi') diff --git a/arch/powerpc/include/asm/elf.h b/arch/powerpc/include/asm/elf.h index 971589a21bc0..79f1c480b5eb 100644 --- a/arch/powerpc/include/asm/elf.h +++ b/arch/powerpc/include/asm/elf.h @@ -160,7 +160,7 @@ extern int arch_setup_additional_pages(struct linux_binprm *bprm, * even if DLINFO_ARCH_ITEMS goes to zero or is undefined. * update AT_VECTOR_SIZE_ARCH if the number of NEW_AUX_ENT entries changes */ -#define ARCH_DLINFO \ +#define COMMON_ARCH_DLINFO \ do { \ /* Handle glibc compatibility. */ \ NEW_AUX_ENT(AT_IGNOREPPC, AT_IGNOREPPC); \ @@ -173,6 +173,18 @@ do { \ ARCH_DLINFO_CACHE_GEOMETRY; \ } while (0) +#define ARCH_DLINFO \ +do { \ + COMMON_ARCH_DLINFO; \ + NEW_AUX_ENT(AT_MINSIGSTKSZ, get_min_sigframe_size()); \ +} while (0) + +#define COMPAT_ARCH_DLINFO \ +do { \ + COMMON_ARCH_DLINFO; \ + NEW_AUX_ENT(AT_MINSIGSTKSZ, get_min_sigframe_size_compat()); \ +} while (0) + /* Relocate the kernel image to @final_address */ void relocate(unsigned long final_address); diff --git a/arch/powerpc/include/asm/signal.h b/arch/powerpc/include/asm/signal.h index 99e1c6de27bc..922d43700fb4 100644 --- a/arch/powerpc/include/asm/signal.h +++ b/arch/powerpc/include/asm/signal.h @@ -9,4 +9,9 @@ struct pt_regs; void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags); +unsigned long get_min_sigframe_size_32(void); +unsigned long get_min_sigframe_size_64(void); +unsigned long get_min_sigframe_size(void); +unsigned long get_min_sigframe_size_compat(void); + #endif /* _ASM_POWERPC_SIGNAL_H */ diff --git a/arch/powerpc/include/uapi/asm/auxvec.h b/arch/powerpc/include/uapi/asm/auxvec.h index 7af21dc0e320..aa7c16215453 100644 --- a/arch/powerpc/include/uapi/asm/auxvec.h +++ b/arch/powerpc/include/uapi/asm/auxvec.h @@ -48,6 +48,8 @@ #define AT_L3_CACHESIZE 46 #define AT_L3_CACHEGEOMETRY 47 -#define AT_VECTOR_SIZE_ARCH 14 /* entries in ARCH_DLINFO */ +#define AT_MINSIGSTKSZ 51 /* stack needed for signal delivery */ + +#define AT_VECTOR_SIZE_ARCH 15 /* entries in ARCH_DLINFO */ #endif diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c index f7f8620663c7..68a91e553e14 100644 --- a/arch/powerpc/kernel/signal.c +++ b/arch/powerpc/kernel/signal.c @@ -141,6 +141,21 @@ unsigned long copy_ckvsx_from_user(struct task_struct *task, int show_unhandled_signals = 1; +unsigned long get_min_sigframe_size(void) +{ + if (IS_ENABLED(CONFIG_PPC64)) + return get_min_sigframe_size_64(); + else + return get_min_sigframe_size_32(); +} + +#ifdef CONFIG_COMPAT +unsigned long get_min_sigframe_size_compat(void) +{ + return get_min_sigframe_size_32(); +} +#endif + /* * Allocate space for the signal frame */ diff --git a/arch/powerpc/kernel/signal_32.c b/arch/powerpc/kernel/signal_32.c index d84c434b2b78..157a7403e3eb 100644 --- a/arch/powerpc/kernel/signal_32.c +++ b/arch/powerpc/kernel/signal_32.c @@ -233,6 +233,12 @@ struct rt_sigframe { int abigap[56]; }; +unsigned long get_min_sigframe_size_32(void) +{ + return max(sizeof(struct rt_sigframe) + __SIGNAL_FRAMESIZE + 16, + sizeof(struct sigframe) + __SIGNAL_FRAMESIZE); +} + /* * Save the current user registers on the user stack. * We only save the altivec/spe registers if the process has used diff --git a/arch/powerpc/kernel/signal_64.c b/arch/powerpc/kernel/signal_64.c index 858fc13b8c51..472596a109e2 100644 --- a/arch/powerpc/kernel/signal_64.c +++ b/arch/powerpc/kernel/signal_64.c @@ -66,6 +66,11 @@ struct rt_sigframe { char abigap[USER_REDZONE_SIZE]; } __attribute__ ((aligned (16))); +unsigned long get_min_sigframe_size_64(void) +{ + return sizeof(struct rt_sigframe) + __SIGNAL_FRAMESIZE; +} + /* * This computes a quad word aligned pointer inside the vmx_reserve array * element. For historical reasons sigcontext might not be quad word aligned, -- cgit v1.2.3