[PATCH v2 10/14] riscv/cfi: Adjust setjmp/longjmp for shadow stack to work

Deepak Gupta debug@rivosinc.com
Tue Jul 22 21:50:32 GMT 2025


On Fri, Jul 11, 2025 at 06:52:51AM -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   | 28 ++++++++++++++++++++++++++++
> sysdeps/riscv/bits/setjmp.h |  4 ++++
> sysdeps/riscv/setjmp.S      | 10 ++++++++++
> 3 files changed, 42 insertions(+)
>
>diff --git a/sysdeps/riscv/__longjmp.S b/sysdeps/riscv/__longjmp.S
>index 47ff3aa09e..1aa8a235d7 100644
>--- a/sysdeps/riscv/__longjmp.S
>+++ b/sysdeps/riscv/__longjmp.S
>@@ -51,6 +51,34 @@ ENTRY (__longjmp)
> 	FREG_L fs11,14*SZREG+11*SZFREG(a0)
> #endif
>
>+#ifdef __riscv_shadow_stack
>+	/* skip unwinding if ss is not enabled  */
>+	ssrdp t0
>+	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:
>+	bleu  t1, t0, .Lunwind_fin
>+	/* 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
>+	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

Why conditionally change size of this structure?
I think we should keep size of jmp_buf static in nature as far as ssp
is concerned.


>   } __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
>+# 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