Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion libunwind/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ set(LIBUNWIND_HEADERS
AddressSpace.hpp
assembly.h
CompactUnwinder.hpp
cet_unwind.h
config.h
dwarf2.h
DwarfInstructions.hpp
Expand All @@ -46,6 +45,7 @@ set(LIBUNWIND_HEADERS
libunwind_ext.h
Registers.hpp
RWMutex.hpp
shadow_stack_unwind.h
Unwind-EHABI.h
UnwindCursor.hpp
../include/libunwind.h
Expand Down
8 changes: 4 additions & 4 deletions libunwind/src/Registers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@
#include <stdint.h>
#include <string.h>

#include "cet_unwind.h"
#include "config.h"
#include "libunwind.h"
#include "shadow_stack_unwind.h"

namespace libunwind {

Expand Down Expand Up @@ -48,7 +48,7 @@ class _LIBUNWIND_HIDDEN Registers_x86;
extern "C" void __libunwind_Registers_x86_jumpto(Registers_x86 *);

#if defined(_LIBUNWIND_USE_CET)
extern "C" void *__libunwind_cet_get_jump_target() {
extern "C" void *__libunwind_shstk_get_jump_target() {
return reinterpret_cast<void *>(&__libunwind_Registers_x86_jumpto);
}
#endif
Expand Down Expand Up @@ -268,7 +268,7 @@ class _LIBUNWIND_HIDDEN Registers_x86_64;
extern "C" void __libunwind_Registers_x86_64_jumpto(Registers_x86_64 *);

#if defined(_LIBUNWIND_USE_CET)
extern "C" void *__libunwind_cet_get_jump_target() {
extern "C" void *__libunwind_shstk_get_jump_target() {
return reinterpret_cast<void *>(&__libunwind_Registers_x86_64_jumpto);
}
#endif
Expand Down Expand Up @@ -1817,7 +1817,7 @@ class _LIBUNWIND_HIDDEN Registers_arm64;
extern "C" void __libunwind_Registers_arm64_jumpto(Registers_arm64 *);

#if defined(_LIBUNWIND_USE_GCS)
extern "C" void *__libunwind_cet_get_jump_target() {
extern "C" void *__libunwind_shstk_get_jump_target() {
return reinterpret_cast<void *>(&__libunwind_Registers_arm64_jumpto);
}
#endif
Expand Down
4 changes: 2 additions & 2 deletions libunwind/src/UnwindCursor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
#ifndef __UNWINDCURSOR_HPP__
#define __UNWINDCURSOR_HPP__

#include "cet_unwind.h"
#include "shadow_stack_unwind.h"
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -3122,7 +3122,7 @@ bool UnwindCursor<A, R>::isReadableAddr(const pint_t addr) const {
#endif

#if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS)
extern "C" void *__libunwind_cet_get_registers(unw_cursor_t *cursor) {
extern "C" void *__libunwind_shstk_get_registers(unw_cursor_t *cursor) {
AbstractUnwindCursor *co = (AbstractUnwindCursor *)cursor;
return co->get_registers();
}
Expand Down
63 changes: 33 additions & 30 deletions libunwind/src/UnwindLevel1.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,64 +25,67 @@
#include <stdio.h>
#include <string.h>

#include "cet_unwind.h"
#include "config.h"
#include "libunwind.h"
#include "libunwind_ext.h"
#include "shadow_stack_unwind.h"
#include "unwind.h"

#if !defined(_LIBUNWIND_ARM_EHABI) && !defined(__USING_SJLJ_EXCEPTIONS__) && \
!defined(__wasm__)

#ifndef _LIBUNWIND_SUPPORT_SEH_UNWIND

// When CET is enabled, each "call" instruction will push return address to
// CET shadow stack, each "ret" instruction will pop current CET shadow stack
// top and compare it with target address which program will return.
// In exception handing, some stack frames will be skipped before jumping to
// landing pad and we must adjust CET shadow stack accordingly.
// _LIBUNWIND_POP_CET_SSP is used to adjust CET shadow stack pointer and we
// directly jump to __libunwind_Registers_x86/x86_64_jumpto instead of using
// a regular function call to avoid pushing to CET shadow stack again.
// When shadow stack is enabled, a separate stack containing only return
// addresses would be maintained. On function return, the return address would
// be compared to the popped address from shadow stack to ensure the return
// target is not tempered with. When unwinding, we're skipping the normal return
// procedure for multiple frames and thus need to pop the return addresses of
// the skipped frames from shadow stack to avoid triggering an exception (using
// `_LIBUNWIND_POP_SHSTK_SSP()`). Also, some architectures, like the x86-family
// CET, push the return adddresses onto shadow stack with common call
// instructions, so for these architectures, normal function calls should be
// avoided when invoking the `jumpto()` function. To do this, we use inline
// assemblies to "goto" the `jumpto()` for these architectures.
#if !defined(_LIBUNWIND_USE_CET) && !defined(_LIBUNWIND_USE_GCS)
#define __unw_phase2_resume(cursor, fn) \
do { \
(void)fn; \
__unw_resume((cursor)); \
} while (0)
#elif defined(_LIBUNWIND_TARGET_I386)
#define __cet_ss_step_size 4
#define __shstk_step_size (4)
#define __unw_phase2_resume(cursor, fn) \
do { \
_LIBUNWIND_POP_CET_SSP((fn)); \
void *cetRegContext = __libunwind_cet_get_registers((cursor)); \
void *cetJumpAddress = __libunwind_cet_get_jump_target(); \
_LIBUNWIND_POP_SHSTK_SSP((fn)); \
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
__asm__ volatile("push %%edi\n\t" \
"sub $4, %%esp\n\t" \
"jmp *%%edx\n\t" :: "D"(cetRegContext), \
"d"(cetJumpAddress)); \
"jmp *%%edx\n\t" ::"D"(shstkRegContext), \
"d"(shstkJumpAddress)); \
} while (0)
#elif defined(_LIBUNWIND_TARGET_X86_64)
#define __cet_ss_step_size 8
#define __shstk_step_size (8)
#define __unw_phase2_resume(cursor, fn) \
do { \
_LIBUNWIND_POP_CET_SSP((fn)); \
void *cetRegContext = __libunwind_cet_get_registers((cursor)); \
void *cetJumpAddress = __libunwind_cet_get_jump_target(); \
__asm__ volatile("jmpq *%%rdx\n\t" :: "D"(cetRegContext), \
"d"(cetJumpAddress)); \
_LIBUNWIND_POP_SHSTK_SSP((fn)); \
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
__asm__ volatile("jmpq *%%rdx\n\t" ::"D"(shstkRegContext), \
"d"(shstkJumpAddress)); \
} while (0)
#elif defined(_LIBUNWIND_TARGET_AARCH64)
#define __cet_ss_step_size 8
#define __shstk_step_size (8)
#define __unw_phase2_resume(cursor, fn) \
do { \
_LIBUNWIND_POP_CET_SSP((fn)); \
void *cetRegContext = __libunwind_cet_get_registers((cursor)); \
void *cetJumpAddress = __libunwind_cet_get_jump_target(); \
_LIBUNWIND_POP_SHSTK_SSP((fn)); \
void *shstkRegContext = __libunwind_shstk_get_registers((cursor)); \
void *shstkJumpAddress = __libunwind_shstk_get_jump_target(); \
__asm__ volatile("mov x0, %0\n\t" \
"br %1\n\t" \
: \
: "r"(cetRegContext), "r"(cetJumpAddress) \
: "r"(shstkRegContext), "r"(shstkJumpAddress) \
: "x0"); \
} while (0)
#endif
Expand Down Expand Up @@ -255,16 +258,16 @@ 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
// In shadow stack enabled environment, we check return address stored in normal
// stack against return address stored in 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.
#if defined(_LIBUNWIND_USE_CET) || defined(_LIBUNWIND_USE_GCS)
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);
unsigned long retInShadowStack =
*(unsigned long *)(shadowStackTop + __shstk_step_size * framesWalked);
if (retInNormalStack != retInShadowStack)
return _URC_FATAL_PHASE2_ERROR;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
//
//===----------------------------------------------------------------------===//

#ifndef LIBUNWIND_CET_UNWIND_H
#define LIBUNWIND_CET_UNWIND_H
#ifndef LIBUNWIND_SHADOW_STACK_UNWIND_H
#define LIBUNWIND_SHADOW_STACK_UNWIND_H

#include "libunwind.h"

Expand All @@ -21,7 +21,7 @@
#include <cet.h>
#include <immintrin.h>

#define _LIBUNWIND_POP_CET_SSP(x) \
#define _LIBUNWIND_POP_SHSTK_SSP(x) \
do { \
unsigned long ssp = _get_ssp(); \
if (ssp != 0) { \
Expand All @@ -46,7 +46,7 @@
#define _LIBUNWIND_USE_GCS 1
#endif

#define _LIBUNWIND_POP_CET_SSP(x) \
#define _LIBUNWIND_POP_SHSTK_SSP(x) \
do { \
if (__chkfeat(_CHKFEAT_GCS)) { \
unsigned tmp = (x); \
Expand All @@ -57,7 +57,7 @@

#endif

extern void *__libunwind_cet_get_registers(unw_cursor_t *);
extern void *__libunwind_cet_get_jump_target(void);
extern void *__libunwind_shstk_get_registers(unw_cursor_t *);
extern void *__libunwind_shstk_get_jump_target(void);

#endif