Skip to content

Commit 0f2679a

Browse files
committed
Fixing remaining issues
Stop using unions to deal with the pointer auth cast semantics, instead perform manual re-signing. This means the templated helper functions no longer need to be templates and so don't need to be in a separated non-extern "C" block. Fixing up the comments.
1 parent 8d7e526 commit 0f2679a

File tree

10 files changed

+110
-100
lines changed

10 files changed

+110
-100
lines changed

libcxxabi/include/__cxxabi_config.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,9 @@
116116
# define __ptrauth_cxxabi_lsd __ptrauth(ptrauth_key_process_dependent_data, 1, 0xE8EE)
117117

118118
// ptrauth_string_discriminator("__cxa_exception::catchTemp") == 0xFA58
119-
# define __ptrauth_cxxabi_catch_temp __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFA58)
119+
# define __ptrauth_cxxabi_catch_temp_disc 0xFA58
120+
# define __ptrauth_cxxabi_catch_temp_key ptrauth_key_process_dependent_data
121+
# define __ptrauth_cxxabi_catch_temp __ptrauth(__ptrauth_cxxabi_catch_temp_key, 1, __ptrauth_cxxabi_catch_temp_disc)
120122

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

libcxxabi/src/cxa_exception.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
7979
// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
8080
// The layout of this structure MUST match the layout of __cxa_exception, with
8181
// primaryException instead of referenceCount.
82-
// The tags used in the pointer authentication qualifiers also need to match
83-
// those of the corresponding members in __cxa_exception.
82+
// The pointer authentication schemas specified here must also match those of
83+
// the corresponding members in __cxa_exception.
8484
struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
8585
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
8686
void* reserve; // padding.
@@ -101,7 +101,6 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
101101
int propagationCount;
102102
#else
103103
int handlerSwitchValue;
104-
105104
const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
106105
const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
107106
void *__ptrauth_cxxabi_catch_temp catchTemp;

libcxxabi/src/cxa_personality.cpp

Lines changed: 63 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -575,9 +575,9 @@ typedef void *__ptrauth_scan_results_landingpad landing_pad_ptr_t;
575575
struct scan_results
576576
{
577577
int64_t ttypeIndex; // > 0 catch handler, < 0 exception spec handler, == 0 a cleanup
578-
action_ptr_t actionRecord; // Currently unused. Retained to ease future maintenance.
579-
lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected
580-
landing_pad_t landingPad; // null -> nothing found, else something found
578+
action_ptr_t actionRecord; // Currently unused. Retained to ease future maintenance.
579+
lsd_ptr_t languageSpecificData; // Needed only for __cxa_call_unexpected
580+
landing_pad_t landingPad; // null -> nothing found, else something found
581581
void* adjustedPtr; // Used in cxa_exception.cpp
582582
_Unwind_Reason_Code reason; // One of _URC_FATAL_PHASE1_ERROR,
583583
// _URC_FATAL_PHASE2_ERROR,
@@ -586,38 +586,7 @@ struct scan_results
586586
};
587587

