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

xiongji90 via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Tue Oct 25 01:30:58 PDT 2022


xiongji90 created this revision.
xiongji90 added a reviewer: hjl.tools.
Herald added projects: libunwind, All.
Herald added a subscriber: libcxx-commits.
Herald added a reviewer: libunwind.
xiongji90 requested review of this revision.
Herald added a project: LLVM.
Herald added a subscriber: llvm-commits.

If CET shadow stack is enabled, we will count the number of stack frames skipped and adjust CET shadow stack based on the number in libunwind unwind_phase2 and unwind_phase2_forced. When unwinding stack, we can compare the return address in normal stack against counterpart in CET shadow stack, if they don't match, it means the return address stored in normal stack has been corrupted, we will return _URC_FATAL_PHASE2_ERROR in that case. We don't check for non-catchable exception since such exceptions will lead to process termination.


Repository:
  rG LLVM Github Monorepo

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.470402.patch
Type: text/x-patch
Size: 3336 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20221025/fd579bb5/attachment.bin>


More information about the llvm-commits mailing list