Skip to content

Commit f4ec273

Browse files
committed
[runtimes][PAC] Harden unwinding when possible (#138571)
This hardens the unwinding logic and datastructures on systems that support pointer authentication. The approach taken to hardening is to harden the schemas of as many high value fields in the myriad structs as possible, and then also explicitly qualify local variables referencing privileged or security critical values. This does introduce ABI linkage between libcxx, libcxxabi, and libunwind but those are in principle separate from the OS itself so we've kept the schema definitions in the library specific headers rather than ptrauth.h
1 parent 7368558 commit f4ec273

16 files changed

+708
-101
lines changed

compiler-rt/lib/builtins/gcc_personality_v0.c

Lines changed: 70 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,45 @@ EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, void *, PCONTEXT,
3030
_Unwind_Personality_Fn);
3131
#endif
3232

33+
#if __has_feature(ptrauth_qualifier)
34+
#include <ptrauth.h>
35+
#if __has_feature(ptrauth_restricted_intptr_qualifier)
36+
#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \
37+
discriminator) \
38+
__ptrauth_restricted_intptr(key, addressDiscriminated, discriminator)
39+
#else
40+
#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \
41+
discriminator) \
42+
__ptrauth(key, addressDiscriminated, discriminator)
43+
#endif
44+
#else
45+
#define __ptrauth_gcc_personality_intptr(...)
46+
#endif
47+
48+
#define __ptrauth_gcc_personality_func_key ptrauth_key_function_pointer
49+
50+
// ptrauth_string_discriminator("__gcc_personality_v0'funcStart") == 0xDFEB
51+
#define __ptrauth_gcc_personality_func_start \
52+
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0xDFEB)
53+
54+
// ptrauth_string_discriminator("__gcc_personality_v0'start") == 0x52DC
55+
#define __ptrauth_gcc_personality_start \
56+
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0x52DC)
57+
58+
// ptrauth_string_discriminator("__gcc_personality_v0'length") == 0xFFF7
59+
#define __ptrauth_gcc_personality_length \
60+
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0xFFF7)
61+
62+
// ptrauth_string_discriminator("__gcc_personality_v0'landingPadOffset") == 0x6498
63+
#define __ptrauth_gcc_personality_lpoffset \
64+
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, 0x6498)
65+
66+
// ptrauth_string_discriminator("__gcc_personality_v0'landingPad") == 0xA134
67+
#define __ptrauth_gcc_personality_lpad_disc 0xA134
68+
#define __ptrauth_gcc_personality_lpad \
69+
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
70+
__ptrauth_gcc_personality_lpad_disc)
71+
3372
// Pointer encodings documented at:
3473
// http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
3574

@@ -205,7 +244,8 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
205244
return continueUnwind(exceptionObject, context);
206245

207246
uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
208-
uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
247+
uintptr_t __ptrauth_gcc_personality_func_start funcStart =
248+
(uintptr_t)_Unwind_GetRegionStart(context);
209249
uintptr_t pcOffset = pc - funcStart;
210250

211251
// Parse LSDA header.
@@ -224,11 +264,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
224264
const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
225265
const uint8_t *p = callSiteTableStart;
226266
while (p < callSiteTableEnd) {
227-
uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
228-
size_t length = readEncodedPointer(&p, callSiteEncoding);
229-
size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
267+
uintptr_t __ptrauth_gcc_personality_start start =
268+
readEncodedPointer(&p, callSiteEncoding);
269+
size_t __ptrauth_gcc_personality_length length =
270+
readEncodedPointer(&p, callSiteEncoding);
271+
size_t __ptrauth_gcc_personality_lpoffset landingPadOffset =
272+
readEncodedPointer(&p, callSiteEncoding);
230273
readULEB128(&p); // action value not used for C code
231-
if (landingPad == 0)
274+
if (landingPadOffset == 0)
232275
continue; // no landing pad for this entry
233276
if ((start <= pcOffset) && (pcOffset < (start + length))) {
234277
// Found landing pad for the PC.
@@ -238,7 +281,28 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
238281
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
239282
(uintptr_t)exceptionObject);
240283
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
241-
_Unwind_SetIP(context, (funcStart + landingPad));
284+
size_t __ptrauth_gcc_personality_lpad landingPad =
285+
funcStart + landingPadOffset;
286+
#if __has_feature(ptrauth_qualifier)
287+
uintptr_t stack_pointer = _Unwind_GetGR(context, -2);
288+
const uintptr_t existingDiscriminator =
289+
ptrauth_blend_discriminator(&landingPad,
290+
__ptrauth_gcc_personality_lpad_disc);
291+
// newIP is authenticated as if it were qualified with a pseudo qualifier
292+
// along the lines of:
293+
// __ptrauth(ptrauth_key_return_address, <stack_pointer>, 0)
294+
// where the stack pointer is used in place of the strict storage
295+
// address.
296+
uintptr_t newIP =
297+
(uintptr_t)ptrauth_auth_and_resign(*(void **)&landingPad,
298+
__ptrauth_gcc_personality_func_key,
299+
existingDiscriminator,
300+
ptrauth_key_return_address,
301+
stack_pointer);
302+
_Unwind_SetIP(context, newIP);
303+
#else
304+
_Unwind_SetIP(context, landingPad);
305+
#endif
242306
return _URC_INSTALL_CONTEXT;
243307
}
244308
}

