[PATCH -next v15 14/19] riscv: signal: Report signal frame size to userspace via auxv
Guo Ren
guoren at kernel.org
Thu Mar 23 07:39:41 PDT 2023
On Fri, Mar 17, 2023 at 7:37 PM Andy Chiu <andy.chiu at sifive.com> wrote:
>
> From: Vincent Chen <vincent.chen at sifive.com>
>
> The vector register belongs to the signal context. They need to be stored
> and restored as entering and leaving the signal handler. According to the
> V-extension specification, the maximum length of the vector registers can
> be 2^(XLEN-1). Hence, if userspace refers to the MINSIGSTKSZ to create a
> sigframe, it may not be enough. To resolve this problem, this patch refers
> to the commit 94b07c1f8c39c
> ("arm64: signal: Report signal frame size to userspace via auxv") to enable
> userspace to know the minimum required sigframe size through the auxiliary
> vector and use it to allocate enough memory for signal context.
>
> Note that auxv always reports size of the sigframe as if V exists for
> all starting processes, whenever the kernel has CONFIG_RISCV_ISA_V. The
> reason is that users usually reference this value to allocate an
> alternative signal stack, and the user may use V anytime. So the user
> must reserve a space for V-context in sigframe in case that the signal
> handler invokes after the kernel allocating V.
>
> Signed-off-by: Greentime Hu <greentime.hu at sifive.com>
> Signed-off-by: Vincent Chen <vincent.chen at sifive.com>
> Signed-off-by: Andy Chiu <andy.chiu at sifive.com>
> Acked-by: Conor Dooley <conor.dooley at microchip.com>
> ---
> arch/riscv/include/asm/elf.h | 9 +++++++++
> arch/riscv/include/asm/processor.h | 2 ++
> arch/riscv/include/uapi/asm/auxvec.h | 1 +
> arch/riscv/kernel/signal.c | 20 +++++++++++++++-----
> 4 files changed, 27 insertions(+), 5 deletions(-)
>
> diff --git a/arch/riscv/include/asm/elf.h b/arch/riscv/include/asm/elf.h
> index 30e7d2455960..ca23c4f6c440 100644
> --- a/arch/riscv/include/asm/elf.h
> +++ b/arch/riscv/include/asm/elf.h
> @@ -105,6 +105,15 @@ do { \
> get_cache_size(3, CACHE_TYPE_UNIFIED)); \
> NEW_AUX_ENT(AT_L3_CACHEGEOMETRY, \
> get_cache_geometry(3, CACHE_TYPE_UNIFIED)); \
> + /* \
> + * Should always be nonzero unless there's a kernel bug. \
> + * If we haven't determined a sensible value to give to \
> + * userspace, omit the entry: \
> + */ \
> + if (likely(signal_minsigstksz)) \
> + NEW_AUX_ENT(AT_MINSIGSTKSZ, signal_minsigstksz); \
> + else \
> + NEW_AUX_ENT(AT_IGNORE, 0); \
> } while (0)
> #define ARCH_HAS_SETUP_ADDITIONAL_PAGES
> struct linux_binprm;
> diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
> index f0ddf691ac5e..38ded8c5f207 100644
> --- a/arch/riscv/include/asm/processor.h
> +++ b/arch/riscv/include/asm/processor.h
> @@ -7,6 +7,7 @@
> #define _ASM_RISCV_PROCESSOR_H
>
> #include <linux/const.h>
> +#include <linux/cache.h>
>
> #include <vdso/processor.h>
>
> @@ -81,6 +82,7 @@ int riscv_of_parent_hartid(struct device_node *node, unsigned long *hartid);
> extern void riscv_fill_hwcap(void);
> extern int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
>
> +extern unsigned long signal_minsigstksz __ro_after_init;
> #endif /* __ASSEMBLY__ */
>
> #endif /* _ASM_RISCV_PROCESSOR_H */
> diff --git a/arch/riscv/include/uapi/asm/auxvec.h b/arch/riscv/include/uapi/asm/auxvec.h
> index fb187a33ce58..10aaa83db89e 100644
> --- a/arch/riscv/include/uapi/asm/auxvec.h
> +++ b/arch/riscv/include/uapi/asm/auxvec.h
> @@ -35,5 +35,6 @@
>
> /* entries in ARCH_DLINFO */
> #define AT_VECTOR_SIZE_ARCH 9
> +#define AT_MINSIGSTKSZ 51
>
> #endif /* _UAPI_ASM_RISCV_AUXVEC_H */
> diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
> index 55d2215d18ea..d2d9232498ca 100644
> --- a/arch/riscv/kernel/signal.c
> +++ b/arch/riscv/kernel/signal.c
> @@ -21,6 +21,8 @@
> #include <asm/vector.h>
> #include <asm/csr.h>
>
> +unsigned long signal_minsigstksz __ro_after_init;
> +
> extern u32 __user_rt_sigreturn[2];
> static size_t riscv_v_sc_size __ro_after_init;
>
> @@ -195,7 +197,7 @@ static long restore_sigcontext(struct pt_regs *regs,
> return err;
> }
>
> -static size_t get_rt_frame_size(void)
> +static size_t get_rt_frame_size(bool cal_all)
> {
> struct rt_sigframe __user *frame;
> size_t frame_size;
> @@ -203,8 +205,10 @@ static size_t get_rt_frame_size(void)
>
> frame_size = sizeof(*frame);
>
> - if (has_vector() && riscv_v_vstate_query(task_pt_regs(current)))
> - total_context_size += riscv_v_sc_size;
> + if (has_vector()) {
> + if (cal_all || riscv_v_vstate_query(task_pt_regs(current)))
> + total_context_size += riscv_v_sc_size;
> + }
> /*
> * Preserved a __riscv_ctx_hdr for END signal context header if an
> * extension uses __riscv_extra_ext_header
> @@ -224,7 +228,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
> struct rt_sigframe __user *frame;
> struct task_struct *task;
> sigset_t set;
> - size_t frame_size = get_rt_frame_size();
> + size_t frame_size = get_rt_frame_size(false);
>
> /* Always make any pending restarted system calls return -EINTR */
> current->restart_block.fn = do_no_restart_syscall;
> @@ -320,7 +324,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
> {
> struct rt_sigframe __user *frame;
> long err = 0;
> - size_t frame_size = get_rt_frame_size();
> + size_t frame_size = get_rt_frame_size(false);
>
> frame = get_sigframe(ksig, regs, frame_size);
> if (!access_ok(frame, frame_size))
> @@ -483,4 +487,10 @@ void __init init_rt_signal_env(void)
> {
> riscv_v_sc_size = sizeof(struct __riscv_ctx_hdr) +
> sizeof(struct __sc_riscv_v_state) + riscv_v_vsize;
> + /*
> + * Determine the stack space required for guaranteed signal delivery.
> + * The signal_minsigstksz will be populated into the AT_MINSIGSTKSZ entry
> + * in the auxiliary array at process startup.
> + */
> + signal_minsigstksz = get_rt_frame_size(true);
> }
> --
> 2.17.1
>
Reviewed-by: Guo Ren <guoren at kernel.org>
--
Best Regards
Guo Ren
More information about the linux-riscv
mailing list