[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