[PATCH 12/12] riscv/cfi: Support ucontext under CFI

Deepak Gupta debug@rivosinc.com
Wed Jun 18 21:34:45 GMT 2025


On Wed, Jun 18, 2025 at 01:42:58AM -0700, Jesse Huang wrote:
>This patches only make the ucontext library work while CFI is enabled.
>enabled. All security checks are skipped and should be implemented if
>correspoding interface are landed into the kernel.
>SSP is stored in the unused t3 slot in the sigcontext structure to avoid

Question:

Why can't we steal a 8 byte slot from `__glibc_reserved` under ucontext_t?


>breaking the current structure.
>
>Co-authored-by: Nia Su <nia.su@sifive.com>
>---
> sysdeps/unix/sysv/linux/riscv/getcontext.S  |  6 +++++
> sysdeps/unix/sysv/linux/riscv/makecontext.c | 19 ++++++++++++++
> sysdeps/unix/sysv/linux/riscv/setcontext.S  | 28 +++++++++++++++++++++
> sysdeps/unix/sysv/linux/riscv/swapcontext.S | 27 +++++++++++++++++++-
> sysdeps/unix/sysv/linux/riscv/sysdep.h      |  2 ++
> 5 files changed, 81 insertions(+), 1 deletion(-)
>
>diff --git a/sysdeps/unix/sysv/linux/riscv/getcontext.S b/sysdeps/unix/sysv/linux/riscv/getcontext.S
>index 86e7a8ff91..e18d317484 100644
>--- a/sysdeps/unix/sysv/linux/riscv/getcontext.S
>+++ b/sysdeps/unix/sysv/linux/riscv/getcontext.S
>@@ -22,6 +22,7 @@
>
> 	.text
> LEAF (__getcontext)
>+	LPAD
> 	SAVE_INT_REG (ra,   0, a0)
> 	SAVE_INT_REG (ra,   1, a0)
> 	SAVE_INT_REG (sp,   2, a0)
>@@ -58,6 +59,11 @@ LEAF (__getcontext)
> 	sw	a1, MCONTEXT_FSR(a0)
> #endif /* __riscv_float_abi_soft */
>
>+#ifdef __riscv_shadow_stack
>+	ssrdp   t0
>+	SAVE_INT_REG (t0,  28, a0)  /* We use t3 slot to store ssp  */A
>+#endif

As I mentioned in my comment of setjmp/longjmp, it's better to save token
on shadow stack itself and then save the pointer in ucontext.