compiler-rt/lib/profile/InstrProfilingValue.c

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@
1212
#include <stdlib.h>
1313
#include <string.h>
1414

15+
#if __has_feature(ptrauth_calls)
16+
#include <ptrauth.h>
17+
#define VALID_CODE_KEY 0
18+
#endif
19+
1520
#include "InstrProfiling.h"
1621
#include "InstrProfilingInternal.h"
1722
#include "InstrProfilingUtil.h"
@@ -83,7 +88,13 @@ __llvm_profile_iterate_data(const __llvm_profile_data *Data) {
8388
/* This method is only used in value profiler mock testing. */
8489
COMPILER_RT_VISIBILITY void *
8590
__llvm_get_function_addr(const __llvm_profile_data *Data) {
86-
return Data->FunctionPointer;
91+
void *FP = Data->FunctionPointer;
92+
#if __has_feature(ptrauth_calls)
93+
// This is only used for tests where we compare against what happens to be
94+
// signed pointers.
95+
FP = ptrauth_sign_unauthenticated(FP, VALID_CODE_KEY, 0);
96+
#endif
97+
return FP;
8798
}
8899

89100
/* Allocate an array that holds the pointers to the linked lists of
@@ -149,6 +160,13 @@ static ValueProfNode *allocateOneNode(void) {
149160
static COMPILER_RT_ALWAYS_INLINE void
150161
instrumentTargetValueImpl(uint64_t TargetValue, void *Data,
151162
uint32_t CounterIndex, uint64_t CountValue) {
163+
#if __has_feature(ptrauth_calls)
164+
// TargetValue is a casted function pointer, which may be signed. Whatever is
165+
// in __llvm_profile_data is not signed. Match authiness of the
166+
// __llvm_profile_data function pointers for comparison + writing back to
167+
// Data.
168+
TargetValue = (uint64_t)ptrauth_strip((void *)TargetValue, VALID_CODE_KEY);
169+
#endif
152170
__llvm_profile_data *PData = (__llvm_profile_data *)Data;
153171
if (!PData)
154172
return;
@@ -368,3 +386,5 @@ static VPDataReaderType TheVPDataReader = {
368386
COMPILER_RT_VISIBILITY VPDataReaderType *lprofGetVPDataReader(void) {
369387
return &TheVPDataReader;
370388
}
389+
390+
#endif

libcxxabi/include/__cxxabi_config.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#define _LIBCXXABI_FUNC_VIS __declspec(dllimport)
4949
#define _LIBCXXABI_TYPE_VIS __declspec(dllimport)
5050
#endif
51+
5152
#else
5253
#if !defined(_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS)
5354
#define _LIBCXXABI_HIDDEN __attribute__((__visibility__("hidden")))
@@ -103,6 +104,52 @@
103104
#define _LIBCXXABI_DTOR_FUNC
104105
#endif
105106

107+
#if __has_include(<ptrauth.h>)
108+
# include <ptrauth.h>
109+
#endif
110+
111+
#if __has_extension(ptrauth_qualifier)
112+
113+
// ptrauth_string_discriminator("__cxa_exception::actionRecord") == 0xFC91
114+
# define __ptrauth_cxxabi_action_record \
115+
__ptrauth(ptrauth_key_process_dependent_data, 1, 0xFC91)
116+
117+
// ptrauth_string_discriminator("__cxa_exception::languageSpecificData") == 0xE8EE
118+
# define __ptrauth_cxxabi_lsd \
119+
__ptrauth(ptrauth_key_process_dependent_data, 1, 0xE8EE)
120+
121+
// ptrauth_string_discriminator("__cxa_exception::catchTemp") == 0xFA58
122+
# define __ptrauth_cxxabi_catch_temp \
123+
__ptrauth(ptrauth_key_process_dependent_data, 1, 0xFA58)
124+
125+
// ptrauth_string_discriminator("__cxa_exception::adjustedPtr") == 0x99E4
126+
# define __ptrauth_cxxabi_adjusted_ptr \
127+
__ptrauth(ptrauth_key_process_dependent_data, 1, 0x99E4)
128+
129+
// ptrauth_string_discriminator("__cxa_exception::unexpectedHandler") == 0x99A9
130+
# define __ptrauth_cxxabi_unexpected_handler \
131+
__ptrauth(ptrauth_key_function_pointer, 1, 0x99A9)
132+
133+
// ptrauth_string_discriminator("__cxa_exception::terminateHandler") == 0x0886)
134+
# define __ptrauth_cxxabi_terminate_handler \
135+
__ptrauth(ptrauth_key_function_pointer, 1, 0x886)
136+
137+
// ptrauth_string_discriminator("__cxa_exception::exceptionDestructor") == 0xC088
138+
# define __ptrauth_cxxabi_exception_destructor \
139+
__ptrauth(ptrauth_key_function_pointer, 1, 0xC088)
140+
141+
#else
142+
143+
# define __ptrauth_cxxabi_action_record
144+
# define __ptrauth_cxxabi_lsd
145+
# define __ptrauth_cxxabi_catch_temp
146+
# define __ptrauth_cxxabi_adjusted_ptr
147+
# define __ptrauth_cxxabi_unexpected_handler
148+
# define __ptrauth_cxxabi_terminate_handler
149+
# define __ptrauth_cxxabi_exception_destructor
150+
151+
#endif
152+
106153
#if __cplusplus < 201103L
107154
# define _LIBCXXABI_NOEXCEPT throw()
108155
#else

libcxxabi/src/cxa_exception.h

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,26 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
4747
// In Wasm, a destructor returns its argument
4848
void *(_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
4949
#else
50-
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
50+
void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor
51+
exceptionDestructor)(void*);
5152
#endif
52-
std::unexpected_handler unexpectedHandler;
53-
std::terminate_handler terminateHandler;
53+
std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
54+
std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
5455

5556
__cxa_exception *nextException;
5657

5758
int handlerCount;
5859

5960
#if defined(_LIBCXXABI_ARM_EHABI)
61+
static_assert(!__has_extension(ptrauth_qualifier));
6062
__cxa_exception* nextPropagatingException;
6163
int propagationCount;
6264
#else
6365
int handlerSwitchValue;
64-
const unsigned char *actionRecord;
65-
const unsigned char *languageSpecificData;
66-
void *catchTemp;
67-
void *adjustedPtr;
66+
const unsigned char* __ptrauth_cxxabi_action_record actionRecord;
67+
const unsigned char* __ptrauth_cxxabi_lsd languageSpecificData;
68+
void* __ptrauth_cxxabi_catch_temp catchTemp;
69+
void* __ptrauth_cxxabi_adjusted_ptr adjustedPtr;
6870
#endif
6971

7072
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
@@ -79,16 +81,19 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
7981
// http://sourcery.mentor.com/archives/cxx-abi-dev/msg01924.html
8082
// The layout of this structure MUST match the layout of __cxa_exception, with
8183
// primaryException instead of referenceCount.
84+
// The tags used in the pointer authentication qualifiers also need to match
85+
// those of the corresponding members in __cxa_exception.
8286
struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
8387
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
8488
void* reserve; // padding.
8589
void* primaryException;
8690
#endif
8791

8892
std::type_info *exceptionType;
89-
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
90-
std::unexpected_handler unexpectedHandler;
91-
std::terminate_handler terminateHandler;
93+
void(_LIBCXXABI_DTOR_FUNC* __ptrauth_cxxabi_exception_destructor
94+
exceptionDestructor)(void*);
95+
std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
96+
std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
9297

9398
__cxa_exception *nextException;
9499

@@ -99,10 +104,11 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
99104
int propagationCount;
100105
#else
101106
int handlerSwitchValue;
102-
const unsigned char *actionRecord;
103-
const unsigned char *languageSpecificData;
104-
void * catchTemp;
105-
void *adjustedPtr;
107+
108+
const unsigned char* __ptrauth_cxxabi_action_record actionRecord;
109+
const unsigned char* __ptrauth_cxxabi_lsd languageSpecificData;
110+
void* __ptrauth_cxxabi_catch_temp catchTemp;
111+
void* __ptrauth_cxxabi_adjusted_ptr adjustedPtr;
106112
#endif
107113

108114
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)

0 commit comments

Comments
 (0)