[llvm-branch-commits] [clang] [compiler-rt] [PAC][AArch64] Support init/fini array signing (PR #95203)
Daniil Kovalev via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Jun 12 00:36:17 PDT 2024
https://github.com/kovdan01 created https://github.com/llvm/llvm-project/pull/95203
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")`) and no address discrimination.
>From 9880b6883cd73ab2dcd0efd9ae80805db862c595 Mon Sep 17 00:00:00 2001
From: Daniil Kovalev <dkovalev at accesssoftek.com>
Date: Wed, 12 Jun 2024 10:28:08 +0300
Subject: [PATCH] [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")`)
and no address discrimination.
---
.../include/clang/Basic/PointerAuthOptions.h | 7 +++
clang/lib/CodeGen/CodeGenModule.cpp | 50 +++++++++++--------
clang/lib/Frontend/CompilerInvocation.cpp | 5 ++
clang/lib/Headers/ptrauth.h | 7 +++
clang/test/CodeGen/ptrauth-init-fini.c | 27 ++++++++++
compiler-rt/lib/builtins/crtbegin.c | 16 ++++++
6 files changed, 92 insertions(+), 20 deletions(-)
create mode 100644 clang/test/CodeGen/ptrauth-init-fini.c
diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h
index 32b179e3f9460..dea8ae439a0eb 100644
--- a/clang/include/clang/Basic/PointerAuthOptions.h
+++ b/clang/include/clang/Basic/PointerAuthOptions.h
@@ -25,6 +25,10 @@
namespace clang {
+/// Constant discriminator to be used with function pointers in .init_array and
+/// .fini_array. The value is ptrauth_string_discriminator("init_fini")
+constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4;
+
constexpr unsigned PointerAuthKeyNone = -1;
class PointerAuthSchema {
@@ -152,6 +156,9 @@ class PointerAuthSchema {
struct PointerAuthOptions {
/// The ABI for C function pointers.
PointerAuthSchema FunctionPointers;
+
+ /// The ABI for function addresses in .init_array and .fini_array
+ PointerAuthSchema InitFiniPointers;
};
} // end namespace clang
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index e4774a587707a..6bc6c34a9f524 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2042,37 +2042,47 @@ void CodeGenModule::AddGlobalDtor(llvm::Function *Dtor, int Priority,
void CodeGenModule::EmitCtorList(CtorList &Fns, const char *GlobalName) {
if (Fns.empty()) return;
- // Ctor function type is void()*.
- llvm::FunctionType* CtorFTy = llvm::FunctionType::get(VoidTy, false);
- llvm::Type *CtorPFTy = llvm::PointerType::get(CtorFTy,
- TheModule.getDataLayout().getProgramAddressSpace());
+ const PointerAuthSchema &InitFiniAuthSchema =
+ getCodeGenOpts().PointerAuth.InitFiniPointers;
+ assert(!InitFiniAuthSchema || !InitFiniAuthSchema.isAddressDiscriminated());
- // Get the type of a ctor entry, { i32, void ()*, i8* }.
- llvm::StructType *CtorStructTy = llvm::StructType::get(
- Int32Ty, CtorPFTy, VoidPtrTy);
+ // Ctor function type is ptr.
+ llvm::PointerType *PtrTy = llvm::PointerType::get(
+ getLLVMContext(), TheModule.getDataLayout().getProgramAddressSpace());
+
+ // Get the type of a ctor entry, { i32, ptr, ptr }.
+ llvm::StructType *CtorStructTy = llvm::StructType::get(Int32Ty, PtrTy, PtrTy);
// Construct the constructor and destructor arrays.
- ConstantInitBuilder builder(*this);
- auto ctors = builder.beginArray(CtorStructTy);
+ ConstantInitBuilder Builder(*this);
+ auto Ctors = Builder.beginArray(CtorStructTy);
for (const auto &I : Fns) {
- auto ctor = ctors.beginStruct(CtorStructTy);
- ctor.addInt(Int32Ty, I.Priority);
- ctor.add(I.Initializer);
+ auto Ctor = Ctors.beginStruct(CtorStructTy);
+ Ctor.addInt(Int32Ty, I.Priority);
+ if (InitFiniAuthSchema) {
+ llvm::Constant *SignedCtorPtr = getConstantSignedPointer(
+ I.Initializer, InitFiniAuthSchema.getKey(),
+ /*StorageAddress=*/nullptr,
+ llvm::ConstantInt::get(
+ SizeTy, InitFiniAuthSchema.getConstantDiscrimination()));
+ Ctor.add(SignedCtorPtr);
+ } else {
+ Ctor.add(I.Initializer);
+ }
if (I.AssociatedData)
- ctor.add(I.AssociatedData);
+ Ctor.add(I.AssociatedData);
else
- ctor.addNullPointer(VoidPtrTy);
- ctor.finishAndAddTo(ctors);
+ Ctor.addNullPointer(PtrTy);
+ Ctor.finishAndAddTo(Ctors);
}
- auto list =
- ctors.finishAndCreateGlobal(GlobalName, getPointerAlign(),
- /*constant*/ false,
- llvm::GlobalValue::AppendingLinkage);
+ auto List = Ctors.finishAndCreateGlobal(GlobalName, getPointerAlign(),
+ /*constant*/ false,
+ llvm::GlobalValue::AppendingLinkage);
// The LTO linker doesn't seem to like it when we set an alignment
// on appending variables. Take it off as a workaround.
- list->setAlignment(std::nullopt);
+ List->setAlignment(std::nullopt);
Fns.clear();
}
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index b4ca3e413b2c0..53c8fefc871c0 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -1468,6 +1468,11 @@ bool CompilerInvocation::setDefaultPointerAuthOptions(
// If you change anything here, be sure to update <ptrauth.h>.
Opts.FunctionPointers =
PointerAuthSchema(Key::ASIA, false, Discrimination::None);
+ if (LangOpts.PointerAuthInitFini) {
+ Opts.InitFiniPointers =
+ PointerAuthSchema(Key::ASIA, false, Discrimination::Constant,
+ InitFiniPointerConstantDiscriminator);
+ }
}
return true;
}
diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h
index aec387153d87c..9bf9eaac312a7 100644
--- a/clang/lib/Headers/ptrauth.h
+++ b/clang/lib/Headers/ptrauth.h
@@ -42,6 +42,9 @@ typedef enum {
The extra data is always 0. */
ptrauth_key_function_pointer = ptrauth_key_process_independent_code,
+ /* The key used to sign pointers in ELF .init_array/.fini_array. */
+ ptrauth_key_init_fini_pointer = ptrauth_key_asia,
+
/* Other pointers signed under the ABI use private ABI rules. */
} ptrauth_key;
@@ -213,6 +216,10 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
#define ptrauth_sign_generic_data(__value, __data) \
__builtin_ptrauth_sign_generic_data(__value, __data)
+#define __ptrauth_init_fini_discriminator 0xd9d4
+#define __ptrauth_init_fini_pointer \
+ __ptrauth(ptrauth_key_init_fini_pointer, 0, __ptrauth_init_fini_discriminator)
+
#else
#define ptrauth_strip(__value, __key) \
diff --git a/clang/test/CodeGen/ptrauth-init-fini.c b/clang/test/CodeGen/ptrauth-init-fini.c
new file mode 100644
index 0000000000000..894e6c84e6347
--- /dev/null
+++ b/clang/test/CodeGen/ptrauth-init-fini.c
@@ -0,0 +1,27 @@
+// REQUIRES: aarch64-registered-target
+// RUN: %clang -target aarch64-elf -march=armv8.3-a+pauth -fptrauth-calls -fptrauth-init-fini \
+// RUN: -S -emit-llvm %s -o - | FileCheck --check-prefix=SIGNED %s
+// RUN: %clang -target aarch64-elf -march=armv8.3-a+pauth -fptrauth-calls -fno-ptrauth-init-fini \
+// RUN: -S -emit-llvm %s -o - | FileCheck --check-prefix=UNSIGNED %s
+// RUN: %clang -target aarch64-elf -march=armv8.3-a+pauth -fptrauth-init-fini \
+// RUN: -S -emit-llvm %s -o - | FileCheck --check-prefix=UNSIGNED %s
+
+// 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 }]
+// 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 }]
+
+// UNSIGNED: @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @foo, ptr null }]
+// UNSIGNED: @llvm.global_dtors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 65535, ptr @bar, ptr null }]
+
+volatile int x = 0;
+
+__attribute__((constructor)) void foo(void) {
+ x = 42;
+}
+
+__attribute__((destructor)) void bar(void) {
+ x = 24;
+}
+
+int main() {
+ return x;
+}
diff --git a/compiler-rt/lib/builtins/crtbegin.c b/compiler-rt/lib/builtins/crtbegin.c
index a0860ca12ea03..143af768de679 100644
--- a/compiler-rt/lib/builtins/crtbegin.c
+++ b/compiler-rt/lib/builtins/crtbegin.c
@@ -8,6 +8,10 @@
#include <stddef.h>
+#if __has_feature(ptrauth_init_fini)
+#include <ptrauth.h>
+#endif
+
__attribute__((visibility("hidden"))) void *__dso_handle = &__dso_handle;
#ifdef EH_USE_FRAME_REGISTRY
@@ -46,8 +50,14 @@ static void __attribute__((used)) __do_init(void) {
}
#ifdef CRT_HAS_INITFINI_ARRAY
+#if __has_feature(ptrauth_init_fini)
+__attribute__((section(".init_array"),
+ used)) static void *__ptrauth_init_fini_pointer __init =
+ __do_init;
+#else
__attribute__((section(".init_array"),
used)) static void (*__init)(void) = __do_init;
+#endif
#elif defined(__i386__) || defined(__x86_64__)
__asm__(".pushsection .init,\"ax\", at progbits\n\t"
"call __do_init\n\t"
@@ -103,8 +113,14 @@ static void __attribute__((used)) __do_fini(void) {
}
#ifdef CRT_HAS_INITFINI_ARRAY
+#if __has_feature(ptrauth_init_fini)
+__attribute__((section(".fini_array"),
+ used)) static void *__ptrauth_init_fini_pointer __fini =
+ __do_fini;
+#else
__attribute__((section(".fini_array"),
used)) static void (*__fini)(void) = __do_fini;
+#endif
#elif defined(__i386__) || defined(__x86_64__)
__asm__(".pushsection .fini,\"ax\", at progbits\n\t"
"call __do_fini\n\t"
More information about the llvm-branch-commits
mailing list