Skip to content

Commit 2e62fe4

Browse files
Pointer-Authentication Based Forward Edge Protection
Co-authored-by: Schrodinger ZHU Yifan <i@zhuyi.fan>
1 parent 5fbf18f commit 2e62fe4

5 files changed

Lines changed: 143 additions & 9 deletions

File tree

CMakeLists.txt

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,44 @@ if(SNMALLOC_COMPILER_SUPPORT_MCX16)
374374
target_compile_options(snmalloc INTERFACE $<$<COMPILE_LANGUAGE:CXX>:-mcx16>)
375375
endif()
376376

377+
check_cxx_compiler_flag(
378+
"-Werror -march=armv8.3-a+pauth -fptrauth-intrinsics"
379+
SNMALLOC_COMPILER_SUPPORT_MARCH_V83A_PAUTH)
380+
if(SNMALLOC_COMPILER_SUPPORT_MARCH_V83A_PAUTH)
381+
set(SNMALLOC_SAVED_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
382+
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -march=armv8.3-a+pauth -fptrauth-intrinsics")
383+
check_cxx_source_compiles("
384+
#if !defined(__aarch64__) && !defined(_M_ARM64) && !defined(_M_ARM64EC)
385+
# error PAC instructions require AArch64
386+
#endif
387+
#if !__has_include(<ptrauth.h>)
388+
# error Missing ptrauth.h
389+
#endif
390+
#include <ptrauth.h>
391+
#ifndef __ARM_FEATURE_PAUTH
392+
# error Compiler target does not expose pointer authentication
393+
#endif
394+
static inline void* sign_and_auth(void* ptr, void* storage)
395+
{
396+
auto discriminator = ptrauth_blend_discriminator(storage, 0x5678U);
397+
auto signed_ptr = ptrauth_sign_unauthenticated(
398+
ptr, ptrauth_key_process_dependent_data, discriminator);
399+
return ptrauth_auth_data(
400+
signed_ptr, ptrauth_key_process_dependent_data, discriminator);
401+
}
402+
int main()
403+
{
404+
return sign_and_auth(nullptr, reinterpret_cast<void*>(0x1234UL)) != nullptr;
405+
}
406+
" SNMALLOC_COMPILER_SUPPORT_PACA_PACG)
407+
set(CMAKE_REQUIRED_FLAGS "${SNMALLOC_SAVED_REQUIRED_FLAGS}")
408+
unset(SNMALLOC_SAVED_REQUIRED_FLAGS)
409+
endif()
410+
if(SNMALLOC_COMPILER_SUPPORT_PACA_PACG)
411+
target_compile_options(snmalloc INTERFACE
412+
$<$<COMPILE_LANGUAGE:CXX>:-march=armv8.3-a+pauth -fptrauth-intrinsics>)
413+
endif()
414+
377415
if (NOT SNMALLOC_HEADER_ONLY_LIBRARY AND SNMALLOC_IPO)
378416
check_ipo_supported(RESULT HAS_IPO)
379417
if (HAS_IPO)
@@ -400,6 +438,7 @@ add_as_define(SNMALLOC_PLATFORM_HAS_GETENTROPY)
400438
add_as_define(SNMALLOC_PTHREAD_ATFORK_WORKS)
401439
add_as_define(SNMALLOC_HAS_LINUX_RANDOM_H)
402440
add_as_define(SNMALLOC_HAS_LINUX_FUTEX_H)
441+
add_as_define(SNMALLOC_COMPILER_SUPPORT_PACA_PACG)
403442
if (SNMALLOC_NO_REALLOCARRAY)
404443
add_as_define(SNMALLOC_NO_REALLOCARRAY)
405444
endif()

src/snmalloc/aal/aal.h

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,36 @@ namespace snmalloc
180180
#endif
181181
}
182182
}
183+
184+
static SNMALLOC_FAST_PATH uintptr_t pointer_auth_sign_data(
185+
uintptr_t value, address_t storage_addr, uintptr_t tweak) noexcept
186+
{
187+
if constexpr ((Arch::aal_features & PtrAuthentication) != 0)
188+
{
189+
return Arch::pointer_auth_sign_data(
190+
value, static_cast<uintptr_t>(storage_addr), tweak);
191+
}
192+
else
193+
{
194+
UNUSED(storage_addr, tweak);
195+
return value;
196+
}
197+
}
198+
199+
static SNMALLOC_FAST_PATH uintptr_t pointer_auth_auth_data(
200+
uintptr_t value, address_t storage_addr, uintptr_t tweak) noexcept
201+
{
202+
if constexpr ((Arch::aal_features & PtrAuthentication) != 0)
203+
{
204+
return Arch::pointer_auth_auth_data(
205+
value, static_cast<uintptr_t>(storage_addr), tweak);
206+
}
207+
else
208+
{
209+
UNUSED(storage_addr, tweak);
210+
return value;
211+
}
212+
}
183213
};
184214

185215
template<class Arch>

src/snmalloc/aal/aal_arm.h

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,12 @@
1313
#endif
1414

1515
#include <stddef.h>
16+
#include <stdint.h>
17+
18+
#if defined(SNMALLOC_COMPILER_SUPPORT_PACA_PACG) && \
19+
defined(__ARM_FEATURE_PAUTH) && __has_include(<ptrauth.h>)
20+
# include <ptrauth.h>
21+
#endif
1622