>+
> /* rt_sigprocmask (SIG_BLOCK, NULL, &ucp->uc_sigmask, _NSIG8) */
> 	li	a3, _NSIG8
> 	add     a2, a0, UCONTEXT_SIGMASK
>diff --git a/sysdeps/unix/sysv/linux/riscv/makecontext.c b/sysdeps/unix/sysv/linux/riscv/makecontext.c
>index 3da27dd5df..c88dd83db9 100644
>--- a/sysdeps/unix/sysv/linux/riscv/makecontext.c
>+++ b/sysdeps/unix/sysv/linux/riscv/makecontext.c
>@@ -21,6 +21,7 @@
> #include <sys/ucontext.h>
> #include <stdarg.h>
> #include <assert.h>
>+#include <sys/mman.h>
>
> void
> __makecontext (ucontext_t *ucp, void (*func) (void), int argc,
>@@ -73,6 +74,24 @@ __makecontext (ucontext_t *ucp, void (*func) (void), int argc,
>
>       va_end (vl);
>     }
>+#ifdef __riscv_shadow_stack
>+  /* Allocate shadow stack for the new context
>+     SSP is stored in t3 slot, SS base is stored in t4 slot  */
>+  /* FIXME: we use user space as a temporary solution until
>+     kernel provides such interface  */
>+
>+  unsigned long ss_size = ucp->uc_stack.ss_size >>
>+			  STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT;
>+  unsigned long ss_page = (ss_size + 4096 - 1) / 4096 + 2;
>+  ss_size = (ss_page - 2) * 4096;
>+  void *ssp = __mmap (NULL, ss_page * 4096, PROT_NONE,
>+                      MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
>+  unsigned long ss_base = (unsigned long) ssp + 4096;
>+  ucp->uc_mcontext.__gregs[REG_PC + 29] = ss_base;
>+  __mprotect ((void *) ss_base, ss_size, PROT_READ | PROT_WRITE);
>+  ucp->uc_mcontext.__gregs[REG_PC + 28] = ss_base + ss_size
>+	           - sizeof (unsigned long);
>+#endif

As I said earlier that `map_shadow_stack` syscall can be used to create a
shadow stack mapping. You can specify if you want kernel to create a token
at the base of shadow stack as part of `map_shadow_stack` arguments.
I imagine that once that is done, then caller of `__makecontext` should
populate appropriate field in `ucontext_t` (that's we need a proper place
holder in ucontext_t)

> }
>
> weak_alias (__makecontext, makecontext)
>diff --git a/sysdeps/unix/sysv/linux/riscv/setcontext.S b/sysdeps/unix/sysv/linux/riscv/setcontext.S
>index a2de57b537..f46115a310 100644
>--- a/sysdeps/unix/sysv/linux/riscv/setcontext.S
>+++ b/sysdeps/unix/sysv/linux/riscv/setcontext.S
>@@ -29,6 +29,7 @@
>
> 	.text
> LEAF (__setcontext)
>+	LPAD
>
> 	mv	t0, a0	/* Save ucp into t0.  */
>
>@@ -45,6 +46,17 @@ LEAF (__setcontext)
>
> 	cfi_def_cfa (t0, 0)
>
>+#ifdef __riscv_shadow_stack
>+	/* Skip if shadow stack is not enabled  */
>+	ssrdp	t2
>+	beqz	t2, .Lfin
>+	/* We are safe to adjust shadow stack after the sanity check  */
>+	RESTORE_INT_REG	   (t1,   28, t0)
>+	/* FIXME: We are skipping ANY security check for now  */
>+	csrw	ssp, t1
>+.Lfin:
>+#endif
>+
> #ifndef __riscv_float_abi_soft
> 	lw	t1, MCONTEXT_FSR(t0)
>
>@@ -66,7 +78,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 +106,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 */
>+	jr	t2
>+#else
> 	jr	t1
>+#endif
>
> 99:	tail	__syscall_error
>
>@@ -99,12 +120,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 */
>+	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 bf5754c8b5..84f77db56a 100644
>--- a/sysdeps/unix/sysv/linux/riscv/swapcontext.S
>+++ b/sysdeps/unix/sysv/linux/riscv/swapcontext.S
>@@ -21,6 +21,7 @@
> /* 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 +60,11 @@ LEAF (__swapcontext)
> 	sw	a1, MCONTEXT_FSR(a0)
> #endif /* __riscv_float_abi_soft */
>
>+#ifdef __riscv_shadow_stack
>+	ssrdp   t1
>+	SAVE_INT_REG (t1,  28, a0)
>+#endif
>+
> /* rt_sigprocmask (SIG_SETMASK, &ucp->uc_sigmask, &oucp->uc_sigmask, _NSIG8) */
> 	li	a3, _NSIG8
> 	add	a2, a0, UCONTEXT_SIGMASK
>@@ -70,6 +76,17 @@ LEAF (__swapcontext)
>
> 	bltz	a0, 99f
>
>+#ifdef __riscv_shadow_stack
>+	/* Skip if shadow stack is not enabled  */
>+	ssrdp	t2
>+	beqz	t2, .Lfin
>+	/* We are safe to adjust shadow stack after the sanity check  */
>+	RESTORE_INT_REG (t1,   28, t0)
>+	/* FIXME: We are skipping ANY security check for now  */
>+	csrw	ssp, t1
>+.Lfin:
>+#endif
>+
> #ifndef __riscv_float_abi_soft
> 	lw	t1, MCONTEXT_FSR(t0)
>
>@@ -91,7 +108,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 +136,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 */
>+	jr	t2
>+#else
> 	jr	t1
>-
>+#endif

Same comments for swapcontext and setcontext.

>
> 99:	tail	__syscall_error
>
>diff --git a/sysdeps/unix/sysv/linux/riscv/sysdep.h b/sysdeps/unix/sysv/linux/riscv/sysdep.h
>index a374dbd431..43055097fc 100644
>--- a/sysdeps/unix/sysv/linux/riscv/sysdep.h
>+++ b/sysdeps/unix/sysv/linux/riscv/sysdep.h
>@@ -210,6 +210,8 @@ GNU_PROPERTY (FEATURE_1_AND, __VALUE_FOR_FEATURE_1_AND)
>
> #else /* !__ASSEMBLER__ */
>
>+# define STACK_SIZE_TO_SHADOW_STACK_SIZE_SHIFT 5
>+
> # if __WORDSIZE == 64
> #  define VDSO_NAME	"LINUX_4.15"
> #  define VDSO_HASH	182943605
>-- 
>2.39.3
>


More information about the Libc-alpha mailing list