Skip to content
Open
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
78 changes: 72 additions & 6 deletions compiler-rt/lib/builtins/gcc_personality_v0.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,51 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
_Unwind_Personality_Fn);
#endif

#if __has_feature(ptrauth_calls)
Copy link
Contributor

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:

#if __has_feature(ptrauth_calls) && __has_feature(ptrauth_returns)
#define LIBUNWIND_PTRAUTH_CALLS_AND_RETURNS
#elif __has_feature(ptrauth_calls) || __has_feature(ptrauth_returns)
#error "Either both or none of ptrauth_calls and ptrauth_returns is allowed to be enabled"
#endif

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.

#include <ptrauth.h>

#if __has_feature(ptrauth_restricted_intptr_qualifier)
#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \
discriminator) \
__ptrauth_restricted_intptr(key, addressDiscriminated, discriminator)
#else
#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \
discriminator) \
__ptrauth(key, addressDiscriminated, discriminator)
#endif
#else
#define __ptrauth_gcc_personality_intptr(...)
#endif

#define __ptrauth_gcc_personality_func_key ptrauth_key_function_pointer

// ptrauth_string_discriminator("__gcc_personality_v0'funcStart") == 0xDFEB
#define __ptrauth_gcc_personality_func_start \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0xDFEB)

// ptrauth_string_discriminator("__gcc_personality_v0'start") == 0x52DC
#define __ptrauth_gcc_personality_start \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0x52DC)

// ptrauth_string_discriminator("__gcc_personality_v0'length") == 0xFFF7
#define __ptrauth_gcc_personality_length \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0xFFF7)

// ptrauth_string_discriminator("__gcc_personality_v0'landingPadOffset") ==
// 0x6498
#define __ptrauth_gcc_personality_lpoffset \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
0x6498)

// ptrauth_string_discriminator("__gcc_personality_v0'landingPad") == 0xA134
#define __ptrauth_gcc_personality_lpad_disc 0xA134
#define __ptrauth_gcc_personality_lpad \
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
__ptrauth_gcc_personality_lpad_disc)

// Pointer encodings documented at:
// http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html

Expand Down Expand Up @@ -205,7 +250,8 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
return continueUnwind(exceptionObject, context);

uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
uintptr_t __ptrauth_gcc_personality_func_start funcStart =
(uintptr_t)_Unwind_GetRegionStart(context);
uintptr_t pcOffset = pc - funcStart;

// Parse LSDA header.
Expand All @@ -224,11 +270,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
const uint8_t *p = callSiteTableStart;
while (p < callSiteTableEnd) {
uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
size_t length = readEncodedPointer(&p, callSiteEncoding);
size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
uintptr_t __ptrauth_gcc_personality_start start =
readEncodedPointer(&p, callSiteEncoding);
size_t __ptrauth_gcc_personality_length length =
readEncodedPointer(&p, callSiteEncoding);
size_t __ptrauth_gcc_personality_lpoffset landingPadOffset =
readEncodedPointer(&p, callSiteEncoding);
readULEB128(&p); // action value not used for C code
if (landingPad == 0)
if (landingPadOffset == 0)
continue; // no landing pad for this entry
if ((start <= pcOffset) && (pcOffset < (start + length))) {
// Found landing pad for the PC.
Expand All @@ -238,7 +287,24 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
(uintptr_t)exceptionObject);
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
_Unwind_SetIP(context, (funcStart + landingPad));
size_t __ptrauth_gcc_personality_lpad landingPad =
funcStart + landingPadOffset;
#if __has_feature(ptrauth_calls)
uintptr_t stackPointer = _Unwind_GetGR(context, -2);
const uintptr_t existingDiscriminator = ptrauth_blend_discriminator(
&landingPad, __ptrauth_gcc_personality_lpad_disc);
// newIP is authenticated as if it were qualified with a pseudo qualifier
// along the lines of:
// __ptrauth(ptrauth_key_return_address, <stackPointer>, 0)
// where the stack pointer is used in place of the strict storage
// address.
uintptr_t newIP = (uintptr_t)ptrauth_auth_and_resign(
*(void **)&landingPad, __ptrauth_gcc_personality_func_key,
existingDiscriminator, ptrauth_key_return_address, stackPointer);
_Unwind_SetIP(context, newIP);
#else
_Unwind_SetIP(context, landingPad);
#endif
return _URC_INSTALL_CONTEXT;
}
}
Expand Down
39 changes: 39 additions & 0 deletions libcxxabi/include/__cxxabi_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,45 @@
#define _LIBCXXABI_DTOR_FUNC
#endif

