Skip to content

Commit aeece52

Browse files
committed
[PAC][AArch64] Support init/fini array signing
If both `-fptrauth-init-fini` and `-fptrauth-calls` are passed, sign function pointers in `llvm.global_ctors` and `llvm.global_dtors` with constant discriminator 0xD9D4 (`ptrauth_string_discriminator("init_fini")`). Additionally, if `-fptrauth-init-fini-address-discrimination` is passed, address discrimination is used for signing (otherwise, just constant discriminator is used).
1 parent 17e51d5 commit aeece52

File tree

17 files changed

+197
-54
lines changed

17 files changed

+197
-54
lines changed

clang/include/clang/Basic/Features.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtr
110110
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
111111
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
112112
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
113+
FEATURE(ptrauth_init_fini_address_discrimination, LangOpts.PointerAuthInitFiniAddressDiscrimination)
113114
EXTENSION(swiftcc,
114115
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
115116
clang::TargetInfo::CCCR_OK)

clang/include/clang/Basic/LangOptions.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps")
168168
LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers")
169169
LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers")
170170
LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
171+
LANGOPT(PointerAuthInitFiniAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated function pointers in init/fini arrays")
171172

172173
LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
173174
LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes")

clang/include/clang/Basic/PointerAuthOptions.h

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

2424
namespace clang {
2525

26+
/// Constant discriminator to be used with function pointers in .init_array and
27+
/// .fini_array. The value is ptrauth_string_discriminator("init_fini")
28+
constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4;
29+
2630
constexpr unsigned PointerAuthKeyNone = -1;
2731

2832
class PointerAuthSchema {
@@ -150,6 +154,9 @@ class PointerAuthSchema {
150154
struct PointerAuthOptions {
151155
/// The ABI for C function pointers.
152156
PointerAuthSchema FunctionPointers;
157+
158+
/// The ABI for function addresses in .init_array and .fini_array
159+
PointerAuthSchema InitFiniPointers;
153160
};
154161

155162
} // end namespace clang

clang/include/clang/Driver/Options.td

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4228,6 +4228,7 @@ defm ptrauth_vtable_pointer_address_discrimination :
42284228
defm ptrauth_vtable_pointer_type_discrimination :
42294229
OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">;
42304230
defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">;
4231+
defm ptrauth_init_fini_address_discrimination : OptInCC1FFlag<"ptrauth-init-fini-address-discrimination", "Enable address discrimination of function pointers in init/fini arrays">;
42314232
}
42324233

42334234
def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,10 +1210,13 @@ void CodeGenModule::Release() {
12101210
(LangOpts.PointerAuthVTPtrTypeDiscrimination
12111211
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR) |
12121212
(LangOpts.PointerAuthInitFini
1213-
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI);
1214-
static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI ==
1215-
AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST,
1216-
"Update when new enum items are defined");
1213+
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI) |
1214+
(LangOpts.PointerAuthInitFiniAddressDiscrimination
1215+
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINIADDRDISC);
1216+
static_assert(
1217+
AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINIADDRDISC ==
1218+
AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST,
1219+
"Update when new enum items are defined");
12171220
if (PAuthABIVersion != 0) {
12181221
getModule().addModuleFlag(llvm::Module::Error,
12191222
"aarch64-elf-pauthabi-platform",
@@ -2051,37 +2054,49 @@ void CodeGenModule::AddGlobalDtor(llvm::Function *Dtor, int Priority,
20512054
void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) {
20522055
if (Fns.empty()) return;
20532056

2054-
// Ctor function type is void()*.
2055-
llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false);
2056-
llvm::Type *CtorPFTy = llvm::PointerType::get(CtorFTy,
2057-
TheModule.getDataLayout().getProgramAddressSpace());
2057+
const PointerAuthSchema &InitFiniAuthSchema =
2058+
getCodeGenOpts().PointerAuth.InitFiniPointers;
20582059

2059-
// Get the type of a ctor entry, { i32, void ()*, i8* }.
2060-
llvm::StructType *CtorStructTy = llvm::StructType::get(
2061-
Int32Ty, CtorPFTy, VoidPtrTy);
2060+
// Ctor function type is ptr.
2061+
llvm::PointerType *PtrTy = llvm::PointerType::get(
2062+
getLLVMContext(), TheModule.getDataLayout().getProgramAddressSpace());
2063+
2064+
// Get the type of a ctor entry, { i32, ptr, ptr }.
2065+
llvm::StructType *CtorStructTy = llvm::StructType::get(Int32Ty, PtrTy, PtrTy);
20622066

20632067
// Construct the constructor and destructor arrays.
2064-
ConstantInitBuilder builder(*this);
2065-
auto ctors = builder.beginArray(CtorStructTy);
2068+
ConstantInitBuilder Builder(*this);
2069+
auto Ctors = Builder.beginArray(CtorStructTy);
20662070
for (const auto &I : Fns) {
2067-
auto ctor = ctors.beginStruct(CtorStructTy);
2068-
ctor.addInt(Int32Ty, I.Priority);
2069-
ctor.add(I.Initializer);
2071+
auto Ctor = Ctors.beginStruct(CtorStructTy);
2072+
Ctor.addInt(Int32Ty, I.Priority);
2073+
if (InitFiniAuthSchema) {
2074+
llvm::Constant *StorageAddress =
2075+
(InitFiniAuthSchema.isAddressDiscriminated()
2076+
? StorageAddress = Ctor.getAddrOfCurrentPosition(PtrTy)
2077+
: nullptr);
2078+
llvm::Constant *SignedCtorPtr = getConstantSignedPointer(
2079+
I.Initializer, InitFiniAuthSchema.getKey(), StorageAddress,
2080+
llvm::ConstantInt::get(
2081+
SizeTy, InitFiniAuthSchema.getConstantDiscrimination()));
2082+
Ctor.add(SignedCtorPtr);
2083+
} else {
2084+
Ctor.add(I.Initializer);
2085+
}
20702086
if (I.AssociatedData)
2071-
ctor.add(I.AssociatedData);
2087+
Ctor.add(I.AssociatedData);
20722088
else
2073-
ctor.addNullPointer(VoidPtrTy);
2074-
ctor.finishAndAddTo(ctors);
2089+
Ctor.addNullPointer(PtrTy);
2090+
Ctor.finishAndAddTo(Ctors);
20752091
}
20762092

2077-
auto list =
2078-
ctors.finishAndCreateGlobal(GlobalName, getPointerAlign(),
2079-
/*constant*/ false,
2080-
llvm::GlobalValue::AppendingLinkage);
2093+
auto List = Ctors.finishAndCreateGlobal(GlobalName, getPointerAlign(),
2094+
/*constant*/ false,
2095+
llvm::GlobalValue::AppendingLinkage);
20812096

20822097
// The LTO linker doesn't seem to like it when we set an alignment
20832098
// on appending variables. Take it off as a workaround.
2084-
list->setAlignment(std::nullopt);
2099+
List->setAlignment(std::nullopt);
20852100

20862101
Fns.clear();
20872102
}

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1789,6 +1789,9 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
17891789
options::OPT_fno_ptrauth_vtable_pointer_type_discrimination);
17901790
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_init_fini,
17911791
options::OPT_fno_ptrauth_init_fini);
1792+
Args.addOptInFlag(CmdArgs,
1793+
options::OPT_fptrauth_init_fini_address_discrimination,
1794+
options::OPT_fno_ptrauth_init_fini_address_discrimination);
17921795
}
17931796

