[libcxx-commits] [PATCH] D136667: Check return address stored in normal stack and CET shadow stack in unwind process phase2

xiongji90 via Phabricator via libcxx-commits libcxx-commits at lists.llvm.org
Tue Nov 1 01:10:50 PDT 2022


xiongji90 updated this revision to Diff 472225.

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D136667/new/

https://reviews.llvm.org/D136667

Files:
  libunwind/src/UnwindLevel1.c


Index: libunwind/src/UnwindLevel1.c
===================================================================
--- libunwind/src/UnwindLevel1.c
+++ libunwind/src/UnwindLevel1.c
@@ -50,6 +50,7 @@
     __unw_resume((cursor));                                                    \
   } while (0)
 #elif defined(_LIBUNWIND_TARGET_I386)
+#define __cet_ss_step_size 4
 #define __unw_phase2_resume(cursor, fn)                                        \
   do {                                                                         \
     _LIBUNWIND_POP_CET_SSP((fn));                                              \
@@ -61,6 +62,7 @@
                      "d"(cetJumpAddress));                                     \
   } while (0)
 #elif defined(_LIBUNWIND_TARGET_X86_64)
+#define __cet_ss_step_size 8
 #define __unw_phase2_resume(cursor, fn)                                        \
   do {                                                                         \
     _LIBUNWIND_POP_CET_SSP((fn));                                              \
@@ -177,6 +179,9 @@
   // uc is initialized by __unw_getcontext in the parent frame. The first stack
   // frame walked is unwind_phase2.
   unsigned framesWalked = 1;
+#if defined(_LIBUNWIND_USE_CET)
+  unsigned long shadowStackTop = _get_ssp();
+#endif
   // Walk each frame until we reach where search phase said to stop.
   while (true) {
 
@@ -228,6 +233,21 @@
     }
 #endif
 
+// In CET enabled environment, we check return address stored in normal stack
+// agains return address stored in CET shadow stack, if the 2 addresses don't
+// match, it means return address in normal stack has been corrupted, we return
+// _URC_FATAL_PHASE2_ERROR. We don't do that check for non-catchable exception
+// since process will be terminated.
+#if defined(_LIBUNWIND_USE_CET)
+    if (shadowStackTop != 0 && exception_object->exception_class != 0) {
+      unw_word_t retInNormalStack;
+      __unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack);
+      unsigned long retInShadowStack = *(
+          unsigned long *)(shadowStackTop + __cet_ss_step_size * framesWalked);
+      if (retInNormalStack != retInShadowStack)
+        return _URC_FATAL_PHASE2_ERROR;
+    }
+#endif
     ++framesWalked;
     // If there is a personality routine, tell it we are unwinding.
     if (frameInfo.handler != 0) {
@@ -295,6 +315,10 @@
   // uc is initialized by __unw_getcontext in the parent frame. The first stack
   // frame walked is unwind_phase2_forced.
   unsigned framesWalked = 1;
+#if defined(_LIBUNWIND_USE_CET)
+  unsigned long shadowStackTop = _get_ssp();
+#endif
+
   // Walk each frame until we reach where search phase said to stop
   while (__unw_step_stage2(cursor) > 0) {
 
@@ -342,6 +366,16 @@
       return _URC_FATAL_PHASE2_ERROR;
     }
 
+#if defined(_LIBUNWIND_USE_CET)
+    if (shadowStackTop != 0 && exception_object->exception_class != 0) {
+      unw_word_t retInNormalStack;
+      __unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack);
+      unsigned long retInShadowStack = *(
+          unsigned long *)(shadowStackTop + __cet_ss_step_size * framesWalked);
+      if (retInNormalStack != retInShadowStack)
+        return _URC_FATAL_PHASE2_ERROR;
+    }
+#endif
     ++framesWalked;
     // If there is a personality routine, tell it we are unwinding.
     if (frameInfo.handler != 0) {


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D136667.472225.patch
Type: text/x-patch
Size: 3336 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/libcxx-commits/attachments/20221101/f529565c/attachment-0001.bin>


More information about the libcxx-commits mailing list