[libunwind] 4db6871 - [libunwind] Check corrupted return address in unwind_phase2 when CET is enabled.

via cfe-commits cfe-commits at lists.llvm.org
Tue Nov 8 22:12:43 PST 2022


Author: jinge90
Date: 2022-11-09T14:27:07+08:00
New Revision: 4db687155bc12f31b5ed122ba1086c5f04838a24

URL: https://github.com/llvm/llvm-project/commit/4db687155bc12f31b5ed122ba1086c5f04838a24
DIFF: https://github.com/llvm/llvm-project/commit/4db687155bc12f31b5ed122ba1086c5f04838a24.diff

LOG: [libunwind] Check corrupted return address in unwind_phase2 when CET is enabled.

If CET shadow stack is enabled, we count the number of stack frames skipped
and adjust CET shadow stack based on the number in libunwind unwind_phase2.
At the same time, we can enhance security via comparing 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 and we
will return _URC_FATAL_PHASE2_ERROR in that case.

Reviewed By: MaskRay
Differential Revision: https://reviews.llvm.org/D136667

Signed-off-by: jinge90 <ge.jin at intel.com>

Added: 
    

Modified: 
    libunwind/src/UnwindLevel1.c

Removed: 
    


################################################################################
diff  --git a/libunwind/src/UnwindLevel1.c b/libunwind/src/UnwindLevel1.c
index 7160680467e42..f984a8bb6adec 100644
--- a/libunwind/src/UnwindLevel1.c
+++ b/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 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
   // uc is initialized by __unw_getcontext in the parent frame. The first stack
   // frame walked is unwind_phase2.
   unsigned framesWalked = 1;
+#ifdef _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,20 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
     }
 #endif
 
+// In CET enabled environment, we check return address stored in normal stack
+// against 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.
+#ifdef _LIBUNWIND_USE_CET
+    if (shadowStackTop != 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) {


        


More information about the cfe-commits mailing list