17941797
void Clang::AddLoongArchTargetArgs(const ArgList &Args,

clang/lib/Frontend/CompilerInvocation.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1468,6 +1468,11 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
14681468
// If you change anything here, be sure to update <ptrauth.h>.
14691469
Opts.FunctionPointers =
14701470
PointerAuthSchema(Key::ASIA, false, Discrimination::None);
1471+
if (LangOpts.PointerAuthInitFini) {
1472+
Opts.InitFiniPointers = PointerAuthSchema(
1473+
Key::ASIA, LangOpts.PointerAuthInitFiniAddressDiscrimination,
1474+
Discrimination::Constant, InitFiniPointerConstantDiscriminator);
1475+
}
14711476
}
14721477
}
14731478

@@ -3387,6 +3392,8 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
33873392
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination);
33883393
if (Opts.PointerAuthInitFini)
33893394
GenerateArg(Consumer, OPT_fptrauth_init_fini);
3395+
if (Opts.PointerAuthInitFiniAddressDiscrimination)
3396+
GenerateArg(Consumer, OPT_fptrauth_init_fini_address_discrimination);
33903397
}
33913398

33923399
static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
@@ -3400,6 +3407,8 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
34003407
Opts.PointerAuthVTPtrTypeDiscrimination =
34013408
Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination);
34023409
Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini);
3410+
Opts.PointerAuthInitFiniAddressDiscrimination =
3411+
Args.hasArg(OPT_fptrauth_init_fini_address_discrimination);
34033412
}
34043413

