[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