[PATCH v5 15/16] riscv/cfi: Support ucontext under CFI
Gabriel Ravier
gabravier@gmail.com
Sun Sep 13 20:11:33 GMT 2026
On 6/28/26 9:02 AM, Jesse Huang wrote:
> This patch adds shadow stack and landing pad support to the ucontext
> library. Shadow stack switches are protected by a shadow stack restore
> token that is validated during the switch.
>
> Co-authored-by: Nia Su <nia.su@sifive.com>
> ---
> sysdeps/unix/sysv/linux/riscv/getcontext.S | 20 +++++
> sysdeps/unix/sysv/linux/riscv/makecontext.c | 19 +++++
> sysdeps/unix/sysv/linux/riscv/setcontext.S | 67 ++++++++++++++++
> sysdeps/unix/sysv/linux/riscv/swapcontext.S | 81 +++++++++++++++++++-
> sysdeps/unix/sysv/linux/riscv/ucontext_i.sym | 4 +-
> 5 files changed, 189 insertions(+), 2 deletions(-)
>
> [snip]
> diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S
> index 9fd5f1f3cb..34ee34b607 100644
> --- a/sysdeps/unix/sysv/linux/riscv/setcontext.S
> +++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S
> @@ -17,6 +17,7 @@
> <https://www.gnu.org/licenses/>. */
>
> #include "ucontext-macros.h"
> +#include "tcb-offsets.h"
>
> /* int __setcontext (const ucontext_t *ucp)
>
> @@ -29,6 +30,7 @@
>
> .text
> LEAF (__setcontext)
> + LPAD
>
> mv t0, a0 /* Save ucp into t0. */
>
> @@ -45,6 +47,55 @@ LEAF (__setcontext)
>
> cfi_def_cfa (t0, 0)
>
> +#ifdef __riscv_shadow_stack
> + /* Skip if shadow stack is not enabled */
> + ssrdp ra
> + beqz ra, .Lfin
> + /* We are safe to adjust shadow stack after the sanity check */
> + REG_L t1, UCONTEXT_SSP_BASE(t0)
> + REG_L a1, UCONTEXT_SSP(t0)
> + REG_L a2, TLS_SSP_BASE_OFFSET(tp)
> + bne t1, a2, .Ldifferent_stack
> +
> +.Lunwind:
> + bleu a1, ra, .Lfin
> + /* increase ssp by at most one page size to ensure the adjustment
> + always runs into a guard page before accidentally pointing to
> + another legal shadow stack page */
> + /* ra = (a1 - ra >= 4096) ? ra + 4096 : a1 */
> + lui t2, 1
> + add ra, ra, t2
> + bleu ra, a1, 1f
> + mv ra, a1
> +1:
> + csrw ssp, ra
> + /* Test if the location pointed by ssp is legal */
> + sspush ra
> + sspopchk ra
> + j .Lunwind
> +
> +.Ldifferent_stack:
> + /* Create restore token */
> + sspush ra
> + mv a4, a1
> +
> +.Lfind_rstor_token:
> + /* Probe and validate target restore token */
> + ssamoswap.d a3, x0, (a4)
> + addi a2, a4, 8
> + beq a3, a2, .Lswitch_stack
> + /* Restore the shadow stack and try the next slot */
> + ssamoswap.d x0, a3, (a4)
> + addi a4, a4, -8
> + j .Lfind_rstor_token
> +
> +.Lswitch_stack:
> + /* Switch stack: update ssp and base */
> + csrw ssp, a1
> + REG_S t1, TLS_SSP_BASE_OFFSET(tp)
> +.Lfin:
> +#endif
> +
> #ifndef __riscv_float_abi_soft
> lw t1, MCONTEXT_FSR(t0)
>
> @@ -66,7 +117,11 @@ LEAF (__setcontext)
>
> /* Note the contents of argument registers will be random
> unless makecontext() has been called. */
> +#ifdef __riscv_landing_pad
> + RESTORE_INT_REG (t2, 0, t0)
> +#else
> RESTORE_INT_REG (t1, 0, t0)
> +#endif
> RESTORE_INT_REG_CFI (ra, 1, t0)
> RESTORE_INT_REG (sp, 2, t0)
> RESTORE_INT_REG_CFI (s0, 8, t0)
> @@ -90,7 +145,12 @@ LEAF (__setcontext)
> RESTORE_INT_REG_CFI (s10, 26, t0)
> RESTORE_INT_REG_CFI (s11, 27, t0)
>
> +#ifdef __riscv_landing_pad
> + /* We need to use software-guared jump */
*software-guarded
> + jr t2
> +#else
> jr t1
> +#endif
>
> 99: tail __syscall_error
>
> @@ -99,12 +159,19 @@ libc_hidden_def (__setcontext)
> weak_alias (__setcontext, setcontext)
>
> LEAF (__start_context)
> + LPAD
>
> /* Terminate call stack by noting ra == 0. Happily, s0 == 0 here. */
> cfi_register (ra, s0)
>
> /* Call the function passed to makecontext. */
> +#ifdef __riscv_landing_pad
> + /* We need to use software-guared jump */
*software-guarded
> + mv t2, s1
> + jalr t2
> +#else
> jalr s1
> +#endif
>
> /* Invoke subsequent context if present, else exit(0). */
> mv a0, s2
> diff --git a/sysdeps/unix/sysv/linux/riscv/swapcontext.S b/sysdeps/unix/sysv/linux/riscv/swapcontext.S
> index 4b3b0b3a14..a040de1b9a 100644
> --- a/sysdeps/unix/sysv/linux/riscv/swapcontext.S
> +++ b/sysdeps/unix/sysv/linux/riscv/swapcontext.S
> @@ -17,10 +17,12 @@
> <https://www.gnu.org/licenses/>. */
>
> #include "ucontext-macros.h"
> +#include "tcb-offsets.h"
>
> /* int swapcontext (ucontext_t *oucp, const ucontext_t *ucp) */
>
> LEAF (__swapcontext)
> + LPAD
> mv t0, a1 /* Save ucp into t0. */
>
> SAVE_INT_REG (ra, 0, a0)
> @@ -59,6 +61,26 @@ LEAF (__swapcontext)
> sw a1, MCONTEXT_FSR(a0)
> #endif /* __riscv_float_abi_soft */
>
> +#ifdef __riscv_shadow_stack
> + /* Skip if shadow stack is not enabled */
> + ssrdp ra
> + beqz ra, .Lsave_fin
> +
> + /* Read ssp_base from TLS */
> + REG_L t2, TLS_SSP_BASE_OFFSET(tp)
> + bnez t2, .Lbase_saved
> +
> + /* if not found, use current ssp as the marker */
> + mv t2, ra
> + REG_S t2, TLS_SSP_BASE_OFFSET(tp)
> +
> +.Lbase_saved:
> + /* Save caller's ssp and base marker to oucp */
> + REG_S t2, UCONTEXT_SSP_BASE(a0)
> + REG_S ra, UCONTEXT_SSP(a0)
> +.Lsave_fin:
> +#endif
> +
> /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, _NSIG8) */
> li a3, _NSIG8
> add a2, a0, UCONTEXT_SIGMASK
> @@ -70,6 +92,55 @@ LEAF (__swapcontext)
>
> bltz a0, 99f
>
> +#ifdef __riscv_shadow_stack
> + /* Skip if shadow stack is not enabled */
> + ssrdp ra
> + beqz ra, .Lfin
> + /* Load ss information from ucp */
> + REG_L a0, UCONTEXT_SSP_BASE(t0)
> + REG_L a1, UCONTEXT_SSP(t0)
> + REG_L a2, TLS_SSP_BASE_OFFSET(tp)
> + bne a0, a2, .Ldifferent_stack
> +
> +.Lunwind:
> + bleu a1, ra, .Lfin
> + /* increase ssp by at most one page size to ensure the adjustment
> + always runs into a guard page before accidentally pointing to
> + another legal shadow stack page */
> + /* ra = (a1 - ra >= 4096) ? ra + 4096 : a1 */
> + lui t2, 1
> + add ra, ra, t2
> + bleu ra, a1, 1f
> + mv ra, a1
> +1:
> + csrw ssp, ra
> + /* Test if the location pointed by ssp is legal */
> + sspush ra
> + sspopchk ra
> + j .Lunwind
> +
> +.Ldifferent_stack:
> + /* Create restore token */
> + sspush ra
> + mv a4, a1
> +
> +.Lfind_rstor_token:
> + /* Probe and validate target restore token */
> + ssamoswap.d a3, x0, (a4)
> + addi a2, a4, 8
> + beq a3, a2, .Lswitch_stack
> + /* Restore the shadow stack and try the next slot */
> + ssamoswap.d x0, a3, (a4)
> + addi a4, a4, -8
> + j .Lfind_rstor_token
> +
> +.Lswitch_stack:
> + /* Switch stack: update ssp and base */
> + csrw ssp, a1
> + REG_S a0, TLS_SSP_BASE_OFFSET(tp)
> +.Lfin:
> +#endif
> +
> #ifndef __riscv_float_abi_soft
> lw t1, MCONTEXT_FSR(t0)
>
> @@ -91,7 +162,11 @@ LEAF (__swapcontext)
>
> /* Note the contents of argument registers will be random
> unless makecontext() has been called. */
> +#ifdef __riscv_landing_pad
> + RESTORE_INT_REG (t2, 0, t0)
> +#else
> RESTORE_INT_REG (t1, 0, t0)
> +#endif
> RESTORE_INT_REG (ra, 1, t0)
> RESTORE_INT_REG (sp, 2, t0)
> RESTORE_INT_REG (s0, 8, t0)
> @@ -115,8 +190,12 @@ LEAF (__swapcontext)
> RESTORE_INT_REG (s10, 26, t0)
> RESTORE_INT_REG (s11, 27, t0)
>
> +#ifdef __riscv_landing_pad
> + /* We need to use software-guared jump */
*software-guarded
> + jr t2
> +#else
> jr t1
> -
> +#endif
>
> 99: tail __syscall_error
>
> [snip]
More information about the Libc-alpha
mailing list