34053414
/// Check if input file kind and language standard are compatible.

clang/lib/Headers/ptrauth.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ typedef enum {
3232
The extra data is always 0. */
3333
ptrauth_key_function_pointer = ptrauth_key_process_independent_code,
3434

35+
/* The key used to sign pointers in ELF .init_array/.fini_array. */
36+
ptrauth_key_init_fini_pointer = ptrauth_key_asia,
37+
3538
/* Other pointers signed under the ABI use private ABI rules. */
3639

3740
} ptrauth_key;
@@ -205,6 +208,11 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
205208
#define ptrauth_sign_generic_data(__value, __data) \
206209
__builtin_ptrauth_sign_generic_data(__value, __data)
207210

211+
#define __ptrauth_init_fini_discriminator 0xd9d4
212+
#define __ptrauth_init_fini_pointer(address_discrimination) \
213+
__ptrauth(ptrauth_key_init_fini_pointer, address_discrimination, \
214+
__ptrauth_init_fini_discriminator)
215+
208216
#else
209217

210218
#define ptrauth_strip(__value, __key) \

clang/test/CodeGen/aarch64-elf-pauthabi.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
// RUN: -fptrauth-auth-traps \
66
// RUN: -fptrauth-vtable-pointer-address-discrimination \
77
// RUN: -fptrauth-vtable-pointer-type-discrimination \
8-
// RUN: -fptrauth-init-fini %s | \
8+
// RUN: -fptrauth-init-fini %s \
9+
// RUN: -fptrauth-init-fini-address-discrimination %s | \
910
// RUN: FileCheck %s --check-prefix=ALL
1011

1112
// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
@@ -32,8 +33,12 @@
3233
// RUN: -fptrauth-calls -fptrauth-init-fini %s | \
3334
// RUN: FileCheck %s --check-prefix=INITFINI
3435

36+
// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
37+
// RUN: -fptrauth-calls -fptrauth-init-fini -fptrauth-init-fini-address-discrimination %s | \
38+
// RUN: FileCheck %s --check-prefix=INITFINIADDR
39+
3540
// ALL: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
36-
// ALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 127}
41+
// ALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 255}
3742

3843
// INTRIN: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
3944
// INTRIN: !{i32 1, !"aarch64-elf-pauthabi-version", i32 1}
@@ -56,4 +61,7 @@
5661
// INITFINI: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
5762
// INITFINI: !{i32 1, !"aarch64-elf-pauthabi-version", i32 66}
5863