1723
namespace snmalloc
1824
{
@@ -28,6 +34,9 @@ namespace snmalloc
2834
static constexpr uint64_t aal_features = IntegerPointers
2935
#if defined(SNMALLOC_VA_BITS_32) || !defined(__APPLE__)
3036
| NoCpuCycleCounters
37+
#endif
38+
#if defined(SNMALLOC_COMPILER_SUPPORT_PACA_PACG) && defined(__ARM_FEATURE_PAUTH)
39+
| PtrAuthentication
3140
#endif
3241
;
3342

@@ -69,6 +78,35 @@ namespace snmalloc
6978
return t;
7079
}
7180
#endif
81+
82+
#if defined(SNMALLOC_COMPILER_SUPPORT_PACA_PACG) && \
83+
defined(__ARM_FEATURE_PAUTH) && __has_include(<ptrauth.h>)
84+
static SNMALLOC_FAST_PATH uintptr_t pointer_auth_sign_data(
85+
uintptr_t value, uintptr_t storage_addr, uintptr_t tweak) noexcept
86+
{
87+
return unsafe_to_uintptr<void>(ptrauth_sign_unauthenticated(
88+
unsafe_from_uintptr<void>(value),
89+
ptrauth_key_process_dependent_data,
90+
/*
91+
* only the lower 16 bits of tweak is used
92+
*/
93+
ptrauth_blend_discriminator(
94+
unsafe_from_uintptr<void>(storage_addr), tweak)));
95+
}
96+
97+
static SNMALLOC_FAST_PATH uintptr_t pointer_auth_auth_data(
98+
uintptr_t value, uintptr_t storage_addr, uintptr_t tweak) noexcept
99+
{
100+
return unsafe_to_uintptr<void>(ptrauth_auth_data(
101+
unsafe_from_uintptr<void>(value),
102+
ptrauth_key_process_dependent_data,
103+
/*
104+
* only the lower 16 bits of tweak is used
105+
*/
106+
ptrauth_blend_discriminator(
107+
unsafe_from_uintptr<void>(storage_addr), tweak)));
108+
}
109+
#endif
72110
};
73111

74112
using AAL_Arch = AAL_arm;

src/snmalloc/aal/aal_consts.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ namespace snmalloc
2424
* internal high-privilege pointers for recycling memory on free().
2525
*/
2626
StrictProvenance = (1 << 2),
27+
/**
28+
* This architecture can authenticate stored internal pointers, allowing
29+
* allocator metadata edges to be signed before storage and authenticated on
30+
* reload.
31+
*/
32+
PtrAuthentication = (1 << 3),
2733
};
2834

2935
enum AalName : int

src/snmalloc/mem/freelist.h

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -290,22 +290,31 @@ namespace snmalloc
290290
const FreeListKey& key,
291291
address_t key_tweak)
292292
{
293-
// Note we can consider other encoding schemes here.
294-
// * XORing curr and next. This doesn't require any key material
295-
// * XORing (curr * key). This makes it harder to guess the underlying
296-
// key, as each location effectively has its own key.
297-
// Curr is not used in the current encoding scheme.
298-
UNUSED(curr);
299-
300293
if constexpr (
294+
mitigations(freelist_forward_edge) && aal_supports<PtrAuthentication>)
295+
{
296+
return unsafe_from_uintptr<Object::T<BQueue>>(
297+
Aal::pointer_auth_sign_data(
298+
unsafe_to_uintptr<Object::T<BQueue>>(next),
299+
curr,
300+
key.key_next ^ key_tweak));
301+
}
302+
else if constexpr (
301303
mitigations(freelist_forward_edge) && !aal_supports<StrictProvenance>)
302304
{
305+
// Note we can consider other encoding schemes here.
306+
// * XORing curr and next. This doesn't require any key material
307+
// * XORing (curr * key). This makes it harder to guess the
308+
// underlying key, as each location effectively has its own key.
309+
// Curr is not used in the current encoding scheme.
310+
UNUSED(curr);
303311
return unsafe_from_uintptr<Object::T<BQueue>>(
304312
unsafe_to_uintptr<Object::T<BQueue>>(next) ^ key.key_next ^
305313
key_tweak);
306314
}
307315
else
308316
{
317+
UNUSED(curr);
309318
UNUSED(key);
310319
UNUSED(key_tweak);
311320
return next;
@@ -364,8 +373,20 @@ namespace snmalloc
364373
const FreeListKey& key,
365374
address_t key_tweak)
366375
{
367-
return BHeadPtr<BView, BQueue>::unsafe_from(
368-
code_next(curr, next.unsafe_ptr(), key, key_tweak));
376+
if constexpr (
377+
mitigations(freelist_forward_edge) && aal_supports<PtrAuthentication>)
378+
{
379+
return BHeadPtr<BView, BQueue>::unsafe_from(
380+
unsafe_from_uintptr<Object::T<BQueue>>(Aal::pointer_auth_auth_data(
381+
unsafe_to_uintptr<Object::T<BQueue>>(next.unsafe_ptr()),
382+
curr,
383+
key.key_next ^ key_tweak)));
384+
}
385+
else
386+
{
387+
return BHeadPtr<BView, BQueue>::unsafe_from(
388+
code_next(curr, next.unsafe_ptr(), key, key_tweak));
389+
}
369390
}
370391

371392
template<

0 commit comments

Comments
 (0)