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

Jesse Huang jesse.huang@sifive.com
Fri Jul 11 13:52:51 GMT 2025


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