64+
// INITFINIADDR: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
65+
// INITFINIADDR: !{i32 1, !"aarch64-elf-pauthabi-version", i32 194}
66+
5967
void foo() {}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// REQUIRES: aarch64-registered-target
2+
3+
// RUN: %clang -target aarch64-elf -march=armv8.3-a+pauth -fptrauth-calls -fptrauth-init-fini \
4+
// RUN: -S -emit-llvm %s -o - | FileCheck --check-prefix=SIGNED %s
5+
6+
// RUN: %clang -target aarch64-elf -march=armv8.3-a+pauth -fptrauth-calls -fptrauth-init-fini \
7+
// RUN: -fptrauth-init-fini-address-discrimination -S -emit-llvm %s -o - | FileCheck --check-prefix=ADDRDISC %s
8+
9+
//// Check that `appendToGlobal{C|D}tors` properly updates `llvm.global_{c|d}tors` uses.
10+
//// Enable address sanitizer to trigger ctor/dtor list update via these functions.
11+
// RUN: %clang -target aarch64-elf -march=armv8.3-a+pauth -fptrauth-calls -fptrauth-init-fini \
12+
// RUN: -fptrauth-init-fini-address-discrimination -fsanitize=address -S -emit-llvm %s -o - | \
13+
// RUN: FileCheck --check-prefix=ASAN %s
14+
15+
// RUN: %clang -target aarch64-elf -march=armv8.3-a+pauth -fptrauth-calls -fno-ptrauth-init-fini \
16+
// RUN: -S -emit-llvm %s -o - | FileCheck --check-prefix=UNSIGNED %s
17+
18+
// RUN: %clang -target aarch64-elf -march=armv8.3-a+pauth -fptrauth-init-fini \
19+
// RUN: -S -emit-llvm %s -o - | FileCheck --check-prefix=UNSIGNED %s
20+
21+
// SIGNED: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764), ptr null }]
22+
// SIGNED: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764), ptr null }]
23+
24+
// ADDRDISC: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr getelementptr inbounds ([1 x { i32, ptr, ptr }], ptr @llvm.global_ctors, i32 0, i32 0, i32 1)), ptr null }]
25+
// ADDRDISC: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764, ptr getelementptr inbounds ([1 x { i32, ptr, ptr }], ptr @llvm.global_dtors, i32 0, i32 0, i32 1)), ptr null }]
26+
27+
// ASAN: @llvm.global_ctors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @foo, i32 0, i64 55764, ptr getelementptr inbounds ([1 x { i32, ptr, ptr }], ptr @llvm.global_ctors, i32 0, i32 0, i32 1)), ptr null }, { i32, ptr, ptr } { i32 1, ptr @asan.module_ctor, ptr @asan.module_ctor }]
28+
// ASAN: @llvm.global_dtors = appending global [2 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr ptrauth (ptr @bar, i32 0, i64 55764, ptr getelementptr inbounds ([1 x { i32, ptr, ptr }], ptr @llvm.global_dtors, i32 0, i32 0, i32 1)), ptr null }, { i32, ptr, ptr } { i32 1, ptr @asan.module_dtor, ptr @asan.module_dtor }]
29+
30+
// UNSIGNED: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }]
31+
// UNSIGNED: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }]
32+
33+
volatile int x = 0;
34+
35+
__attribute__((constructor)) void foo(void) {
36+
x = 42;
37+
}
38+
39+
__attribute__((destructor)) void bar(void) {
40+
x = 24;
41+
}
42+
43+
int main() {
44+
return x;
45+
}

clang/test/Driver/aarch64-ptrauth.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,18 @@
1010
// RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-address-discrimination \
1111
// RUN: -fno-ptrauth-vtable-pointer-type-discrimination -fptrauth-vtable-pointer-type-discrimination \
1212
// RUN: -fno-ptrauth-init-fini -fptrauth-init-fini \
13+
// RUN: -fno-ptrauth-init-fini-address-discrimination -fptrauth-init-fini-address-discrimination \
1314
// RUN: %s 2>&1 | FileCheck %s --check-prefix=ALL
14-
// ALL: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-init-fini"
15+
// ALL: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination"
1516

1617
// RUN: not %clang -### -c --target=x86_64 -fptrauth-intrinsics -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps \
1718
// RUN: -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination \
18-
// RUN: -fptrauth-init-fini %s 2>&1 | FileCheck %s --check-prefix=ERR
19+
// RUN: -fptrauth-init-fini -fptrauth-init-fini-address-discrimination %s 2>&1 | FileCheck %s --check-prefix=ERR
1920
// ERR: error: unsupported option '-fptrauth-intrinsics' for target '{{.*}}'
2021
// ERR-NEXT: error: unsupported option '-fptrauth-calls' for target '{{.*}}'
2122
// ERR-NEXT: error: unsupported option '-fptrauth-returns' for target '{{.*}}'
2223
// ERR-NEXT: error: unsupported option '-fptrauth-auth-traps' for target '{{.*}}'
2324
// ERR-NEXT: error: unsupported option '-fptrauth-vtable-pointer-address-discrimination' for target '{{.*}}'
2425
// ERR-NEXT: error: unsupported option '-fptrauth-vtable-pointer-type-discrimination' for target '{{.*}}'
2526
// ERR-NEXT: error: unsupported option '-fptrauth-init-fini' for target '{{.*}}'
27+
// ERR-NEXT: error: unsupported option '-fptrauth-init-fini-address-discrimination' for target '{{.*}}'

0 commit comments

Comments
 (0)