#if __has_include(<ptrauth.h>)
# include <ptrauth.h>
#endif

#if __has_feature(ptrauth_calls)

// ptrauth_string_discriminator("__cxa_exception::actionRecord") == 0xFC91
# define __ptrauth_cxxabi_action_record __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFC91)

// ptrauth_string_discriminator("__cxa_exception::languageSpecificData") == 0xE8EE
# define __ptrauth_cxxabi_lsd __ptrauth(ptrauth_key_process_dependent_data, 1, 0xE8EE)

// ptrauth_string_discriminator("__cxa_exception::catchTemp") == 0xFA58
# define __ptrauth_cxxabi_catch_temp __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFA58)

// ptrauth_string_discriminator("__cxa_exception::adjustedPtr") == 0x99E4
# define __ptrauth_cxxabi_adjusted_ptr __ptrauth(ptrauth_key_process_dependent_data, 1, 0x99E4)

// ptrauth_string_discriminator("__cxa_exception::unexpectedHandler") == 0x99A9
# define __ptrauth_cxxabi_unexpected_handler __ptrauth(ptrauth_key_function_pointer, 1, 0x99A9)

// ptrauth_string_discriminator("__cxa_exception::terminateHandler") == 0x0886)
# define __ptrauth_cxxabi_terminate_handler __ptrauth(ptrauth_key_function_pointer, 1, 0x886)

// ptrauth_string_discriminator("__cxa_exception::exceptionDestructor") == 0xC088
# define __ptrauth_cxxabi_exception_destructor __ptrauth(ptrauth_key_function_pointer, 1, 0xC088)

#else

# define __ptrauth_cxxabi_action_record
# define __ptrauth_cxxabi_lsd
# define __ptrauth_cxxabi_catch_temp
# define __ptrauth_cxxabi_adjusted_ptr
# define __ptrauth_cxxabi_unexpected_handler
# define __ptrauth_cxxabi_terminate_handler
# define __ptrauth_cxxabi_exception_destructor

#endif

#if __cplusplus < 201103L
# define _LIBCXXABI_NOEXCEPT throw()
#else
Expand Down
4 changes: 3 additions & 1 deletion libcxxabi/src/cxa_exception.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,9 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() {
std::terminate();
__cxa_exception *exception_header =
static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
::memset(exception_header, 0, actual_size);
// We warn on memset to a non-trivially castable type. We might want to
// change that diagnostic to not fire on a trivially obvious zero fill.
::memset(static_cast<void*>(exception_header), 0, actual_size);
return thrown_object_from_cxa_exception(exception_header);
}

Expand Down
31 changes: 17 additions & 14 deletions libcxxabi/src/cxa_exception.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
// In Wasm, a destructor returns its argument
void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
#else
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
#endif
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;

__cxa_exception *nextException;

Expand All @@ -61,10 +61,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
int propagationCount;
#else
int handlerSwitchValue;
const unsigned char *actionRecord;
const unsigned char *languageSpecificData;
void *catchTemp;
void *adjustedPtr;
const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
void *__ptrauth_cxxabi_catch_temp catchTemp;
void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
#endif

#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
Expand All @@ -79,16 +79,18 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
// The layout of this structure MUST match the layout of __cxa_exception, with
// primaryException instead of referenceCount.
// The tags used in the pointer authentication qualifiers also need to match
// those of the corresponding members in __cxa_exception.
struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
void* reserve; // padding.
void* primaryException;
#endif

std::type_info *exceptionType;
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
std::unexpected_handler unexpectedHandler;
std::terminate_handler terminateHandler;
void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;

__cxa_exception *nextException;

Expand All @@ -99,10 +101,11 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
int propagationCount;
#else
int handlerSwitchValue;
const unsigned char *actionRecord;
const unsigned char *languageSpecificData;
void * catchTemp;
void *adjustedPtr;

const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
void *__ptrauth_cxxabi_catch_temp catchTemp;
void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
#endif

#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
Expand Down
102 changes: 93 additions & 9 deletions libcxxabi/src/cxa_personality.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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_qualifier)
# 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
Expand Down Expand Up @@ -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,
Expand All @@ -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) {
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,
Expand All @@ -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);
// 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
_Unwind_SetIP(context, results.landingPad);
#endif
}

/*
Expand Down Expand Up @@ -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__
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down
Loading
Loading