[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