Skip to content

Commit c3fefed

Browse files
ojhuntLukacma
authored andcommitted
[runtimes][PAC] Harden unwinding when possible (llvm#143230)
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 4e24f30 commit c3fefed

17 files changed

+753
-108
lines changed

compiler-rt/lib/builtins/gcc_personality_v0.c

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

33+
#if __has_feature(ptrauth_calls)
34+
#include <ptrauth.h>
35+
36+
// `__ptrauth_restricted_intptr` is a feature of apple clang that predates
37+
// support for direct application of `__ptrauth` to integer types. This
38+
// guard is necessary to support compilation with those compiler.
39+
#if __has_feature(ptrauth_restricted_intptr_qualifier)
40+
#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \
41+
discriminator) \
42+
__ptrauth_restricted_intptr(key, addressDiscriminated, discriminator)
43+
#else
44+
#define __ptrauth_gcc_personality_intptr(key, addressDiscriminated, \
45+
discriminator) \
46+
__ptrauth(key, addressDiscriminated, discriminator)
47+
#endif
48+
#else
49+
#define __ptrauth_gcc_personality_intptr(...)
50+
#endif
51+
52+
#define __ptrauth_gcc_personality_func_key ptrauth_key_function_pointer
53+
54+
// ptrauth_string_discriminator("__gcc_personality_v0'funcStart") == 0xDFEB
55+
#define __ptrauth_gcc_personality_func_start \
56+
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
57+
0xDFEB)
58+
59+
// ptrauth_string_discriminator("__gcc_personality_v0'start") == 0x52DC
60+
#define __ptrauth_gcc_personality_start \
61+
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
62+
0x52DC)
63+
64+
// ptrauth_string_discriminator("__gcc_personality_v0'length") == 0xFFF7
65+
#define __ptrauth_gcc_personality_length \
66+
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
67+
0xFFF7)
68+
69+
// ptrauth_string_discriminator("__gcc_personality_v0'landingPadOffset") ==
70+
// 0x6498
71+
#define __ptrauth_gcc_personality_lpoffset \
72+
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
73+
0x6498)
74+
75+
// ptrauth_string_discriminator("__gcc_personality_v0'landingPad") == 0xA134
76+
#define __ptrauth_gcc_personality_lpad_disc 0xA134
77+
#define __ptrauth_gcc_personality_lpad \
78+
__ptrauth_gcc_personality_intptr(__ptrauth_gcc_personality_func_key, 1, \
79+
__ptrauth_gcc_personality_lpad_disc)
80+
3381
// Pointer encodings documented at:
3482
// http://refspecs.freestandards.org/LSB_1.3.0/gLSB/gLSB/ehframehdr.html
3583

@@ -205,7 +253,8 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
205253
return continueUnwind(exceptionObject, context);
206254

207255
uintptr_t pc = (uintptr_t)_Unwind_GetIP(context) - 1;
208-
uintptr_t funcStart = (uintptr_t)_Unwind_GetRegionStart(context);
256+
uintptr_t __ptrauth_gcc_personality_func_start funcStart =
257+
(uintptr_t)_Unwind_GetRegionStart(context);
209258
uintptr_t pcOffset = pc - funcStart;
210259