588588
} // unnamed namespace
589-
} // extern "C"
590-
591-
#if !defined(_LIBCXXABI_ARM_EHABI)
592-
namespace {
593-
// The logical model for casting authenticated function pointers makes
594-
// it impossible to directly cast them without breaking the authentication,
595-
// as a result we need this pair of helpers.
596-
//
597-
// __ptrauth_nop_cast cannot be used here as the authentication schemas include
598-
// address diversification.
599-
template <typename PtrType>
600-
void set_landing_pad_as_ptr(scan_results& results, const PtrType& landingPad) {
601-
union {
602-
landing_pad_t* as_landing_pad;
603-
landing_pad_ptr_t* as_pointer;
604-
} u;
605-
u.as_landing_pad = &results.landingPad;
606-
*u.as_pointer = landingPad;
607-
}
608589

609-
static const landing_pad_ptr_t& get_landing_pad_as_ptr(const scan_results& results) {
610-
union {
611-
const landing_pad_t* as_landing_pad;
612-
const landing_pad_ptr_t* as_pointer;
613-
} u;
614-
u.as_landing_pad = &results.landingPad;
615-
return *u.as_pointer;
616-
}
617-
} // unnamed namespace
618-
#endif
619-
620-
extern "C" {
621590
static
622591
void
623592
set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
@@ -638,10 +607,14 @@ set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context,
638607
// We manually re-sign the IP as the __ptrauth qualifiers cannot
639608
// express the required relationship with the destination address
640609
const auto existingDiscriminator =
641-
ptrauth_blend_discriminator(&results.landingPad, __ptrauth_scan_results_landingpad_disc);
610+
ptrauth_blend_discriminator(&results.landingPad,
611+
__ptrauth_scan_results_landingpad_disc);
642612
unw_word_t newIP /* opaque __ptrauth(ptrauth_key_return_address, stackPointer, 0) */ =
643-
(unw_word_t)ptrauth_auth_and_resign(*(void* const*)&results.landingPad, __ptrauth_scan_results_landingpad_key,
644-
existingDiscriminator, ptrauth_key_return_address, stackPointer);
613+
(unw_word_t)ptrauth_auth_and_resign(*(void* const*)&results.landingPad,
614+
__ptrauth_scan_results_landingpad_key,
615+
existingDiscriminator,
616+
ptrauth_key_return_address,
617+
stackPointer);
645618
_Unwind_SetIP(context, newIP);
646619
#else
647620
_Unwind_SetIP(context, results.landingPad);
@@ -991,6 +964,57 @@ _UA_CLEANUP_PHASE
991964
*/
992965

993966
#if !defined(_LIBCXXABI_ARM_EHABI)
967+
968+
// We use these helper functions to work around the behavior of casting between
969+
// integers (even those that are authenticated) and authenticated pointers.
970+
// Because the schemas being used are address discriminated we cannot use a
971+
// trivial value union to coerce the types so instead we perform the re-signing
972+
// manually.
973+
using __cxa_catch_temp_type = decltype(__cxa_exception::catchTemp);
974+
static inline void set_landing_pad(scan_results& results,
975+
const __cxa_catch_temp_type& source) {
976+
#if __has_feature(ptrauth_calls)
977+
const uintptr_t sourceDiscriminator =
978+
ptrauth_blend_discriminator(&source, __ptrauth_cxxabi_catch_temp_disc);
979+
const uintptr_t targetDiscriminator =
980+
ptrauth_blend_discriminator(&results.landingPad,
981+
__ptrauth_scan_results_landingpad_disc);
982+
uintptr_t reauthenticatedLandingPad =
983+
(uintptr_t)ptrauth_auth_and_resign(*reinterpret_cast<void* const*>(&source),
984+
__ptrauth_cxxabi_catch_temp_key,
985+
sourceDiscriminator,
986+
__ptrauth_scan_results_landingpad_key,
987+
targetDiscriminator);
988+
memmove(reinterpret_cast<void *>(&results.landingPad),
989+
reinterpret_cast<void *>(&reauthenticatedLandingPad),
990+
sizeof(reauthenticatedLandingPad));
991+
#else
992+
results.landingPad = reinterpret_cast<landing_pad_t>(source);
993+
#endif
994+
}
995+
996+
static inline void get_landing_pad(__cxa_catch_temp_type &dest,
997+
const scan_results &results) {
998+
#if __has_feature(ptrauth_calls)
999+
const uintptr_t sourceDiscriminator =
1000+
ptrauth_blend_discriminator(&results.landingPad,
1001+
__ptrauth_scan_results_landingpad_disc);
1002+
const uintptr_t targetDiscriminator =
1003+
ptrauth_blend_discriminator(&dest, __ptrauth_cxxabi_catch_temp_disc);
1004+
uintptr_t reauthenticatedPointer =
1005+
(uintptr_t)ptrauth_auth_and_resign(*reinterpret_cast<void* const*>(&results.landingPad),
1006+
__ptrauth_scan_results_landingpad_key,
1007+
sourceDiscriminator,
1008+
__ptrauth_cxxabi_catch_temp_key,
1009+
targetDiscriminator);
1010+
memmove(reinterpret_cast<void *>(&dest),
1011+
reinterpret_cast<void *>(&reauthenticatedPointer),
1012+
sizeof(reauthenticatedPointer));
1013+
#else
1014+
dest = reinterpret_cast<__cxa_catch_temp_type>(results.landingPad);
1015+
#endif
1016+
}
1017+
9941018
#ifdef __WASM_EXCEPTIONS__
9951019
_Unwind_Reason_Code __gxx_personality_wasm0
9961020
#elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__)
@@ -1023,7 +1047,7 @@ __gxx_personality_v0
10231047
results.ttypeIndex = exception_header->handlerSwitchValue;
10241048
results.actionRecord = exception_header->actionRecord;
10251049
results.languageSpecificData = exception_header->languageSpecificData;
1026-
set_landing_pad_as_ptr(results, exception_header->catchTemp);
1050+
set_landing_pad(results, exception_header->catchTemp);
10271051
results.adjustedPtr = exception_header->adjustedPtr;
10281052

10291053
// Jump to the handler.
@@ -1057,7 +1081,7 @@ __gxx_personality_v0
10571081
exc->handlerSwitchValue = static_cast<int>(results.ttypeIndex);
10581082
exc->actionRecord = results.actionRecord;
10591083
exc->languageSpecificData = results.languageSpecificData;
1060-
exc->catchTemp = get_landing_pad_as_ptr(results);
1084+
get_landing_pad(exc->catchTemp, results);
10611085
exc->adjustedPtr = results.adjustedPtr;
10621086
#ifdef __WASM_EXCEPTIONS__
10631087
// Wasm only uses a single phase (_UA_SEARCH_PHASE), so save the

libunwind/include/__libunwind_config.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,11 @@
7373
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_PPC
7474
# elif defined(__aarch64__)
7575
# define _LIBUNWIND_TARGET_AARCH64 1
76-
# define _LIBUNWIND_CONTEXT_SIZE 67
76+
#define _LIBUNWIND_CONTEXT_SIZE 67
7777
# if defined(__SEH__)
7878
# define _LIBUNWIND_CURSOR_SIZE 164
7979
# else
80-
# define _LIBUNWIND_CURSOR_SIZE 79
80+
#define _LIBUNWIND_CURSOR_SIZE 79
8181
# endif
8282
# define _LIBUNWIND_HIGHEST_DWARF_REGISTER _LIBUNWIND_HIGHEST_DWARF_REGISTER_ARM64
8383
# elif defined(__arm__)
@@ -216,7 +216,7 @@
216216
# define _LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING 1
217217
#elif __has_feature(ptrauth_calls) != __has_feature(ptrauth_returns)
218218
# error "Either both or none of ptrauth_calls and ptrauth_returns "\
219-
"is allowed to be enabled"
219+
"is allowed to be enabled"
220220
#endif
221221

222222
#endif // ____LIBUNWIND_CONFIG_H__

libunwind/include/libunwind.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@
127127

128128
#else
129129

130+
#define __unwind_ptrauth_restricted_intptr(...)
130131
#define __ptrauth_unwind_upi_handler
131132
#define __ptrauth_unwind_upi_handler_intptr
132133
#define __ptrauth_unwind_upi_startip
@@ -142,6 +143,7 @@
142143
#define __ptrauth_unwind_uis_compact_unwind_section
143144
#define __ptrauth_unwind_uis_compact_unwind_section_length
144145
#define __ptrauth_unwind_cie_info_personality
146+
145147
#endif
146148

147149
#if defined(_WIN32) && defined(__SEH__)
@@ -197,8 +199,8 @@ struct unw_proc_info_t {
197199
unw_word_t __ptrauth_unwind_upi_handler_intptr handler;
198200
unw_word_t gp; /* not used */
199201
unw_word_t __ptrauth_unwind_upi_flags flags; /* not used */
200-
uint32_t format; /* compact unwind encoding, or zero if none */
201-
uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
202+
uint32_t format; /* compact unwind encoding, or zero if none */
203+
uint32_t unwind_info_size; /* size of DWARF unwind info, or zero if none */
202204
unw_word_t __ptrauth_unwind_upi_info unwind_info; /* address of DWARF unwind info, or zero */
203205
unw_word_t __ptrauth_unwind_upi_extra extra; /* mach_header of mach-o image containing func */
204206
};

libunwind/src/CompactUnwinder.hpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -601,12 +601,16 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrameless(
601601
savedRegisterLoc -= 8;
602602
}
603603

604+
// We load the link register prior to setting the new SP as the authentication
605+
// schema for LR entangles the SP of the old frame into the diversifier.
604606
Registers_arm64::reg_t linkRegister = registers.getRegister(UNW_AARCH64_LR);
605607

606608
// subtract stack size off of sp
607609
registers.setSP(savedRegisterLoc);
608610

609-
// set pc to be value in lr
611+
// Set pc to be value in lr. This needs to be performed after the new SP has
612+
// been set, as the PC authentication schema entangles the SP of the new
613+
// frame.
610614
registers.setIP(linkRegister);
611615

612616
return UNW_STEP_SUCCESS;
@@ -684,13 +688,14 @@ int CompactUnwinder_arm64<A>::stepWithCompactEncodingFrame(
684688

685689
Registers_arm64::reg_t fp = registers.getFP();
686690

687-
// old sp is fp less saved fp and lr. Set this before LR because in arm64e
688-
// it's the authentication discriminator.
689-
registers.setSP(fp + 16);
690-
691691
// fp points to old fp
692692
registers.setFP(addressSpace.get64(fp));
693693

694+
// Old sp is fp less saved fp and lr. We need to set this prior to setting
695+
// the lr as the pointer authentication schema for the lr incorporates the
696+
// sp as part of the diversifier.
697+
registers.setSP(fp + 16);
698+
694699
// pop return address into pc
695700
registers.setIP(addressSpace.get64(fp + 8));
696701

libunwind/src/DwarfParser.hpp

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@
2323

2424
#include "config.h"
2525

26+
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
27+
#include <ptrauth.h>
28+
#endif
29+
2630
namespace libunwind {
2731

2832
/// CFI_Parser does basic parsing of a CFI (Call Frame Information) records.
@@ -314,18 +318,6 @@ bool CFI_Parser<A>::findFDE(A &addressSpace, pint_t pc, pint_t ehSectionStart,
314318
}
315319
return false;
316320
}
317-
namespace {
318-
// This helper function handles setting the manually signed personality on
319-
// CIE_Info without attempt to authenticate and/or re-sign
320-
template <typename CIE_Info, typename T>
321-
[[maybe_unused]] void set_cie_info_personality(CIE_Info *info,
322-
T signed_personality) {
323-
static_assert(sizeof(info->personality) == sizeof(signed_personality),
324-
"Signed personality is the wrong size");
325-
memmove((void *)&info->personality, (void *)&signed_personality,
326-
sizeof(signed_personality));
327-
}
328-
}
329321

330322
/// Extract info from a CIE
331323
template <typename A>
@@ -420,7 +412,10 @@ const char *CFI_Parser<A>::parseCIE(A &addressSpace, pint_t cie,
420412
personality = (pint_t)signedPtr;
421413
}
422414
#endif
423-
set_cie_info_personality(cieInfo, personality);
415+
// We use memmove to set the CIE personality as we have already
416+
// re-signed the pointer to the correct schema.
417+
memmove((void *)&cieInfo->personality, (void *)&personality,
418+
sizeof(personality));
424419
break;
425420
}
426421
case 'L':

libunwind/src/Registers.hpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1950,7 +1950,7 @@ inline Registers_arm64::Registers_arm64(const void *registers) {
19501950
// authenticating so that we maintain the signature for the resigning
19511951
// performed by setIP.
19521952
uint64_t pcRegister = 0;
1953-
memcpy(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
1953+
memmove(&pcRegister, ((uint8_t *)&_registers) + offsetof(GPRs, __pc),
19541954
sizeof(pcRegister));
19551955
setIP(pcRegister);
19561956
#endif
@@ -1962,9 +1962,9 @@ inline Registers_arm64::Registers_arm64(const Registers_arm64 &other) {
19621962

19631963
inline Registers_arm64 &
19641964
Registers_arm64::operator=(const Registers_arm64 &other) {
1965-
memcpy(&_registers, &other._registers, sizeof(_registers));
1966-
memcpy(_vectorHalfRegisters, &other._vectorHalfRegisters,
1967-
sizeof(_vectorHalfRegisters));
1965+
memmove(&_registers, &other._registers, sizeof(_registers));
1966+
memmove(_vectorHalfRegisters, &other._vectorHalfRegisters,
1967+
sizeof(_vectorHalfRegisters));
19681968
#if defined(_LIBUNWIND_TARGET_AARCH64_AUTHENTICATED_UNWINDING)
19691969
// We perform this step to ensure that we correctly authenticate and re-sign
19701970
// the pc after the bitwise copy.

libunwind/src/UnwindCursor.hpp

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1750,18 +1750,6 @@ bool UnwindCursor<A, R>::getInfoFromDwarfSection(
17501750

17511751

17521752
#if defined(_LIBUNWIND_SUPPORT_COMPACT_UNWIND)
1753-
// This helper function handles setting the manually signed handler on
1754-
// unw_proc_info without attempt to authenticate and/or re-sign
1755-
namespace {
1756-
template <typename T>
1757-
void set_proc_info_handler(unw_proc_info_t &info, T signed_handler) {
1758-
static_assert(sizeof(info.handler) == sizeof(signed_handler),
1759-
"Signed handler is the wrong size");
1760-
memmove((void *)&info.handler, (void *)&signed_handler,
1761-
sizeof(signed_handler));
1762-
}
1763-
} // unnamed namespace
1764-
17651753
template <typename A, typename R>
17661754
bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
17671755
const typename R::link_reg_t &pc, const UnwindInfoSections &sects) {
@@ -2018,7 +2006,12 @@ bool UnwindCursor<A, R>::getInfoFromCompactEncodingSection(
20182006
_info.start_ip = funcStart;
20192007
_info.end_ip = funcEnd;
20202008
_info.lsda = lsda;
2021-
set_proc_info_handler(_info, personality);
2009+
// We use memmove to copy the personality function as we have already manually
2010+
// re-signed the pointer, and assigning directly will attempt to incorrectly
2011+
// sign the already signed value.
2012+
memmove(reinterpret_cast<void *>(&_info.handler),
2013+
reinterpret_cast<void *>(&personality),
2014+
sizeof(personality));
20222015
_info.gp = 0;
20232016
_info.flags = 0;
20242017
_info.format = encoding;

libunwind/src/UnwindLevel1.c

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -90,30 +90,20 @@
9090
} while (0)
9191
#endif
9292

93-
// There is not currently a clean way to cast between an authenticated
94-
// integer and an authenticated function pointer, so we need this helper
95-
// function to keep things clean.
93+
// We need this helper function as the semantics of casting between integers and
94+
// function pointers mean that we end up with a function pointer without the
95+
// correct signature. Instead we assign to an integer with a matching schema,
96+
// and then memmove the result into a variable of the correct type. This memmove
97+
// is possible as `_Unwind_Personality_Fn` is a standard function pointer, and
98+
// as such is not address diversified.
9699
static _Unwind_Personality_Fn get_handler_function(unw_proc_info_t *frameInfo) {
97-
// Converting from an authenticated integer to a _Unwind_Personality_Fn
98-
// requires multiple steps, but as the schema of _Unwind_Personality_Fn is
99-
// not address diversified we can mostly just rely on automatic re-signing
100-
// by clang.
101-
102-
// Step 1. Assign from the address diversified integer in frameInfo->handler
103-
// to the non-address diversified schema of `_Unwind_Personality_Fn`
104100
uintptr_t __unwind_ptrauth_restricted_intptr(ptrauth_key_function_pointer,
105101
0,
106102
ptrauth_function_pointer_type_discriminator(_Unwind_Personality_Fn))
107103
reauthenticatedIntegerHandler = frameInfo->handler;
108-
109-
// Step 2. Memcpy from our re-signed integer typed handler to an
110-
// _Unwind_Personality_Fn typed local - this avoids any confused
111-
// re-signing of values that already have a signature.
112104
_Unwind_Personality_Fn handler;
113-
memcpy(&handler, (void *)&reauthenticatedIntegerHandler,
105+
memmove(&handler, (void *)&reauthenticatedIntegerHandler,
114106
sizeof(_Unwind_Personality_Fn));
115-
116-
// Step 3. Finally return the correctly typed and signed value.
117107
return handler;
118108
}
119109

0 commit comments

Comments
 (0)