lkml.org 
[lkml]   [2023]   [Feb]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v1 RFC Zisslpcfi 18/20] riscv signal: Save and restore of shadow stack for signal
    Date
    Save shadow stack pointer in ucontext structure while delivering signal.
    Restore shadow stack pointer from ucontext on sigreturn.

    Signed-off-by: Deepak Gupta <debug@rivosinc.com>
    ---
    arch/riscv/kernel/signal.c | 45 ++++++++++++++++++++++++++++++++++++++
    1 file changed, 45 insertions(+)

    diff --git a/arch/riscv/kernel/signal.c b/arch/riscv/kernel/signal.c
    index bfb2afa4135f..b963bbce5879 100644
    --- a/arch/riscv/kernel/signal.c
    +++ b/arch/riscv/kernel/signal.c
    @@ -103,6 +103,7 @@ SYSCALL_DEFINE0(rt_sigreturn)
    struct pt_regs *regs = current_pt_regs();
    struct rt_sigframe __user *frame;
    struct task_struct *task;
    + struct thread_info *info = NULL;
    sigset_t set;

    /* Always make any pending restarted system calls return -EINTR */
    @@ -124,6 +125,27 @@ SYSCALL_DEFINE0(rt_sigreturn)
    if (restore_altstack(&frame->uc.uc_stack))
    goto badframe;

    +#if defined(CONFIG_USER_SHADOW_STACK)
    + /*
    + * TODO: Restore shadow stack as a form of token stored on shadow stack itself as a safe
    + * way to restore.
    + * A token on shadow gives following properties
    + * - Safe save and restore for shadow stack switching. Any save of shadow stack
    + * must have had saved a token on shadow stack. Similarly any restore of shadow
    + * stack must check the token before restore. Since writing to shadow stack with
    + * address of shadow stack itself is not easily allowed. A restore without a save
    + * is quite difficult for an attacker to perform.
    + * - A natural break. A token in shadow stack provides a natural break in shadow stack
    + * So a single linear range can be bucketed into different shadow stack segments.
    + * Any sspop; sscheckra will detect the condition and fault to kernel.
    + */
    + info = current_thread_info();
    + if (info->user_cfi_state.ubcfi_en &&
    + __copy_from_user(&info->user_cfi_state.user_shdw_stk, &frame->uc.uc_ss_ptr,
    + sizeof(unsigned long)))
    + goto badframe;
    +#endif
    +
    regs->cause = -1UL;

    return regs->a0;
    @@ -180,6 +202,7 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
    struct pt_regs *regs)
    {
    struct rt_sigframe __user *frame;
    + struct thread_info *info = NULL;
    long err = 0;

    frame = get_sigframe(ksig, regs, sizeof(*frame));
    @@ -191,6 +214,23 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
    /* Create the ucontext. */
    err |= __put_user(0, &frame->uc.uc_flags);
    err |= __put_user(NULL, &frame->uc.uc_link);
    +#if defined(CONFIG_USER_SHADOW_STACK)
    + /*
    + * TODO: Save a pointer to shadow stack itself on shadow stack as a form of token.
    + * A token on shadow gives following properties
    + * - Safe save and restore for shadow stack switching. Any save of shadow stack
    + * must have had saved a token on shadow stack. Similarly any restore of shadow
    + * stack must check the token before restore. Since writing to shadow stack with
    + * address of shadow stack itself is not easily allowed. A restore without a save
    + * is quite difficult for an attacker to perform.
    + * - A natural break. A token in shadow stack provides a natural break in shadow stack
    + * So a single linear range can be bucketed into different shadow stack segments. Any
    + * sspop; sscheckra will detect the condition and fault to kernel.
    + */
    + info = current_thread_info();
    + if (info->user_cfi_state.ubcfi_en)
    + err |= __put_user(info->user_cfi_state.user_shdw_stk, &frame->uc.uc_ss_ptr);
    +#endif
    err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
    err |= setup_sigcontext(frame, regs);
    err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
    @@ -201,6 +241,11 @@ static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
    #ifdef CONFIG_MMU
    regs->ra = (unsigned long)VDSO_SYMBOL(
    current->mm->context.vdso, rt_sigreturn);
    +#if defined(CONFIG_USER_SHADOW_STACK)
    + /* if bcfi is enabled x1 (ra) and x5 (t0) must match */
    + if (info->user_cfi_state.ubcfi_en)
    + regs->t0 = regs->ra;
    +#endif
    #else
    /*
    * For the nommu case we don't have a VDSO. Instead we push two
    --
    2.25.1
    \
     
     \ /
      Last update: 2023-03-27 00:19    [W:4.040 / U:2.480 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site