[PATCH 10/12] riscv/cfi: Adjust setjmp/longjmp for shadow stack to work
Deepak Gupta
debug@rivosinc.com
Wed Jun 18 19:18:50 GMT 2025
Hi Jesse,
Thanks for taking the lead.
Can we do save and restore a bit differently using a token mechanism.
On Wed, Jun 18, 2025 at 01:42:56AM -0700, Jesse Huang wrote:
>Since longjmp to a previous setjmp'ed state could change the stack
>frame and involves stack frame unwinding, shadow stacks is also required
>to be unwinded.
>
>The unwinding is implemented according to the zicfiss spec by increasing
>the ssp by a page size (4K) at most, to prevent from accidentally point
>to another legal shadow stack page after the adjustment.
>---
> sysdeps/riscv/__longjmp.S | 30 ++++++++++++++++++++++++++++++
> sysdeps/riscv/bits/setjmp.h | 4 ++++
> sysdeps/riscv/setjmp.S | 10 ++++++++++
> 3 files changed, 44 insertions(+)
>
>diff --git a/sysdeps/riscv/__longjmp.S b/sysdeps/riscv/__longjmp.S
>index 47ff3aa09e..3f1fc3148d 100644
>--- a/sysdeps/riscv/__longjmp.S
>+++ b/sysdeps/riscv/__longjmp.S
>@@ -51,6 +51,36 @@ ENTRY (__longjmp)
> FREG_L fs11,14*SZREG+11*SZFREG(a0)
> #endif
>
>+#ifdef __riscv_shadow_stack
>+ /* read ssp into t0 */
>+ ssrdp t0
>+ /* skip unwinding if ss is not enabled */
>+ beqz t0, .Lunwind_fin
>+# ifndef __riscv_float_abi_soft
>+ REG_L t1, 14*SZREG+12*SZFREG(a0)
>+# else
>+ REG_L t1, 14*SZREG(a0)
>+# endif
>+.Lunwind:
>+ /* should not be taken in normal condition */
>+ bleu t1, t0, .Lunwind_fin
>+ /* The unwinding algorithm came from the shadow_stack spec, increase ssp
>+ by at most a page size to ensure always run into a guard page
>+ before accidentally point to another legal shadow stack page */
>+ /* t0 = (t1 - t0 >= 4096) ? t0 + 4096 : t1 */
>+ lui a0, 1
>+ add t0, t0, a0
>+ bleu t0, t1, 1f
>+ mv t0, t1
>+1:
>+ csrw ssp, t0
>+ /* Test if the location pointed by ssp is legal */
>+ sspush x5
>+ sspopchk x5
Above is useful in C++ exception unwinding where a lot of other stuff gets
unwinded too (registers, etc) as per static information in DWARF (I think its
in dwarf)
In case of setjmp/longjmp, we can use shadow stack token mechainsm.
We can do below instead to restore shadow stack pointer (see save token
in my comments in setjmp)
ssrdp t0
beqz t0, .Lskip_ss_token_rstor
/*
* non-zero t0 means shadow stack is enabled. thus ssamoswap/csrw to
* ssp won't fault.
*/
REG_L t0, 14*SZREG(a0) /* get the saved ss pointer */
ssamoswap t1, x0, (t0) /* Get the saved token, and store 0 */
addi t0, t0, 8 /* increment ss pointer */
bneq t0, t1, fatal /* ss ptr and token must match */
csrw ssp, t0 /* we did validation and restoring ssp correctly */
.Lskip_ss_token_rstor:
fatal:
terminate or recovery action
>+ j .Lunwind
>+.Lunwind_fin:
>+#endif
>+
> seqz a0, a1
> add a0, a0, a1 # a0 = (a1 == 0) ? 1 : a1
> ret
>diff --git a/sysdeps/riscv/bits/setjmp.h b/sysdeps/riscv/bits/setjmp.h
>index 5ebbec393a..5cbc12fa3d 100644
>--- a/sysdeps/riscv/bits/setjmp.h
>+++ b/sysdeps/riscv/bits/setjmp.h
>@@ -33,6 +33,10 @@ typedef struct __jmp_buf_internal_tag
> double __fpregs[12];
> #elif !defined __riscv_float_abi_soft
> # error unsupported FLEN
>+#endif
>+#ifdef __riscv_shadow_stack
>+ /* Shadow stack pointer. */
>+ long int __ssp;
> #endif
> } __jmp_buf[1];
>
>diff --git a/sysdeps/riscv/setjmp.S b/sysdeps/riscv/setjmp.S
>index df048cb544..f547bc0238 100644
>--- a/sysdeps/riscv/setjmp.S
>+++ b/sysdeps/riscv/setjmp.S
>@@ -61,6 +61,16 @@ ENTRY (__sigsetjmp)
> FREG_S fs11,14*SZREG+11*SZFREG(a0)
> #endif
>
>+#ifdef __riscv_shadow_stack
>+ /* read ssp into t0 */
>+ ssrdp t0
It will be better if we do something like below to save shadow stack pointer
as token on shadow stack itself.
ssrdp t0
beqz t0, .Lskip_ss_token_prep
mv t1, t0 /* record current ss pointer in t1 */
addi t0, t0, -8 /* decrement current ss pointer by 8 */
ssamoswap x0, t1, (t0) /* save away current ss pointer on ss itself */
.Lskip_ss_token_prep:
>+# ifndef __riscv_float_abi_soft
>+ REG_S t0, 14*SZREG+12*SZFREG(a0)
>+# else
>+ REG_S t0, 14*SZREG(a0)
>+# endif
>+#endif
>+
> #if !IS_IN (libc) && IS_IN (rtld)
> /* In ld.so we never save the signal mask. */
> li a0, 0
>--
>2.39.3
>
More information about the Libc-alpha
mailing list