-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[runtimes][PAC] Harden unwinding when possible #143230
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 15 commits
57546b2
dab099b
65a72ab
c6cfb8e
3d79bd4
5b09bc5
ee9689b
61ec1ad
26b7d70
d6375dd
972edcb
fd5c9f7
ad625da
5c0e448
6ceef4f
a3a09f0
4d76220
44b5f58
5119926
2c1ffa2
915f21e
2b81a19
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,7 +20,44 @@ | |
#include "cxa_exception.h" | ||
#include "cxa_handlers.h" | ||
#include "private_typeinfo.h" | ||
#include "unwind.h" | ||
|
||
#if __has_feature(ptrauth_calls) | ||
|
||
// CXXABI depends on defintions in libunwind as pointer auth couples the | ||
// definitions | ||
# include "libunwind.h" | ||
|
||
// The actual value of the discriminators listed below is not important. | ||
// The derivation of the constants is only being included for the purpose | ||
// of maintaining a record of how they were originally produced. | ||
|
||
// ptrauth_string_discriminator("scan_results::languageSpecificData") == 0xE50D) | ||
# define __ptrauth_scan_results_lsd __ptrauth(ptrauth_key_process_dependent_code, 1, 0xE50D) | ||
|
||
// ptrauth_string_discriminator("scan_results::actionRecord") == 0x9823 | ||
# define __ptrauth_scan_results_action_record __ptrauth(ptrauth_key_process_dependent_code, 1, 0x9823) | ||
|
||
// scan result is broken up as we have a manual re-sign that requires each component | ||
# define __ptrauth_scan_results_landingpad_key ptrauth_key_process_dependent_code | ||
// ptrauth_string_discriminator("scan_results::landingPad") == 0xD27C | ||
# define __ptrauth_scan_results_landingpad_disc 0xD27C | ||
# define __ptrauth_scan_results_landingpad \ | ||
__ptrauth(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc) | ||
|
||
# if __has_extension(__ptrauth_restricted_intptr) | ||
# define __ptrauth_scan_results_landingpad_intptr \ | ||
__ptrauth_restricted_intptr(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc) | ||
# else | ||
# define __ptrauth_scan_results_landingpad_intptr \ | ||
__ptrauth(__ptrauth_scan_results_landingpad_key, 1, __ptrauth_scan_results_landingpad_disc) | ||
# endif | ||
|
||
#else | ||
# define __ptrauth_scan_results_lsd | ||
# define __ptrauth_scan_results_action_record | ||
# define __ptrauth_scan_results_landingpad | ||
# define __ptrauth_scan_results_landingpad_intptr | ||
#endif | ||
|
||
// TODO: This is a temporary workaround for libc++abi to recognize that it's being | ||
// built against LLVM's libunwind. LLVM's libunwind started reporting _LIBUNWIND_VERSION | ||
|
@@ -527,12 +564,17 @@ get_thrown_object_ptr(_Unwind_Exception* unwind_exception) | |
namespace | ||
{ | ||
|
||
typedef const uint8_t *__ptrauth_scan_results_lsd lsd_ptr_t; | ||
typedef const uint8_t *__ptrauth_scan_results_action_record action_ptr_t; | ||
typedef uintptr_t __ptrauth_scan_results_landingpad_intptr landing_pad_t; | ||
typedef void *__ptrauth_scan_results_landingpad landing_pad_ptr_t; | ||
|
||
struct scan_results | ||
{ | ||
int64_t ttypeIndex; // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup | ||
const uint8_t* actionRecord; // Currently unused. Retained to ease future maintenance. | ||
const uint8_t* languageSpecificData; // Needed only for __cxa_call_unexpected | ||
uintptr_t landingPad; // null -> nothing found, else something found | ||
action_ptr_t actionRecord; // Currently unused. Retained to ease future maintenance. | ||
lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected | ||
landing_pad_t landingPad; // null -> nothing found, else something found | ||
void* adjustedPtr; // Used in cxa_exception.cpp | ||
_Unwind_Reason_Code reason; // One of _URC_FATAL_PHASE1_ERROR, | ||
// _URC_FATAL_PHASE2_ERROR, | ||
|
@@ -541,7 +583,38 @@ struct scan_results | |
}; | ||
|
||
} // unnamed namespace | ||
} // extern "C" | ||
|
||
#if !defined(_LIBCXXABI_ARM_EHABI) | ||
namespace { | ||
// The logical model for casting authenticated function pointers makes | ||
// it impossible to directly cast them without breaking the authentication, | ||
// as a result we need this pair of helpers. | ||
// | ||
// __ptrauth_nop_cast cannot be used here as the authentication schemas include | ||
// address diversification. | ||
template <typename PtrType> | ||
void set_landing_pad_as_ptr(scan_results& results, const PtrType& out) { | ||
kovdan01 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
union { | ||
landing_pad_t* as_landing_pad; | ||
landing_pad_ptr_t* as_pointer; | ||
} u; | ||
u.as_landing_pad = &results.landingPad; | ||
*u.as_pointer = out; | ||
} | ||
|
||
static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) { | ||
union { | ||
const landing_pad_t* as_landing_pad; | ||
const landing_pad_ptr_t* as_pointer; | ||
} u; | ||
u.as_landing_pad = &results.landingPad; | ||
return *u.as_pointer; | ||
} | ||
} // unnamed namespace | ||
#endif | ||
|
||
extern "C" { | ||
static | ||
void | ||
set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, | ||
|
@@ -557,7 +630,19 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, | |
reinterpret_cast<uintptr_t>(unwind_exception)); | ||
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), | ||
static_cast<uintptr_t>(results.ttypeIndex)); | ||
#if __has_feature(ptrauth_calls) | ||
auto stackPointer = _Unwind_GetGR(context, UNW_REG_SP); | ||
kovdan01 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// We manually re-sign the IP as the __ptrauth qualifiers cannot | ||
// express the required relationship with the destination address | ||
const auto existingDiscriminator = | ||
ptrauth_blend_discriminator(&results.landingPad, __ptrauth_scan_results_landingpad_disc); | ||
unw_word_t newIP /* opaque __ptrauth(ptrauth_key_return_address, stackPointer, 0) */ = | ||
(unw_word_t)ptrauth_auth_and_resign(*(void* const*)&results.landingPad, __ptrauth_scan_results_landingpad_key, | ||
existingDiscriminator, ptrauth_key_return_address, stackPointer); | ||
_Unwind_SetIP(context, newIP); | ||
#else | ||
kovdan01 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
_Unwind_SetIP(context, results.landingPad); | ||
#endif | ||
} | ||
|
||
/* | ||
|
@@ -691,12 +776,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, | |
// The call sites are ordered in increasing value of start | ||
uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding); | ||
uintptr_t length = readEncodedPointer(&callSitePtr, callSiteEncoding); | ||
uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); | ||
landing_pad_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); | ||
uintptr_t actionEntry = readULEB128(&callSitePtr); | ||
if ((start <= ipOffset) && (ipOffset < (start + length))) | ||
#else // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__ | ||
// ip is 1-based index into this table | ||
uintptr_t landingPad = readULEB128(&callSitePtr); | ||
landing_pad_t landingPad = readULEB128(&callSitePtr); | ||
uintptr_t actionEntry = readULEB128(&callSitePtr); | ||
if (--ip == 0) | ||
#endif // __USING_SJLJ_EXCEPTIONS__ || __WASM_EXCEPTIONS__ | ||
|
@@ -935,8 +1020,7 @@ __gxx_personality_v0 | |
results.ttypeIndex = exception_header->handlerSwitchValue; | ||
results.actionRecord = exception_header->actionRecord; | ||
results.languageSpecificData = exception_header->languageSpecificData; | ||
results.landingPad = | ||
reinterpret_cast<uintptr_t>(exception_header->catchTemp); | ||
set_landing_pad_as_ptr(results, exception_header->catchTemp); | ||
results.adjustedPtr = exception_header->adjustedPtr; | ||
|
||
// Jump to the handler. | ||
|
@@ -970,7 +1054,7 @@ __gxx_personality_v0 | |
exc->handlerSwitchValue = static_cast<int>(results.ttypeIndex); | ||
exc->actionRecord = results.actionRecord; | ||
exc->languageSpecificData = results.languageSpecificData; | ||
exc->catchTemp = reinterpret_cast<void*>(results.landingPad); | ||
exc->catchTemp = get_landing_pad_as_ptr(results); | ||
exc->adjustedPtr = results.adjustedPtr; | ||
#ifdef __WASM_EXCEPTIONS__ | ||
// Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As discussed previously, let's use the new macro
LIBUNWIND_PTRAUTH_CALLS_AND_RETURNS
defined as follows everywhere instead of__has_include(<ptrauth.h>)
,__has_feature(ptrauth_calls)
,__has_feature(ptrauth_returns)
,__has_extension(ptrauth_qualifier)
, etc:See proposed fix in commit 644405b in my branch https://github.com/kovdan01/llvm-project/commits/pointer-authenticated-unwinding-2025-09-22-with-fixes/.
I think this should be done in scope of this PR.