211260
// Parse LSDA header.
@@ -224,11 +273,14 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
224273
const uint8_t *callSiteTableEnd = callSiteTableStart + callSiteTableLength;
225274
const uint8_t *p = callSiteTableStart;
226275
while (p < callSiteTableEnd) {
227-
uintptr_t start = readEncodedPointer(&p, callSiteEncoding);
228-
size_t length = readEncodedPointer(&p, callSiteEncoding);
229-
size_t landingPad = readEncodedPointer(&p, callSiteEncoding);
276+
uintptr_t __ptrauth_gcc_personality_start start =
277+
readEncodedPointer(&p, callSiteEncoding);
278+
size_t __ptrauth_gcc_personality_length length =
279+
readEncodedPointer(&p, callSiteEncoding);
280+
size_t __ptrauth_gcc_personality_lpoffset landingPadOffset =
281+
readEncodedPointer(&p, callSiteEncoding);
230282
readULEB128(&p); // action value not used for C code
231-
if (landingPad == 0)
283+
if (landingPadOffset == 0)
232284
continue; // no landing pad for this entry
233285
if ((start <= pcOffset) && (pcOffset < (start + length))) {
234286
// Found landing pad for the PC.
@@ -238,7 +290,24 @@ COMPILER_RT_ABI _Unwind_Reason_Code __gcc_personality_v0(
238290
_Unwind_SetGR(context, __builtin_eh_return_data_regno(0),
239291
(uintptr_t)exceptionObject);
240292
_Unwind_SetGR(context, __builtin_eh_return_data_regno(1), 0);
241-
_Unwind_SetIP(context, (funcStart + landingPad));
293+
size_t __ptrauth_gcc_personality_lpad landingPad =
294+
funcStart + landingPadOffset;
295+
#if __has_feature(ptrauth_calls)
296+
uintptr_t stackPointer = _Unwind_GetGR(context, -2);
297+
const uintptr_t existingDiscriminator = ptrauth_blend_discriminator(
298+
&landingPad, __ptrauth_gcc_personality_lpad_disc);
299+
// newIP is authenticated as if it were qualified with a pseudo qualifier
300+
// along the lines of:
301+
// __ptrauth(ptrauth_key_return_address, <stackPointer>, 0)
302+
// where the stack pointer is used in place of the strict storage
303+
// address.
304+
uintptr_t newIP = (uintptr_t)ptrauth_auth_and_resign(
305+
*(void **)&landingPad, __ptrauth_gcc_personality_func_key,
306+
existingDiscriminator, ptrauth_key_return_address, stackPointer);
307+
_Unwind_SetIP(context, newIP);
308+
#else
309+
_Unwind_SetIP(context, landingPad);
310+
#endif
242311
return _URC_INSTALL_CONTEXT;
243312
}
244313
}

libcxxabi/include/__cxxabi_config.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,47 @@
103103
#define _LIBCXXABI_DTOR_FUNC
104104
#endif
105105

106+
#if __has_include(<ptrauth.h>)
107+
# include <ptrauth.h>
108+
#endif
109+
110+
#if __has_feature(ptrauth_calls)
111+
112+
// ptrauth_string_discriminator("__cxa_exception::actionRecord") == 0xFC91
113+
# define __ptrauth_cxxabi_action_record __ptrauth(ptrauth_key_process_dependent_data, 1, 0xFC91)
114+
115+
// ptrauth_string_discriminator("__cxa_exception::languageSpecificData") == 0xE8EE
116+
# define __ptrauth_cxxabi_lsd __ptrauth(ptrauth_key_process_dependent_data, 1, 0xE8EE)
117+
118+
// ptrauth_string_discriminator("__cxa_exception::catchTemp") == 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)
122+
123+
// ptrauth_string_discriminator("__cxa_exception::adjustedPtr") == 0x99E4
124+
# define __ptrauth_cxxabi_adjusted_ptr __ptrauth(ptrauth_key_process_dependent_data, 1, 0x99E4)
125+
126+
// ptrauth_string_discriminator("__cxa_exception::unexpectedHandler") == 0x99A9
127+
# define __ptrauth_cxxabi_unexpected_handler __ptrauth(ptrauth_key_function_pointer, 1, 0x99A9)
128+
129+
// ptrauth_string_discriminator("__cxa_exception::terminateHandler") == 0x0886)
130+
# define __ptrauth_cxxabi_terminate_handler __ptrauth(ptrauth_key_function_pointer, 1, 0x886)
131+
132+
// ptrauth_string_discriminator("__cxa_exception::exceptionDestructor") == 0xC088
133+
# define __ptrauth_cxxabi_exception_destructor __ptrauth(ptrauth_key_function_pointer, 1, 0xC088)
134+
135+
#else
136+
137+
# define __ptrauth_cxxabi_action_record
138+
# define __ptrauth_cxxabi_lsd
139+
# define __ptrauth_cxxabi_catch_temp
140+
# define __ptrauth_cxxabi_adjusted_ptr
141+
# define __ptrauth_cxxabi_unexpected_handler
142+
# define __ptrauth_cxxabi_terminate_handler
143+
# define __ptrauth_cxxabi_exception_destructor
144+
145+
#endif
146+
106147
#if __cplusplus < 201103L
107148
# define _LIBCXXABI_NOEXCEPT throw()
108149
#else

libcxxabi/src/cxa_exception.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,9 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() {
192192
std::terminate();
193193
__cxa_exception *exception_header =
194194
static_cast<__cxa_exception *>((void *)(raw_buffer + header_offset));
195-
::memset(exception_header, 0, actual_size);
195+
// We warn on memset to a non-trivially castable type. We might want to
196+
// change that diagnostic to not fire on a trivially obvious zero fill.
197+
::memset(static_cast<void*>(exception_header), 0, actual_size);
196198
return thrown_object_from_cxa_exception(exception_header);
197199
}
198200

libcxxabi/src/cxa_exception.h

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,10 @@ 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 exceptionDestructor)(void *);
5151
#endif
52-
std::unexpected_handler unexpectedHandler;
53-
std::terminate_handler terminateHandler;
52+
std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
53+
std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
5454

