Skip to content

Commit 4db6871

Browse files
committed
[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 <[email protected]>
1 parent b17b25d commit 4db6871

File tree

1 file changed

+19
-0
lines changed

1 file changed

+19
-0
lines changed

libunwind/src/UnwindLevel1.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
__unw_resume((cursor)); \
5151
} while (0)
5252
#elif defined(_LIBUNWIND_TARGET_I386)
53+
#define __cet_ss_step_size 4
5354
#define __unw_phase2_resume(cursor, fn) \
5455
do { \
5556
_LIBUNWIND_POP_CET_SSP((fn)); \
@@ -61,6 +62,7 @@
6162
"d"(cetJumpAddress)); \
6263
} while (0)
6364
#elif defined(_LIBUNWIND_TARGET_X86_64)
65+
#define __cet_ss_step_size 8
6466
#define __unw_phase2_resume(cursor, fn) \
6567
do { \
6668
_LIBUNWIND_POP_CET_SSP((fn)); \
@@ -177,6 +179,9 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
177179
// uc is initialized by __unw_getcontext in the parent frame. The first stack
178180
// frame walked is unwind_phase2.
179181
unsigned framesWalked = 1;
182+
#ifdef _LIBUNWIND_USE_CET
183+
unsigned long shadowStackTop = _get_ssp();
184+
#endif
180185
// Walk each frame until we reach where search phase said to stop.
181186
while (true) {
182187

@@ -228,6 +233,20 @@ unwind_phase2(unw_context_t *uc, unw_cursor_t *cursor, _Unwind_Exception *except
228233
}
229234
#endif
230235

236+
// In CET enabled environment, we check return address stored in normal stack
237+
// against return address stored in CET shadow stack, if the 2 addresses don't
238+
// match, it means return address in normal stack has been corrupted, we return
239+
// _URC_FATAL_PHASE2_ERROR.
240+
#ifdef _LIBUNWIND_USE_CET
241+
if (shadowStackTop != 0) {
242+
unw_word_t retInNormalStack;
243+
__unw_get_reg(cursor, UNW_REG_IP, &retInNormalStack);
244+
unsigned long retInShadowStack = *(
245+
unsigned long *)(shadowStackTop + __cet_ss_step_size * framesWalked);
246+
if (retInNormalStack != retInShadowStack)
247+
return _URC_FATAL_PHASE2_ERROR;
248+
}
249+
#endif
231250
++framesWalked;
232251
// If there is a personality routine, tell it we are unwinding.
233252
if (frameInfo.handler != 0) {

0 commit comments

Comments
 (0)