5555
__cxa_exception *nextException;
5656

@@ -61,10 +61,10 @@ struct _LIBCXXABI_HIDDEN __cxa_exception {
6161
int propagationCount;
6262
#else
6363
int handlerSwitchValue;
64-
const unsigned char *actionRecord;
65-
const unsigned char *languageSpecificData;
66-
void *catchTemp;
67-
void *adjustedPtr;
64+
const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
65+
const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
66+
void *__ptrauth_cxxabi_catch_temp catchTemp;
67+
void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
6868
#endif
6969

7070
#if !defined(__LP64__) && !defined(_WIN64) && !defined(_LIBCXXABI_ARM_EHABI)
@@ -79,16 +79,18 @@ 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 pointer authentication schemas specified here must also match those of
83+
// the corresponding members in __cxa_exception.
8284
struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
8385
#if defined(__LP64__) || defined(_WIN64) || defined(_LIBCXXABI_ARM_EHABI)
8486
void* reserve; // padding.
8587
void* primaryException;
8688
#endif
8789

8890
std::type_info *exceptionType;
89-
void (_LIBCXXABI_DTOR_FUNC *exceptionDestructor)(void *);
90-
std::unexpected_handler unexpectedHandler;
91-
std::terminate_handler terminateHandler;
91+
void (_LIBCXXABI_DTOR_FUNC *__ptrauth_cxxabi_exception_destructor exceptionDestructor)(void *);
92+
std::unexpected_handler __ptrauth_cxxabi_unexpected_handler unexpectedHandler;
93+
std::terminate_handler __ptrauth_cxxabi_terminate_handler terminateHandler;
9294

9395
__cxa_exception *nextException;
9496

@@ -99,10 +101,10 @@ struct _LIBCXXABI_HIDDEN __cxa_dependent_exception {
99101
int propagationCount;
100102
#else
101103
int handlerSwitchValue;
102-
const unsigned char *actionRecord;
103-
const unsigned char *languageSpecificData;
104-
void * catchTemp;
105-
void *adjustedPtr;
104+
const unsigned char *__ptrauth_cxxabi_action_record actionRecord;
105+
const unsigned char *__ptrauth_cxxabi_lsd languageSpecificData;
106+
void *__ptrauth_cxxabi_catch_temp catchTemp;
107+
void *__ptrauth_cxxabi_adjusted_ptr adjustedPtr;
106108
#endif
107109

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

0 commit comments

Comments
 (0)