Skip to content

[PAC][AArch64] Support init/fini array signing #96478

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
Aug 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,10 @@ FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtr
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination)
FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
FEATURE(ptrauth_init_fini_address_discrimination, LangOpts.PointerAuthInitFiniAddressDiscrimination)
EXTENSION(swiftcc,
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
clang::TargetInfo::CCCR_OK)
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -170,9 +170,11 @@ LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps")
LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers")
LANGOPT(PointerAuthTypeInfoVTPtrDiscrimination, 1, 0, "incorporate type and address discrimination in authenticated vtable pointers for std::type_info")
LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
BENIGN_LANGOPT(PointerAuthFunctionTypeDiscrimination, 1, 0,
"Use type discrimination when signing function pointers")
LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
LANGOPT(PointerAuthInitFiniAddressDiscrimination, 1, 0,
"incorporate address discrimination in authenticated function pointers in init/fini arrays")

LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
LANGOPT(ExperimentalLateParseAttributes, 1, 0, "experimental late parsing of attributes")
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/PointerAuthOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,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;

/// Constant discriminator for std::type_info vtable pointers: 0xB1EA/45546
Expand Down Expand Up @@ -186,6 +190,9 @@ struct PointerAuthOptions {

/// The ABI for C++ member function pointers.
PointerAuthSchema CXXMemberFunctionPointers;

/// The ABI for function addresses in .init_array and .fini_array
PointerAuthSchema InitFiniPointers;
};

} // end namespace clang
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4253,11 +4253,13 @@ defm ptrauth_vtable_pointer_type_discrimination :
OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">;
defm ptrauth_type_info_vtable_pointer_discrimination :
OptInCC1FFlag<"ptrauth-type-info-vtable-pointer-discrimination", "Enable type and address discrimination of vtable pointer of std::type_info">;
defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">;
defm ptrauth_function_pointer_type_discrimination : OptInCC1FFlag<"ptrauth-function-pointer-type-discrimination",
"Enable type discrimination on C function pointers">;
defm ptrauth_indirect_gotos : OptInCC1FFlag<"ptrauth-indirect-gotos",
"Enable signing and authentication of indirect goto targets">;
defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">;
defm ptrauth_init_fini_address_discrimination : OptInCC1FFlag<"ptrauth-init-fini-address-discrimination",
"Enable address discrimination of function pointers in init/fini arrays">;
}

def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
Expand Down
67 changes: 43 additions & 24 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1218,10 +1218,13 @@ void CodeGenModule::Release() {
(LangOpts.PointerAuthVTPtrTypeDiscrimination
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRTYPEDISCR) |
(LangOpts.PointerAuthInitFini
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI);
static_assert(AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI ==
AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST,
"Update when new enum items are defined");
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINI) |
(LangOpts.PointerAuthInitFiniAddressDiscrimination
<< AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINIADDRDISC);
static_assert(
AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INITFINIADDRDISC ==
AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_LAST,
"Update when new enum items are defined");
if (PAuthABIVersion != 0) {
getModule().addModuleFlag(llvm::Module::Error,
"aarch64-elf-pauthabi-platform",
Expand Down Expand Up @@ -2082,37 +2085,53 @@ 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;

// 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 *StorageAddress =
(InitFiniAuthSchema.isAddressDiscriminated()
? llvm::ConstantExpr::getIntToPtr(
llvm::ConstantInt::get(
IntPtrTy,
llvm::ConstantPtrAuth::AddrDiscriminator_CtorsDtors),
PtrTy)
: nullptr);
llvm::Constant *SignedCtorPtr = getConstantSignedPointer(
I.Initializer, InitFiniAuthSchema.getKey(), StorageAddress,
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();
}
Expand Down
7 changes: 5 additions & 2 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1847,14 +1847,17 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
Args.addOptInFlag(
CmdArgs, options::OPT_fptrauth_type_info_vtable_pointer_discrimination,
options::OPT_fno_ptrauth_type_info_vtable_pointer_discrimination);
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_init_fini,
options::OPT_fno_ptrauth_init_fini);
Args.addOptInFlag(
CmdArgs, options::OPT_fptrauth_function_pointer_type_discrimination,
options::OPT_fno_ptrauth_function_pointer_type_discrimination);

Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_indirect_gotos,
options::OPT_fno_ptrauth_indirect_gotos);
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_init_fini,
options::OPT_fno_ptrauth_init_fini);
Args.addOptInFlag(CmdArgs,
options::OPT_fptrauth_init_fini_address_discrimination,
options::OPT_fno_ptrauth_init_fini_address_discrimination);
}

void Clang::AddLoongArchTargetArgs(const ArgList &Args,
Expand Down
18 changes: 13 additions & 5 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1503,6 +1503,12 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
PointerAuthSchema(Key::ASIA, true, Discrimination::Decl);
Opts.CXXMemberFunctionPointers =
PointerAuthSchema(Key::ASIA, false, Discrimination::Type);

if (LangOpts.PointerAuthInitFini) {
Opts.InitFiniPointers = PointerAuthSchema(
Key::ASIA, LangOpts.PointerAuthInitFiniAddressDiscrimination,
Discrimination::Constant, InitFiniPointerConstantDiscriminator);
}
}
Opts.IndirectGotos = LangOpts.PointerAuthIndirectGotos;
}
Expand Down Expand Up @@ -3425,11 +3431,12 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination);
if (Opts.PointerAuthTypeInfoVTPtrDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_type_info_vtable_pointer_discrimination);

if (Opts.PointerAuthInitFini)
GenerateArg(Consumer, OPT_fptrauth_init_fini);
if (Opts.PointerAuthFunctionTypeDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_function_pointer_type_discrimination);
if (Opts.PointerAuthInitFini)
GenerateArg(Consumer, OPT_fptrauth_init_fini);
if (Opts.PointerAuthInitFiniAddressDiscrimination)
GenerateArg(Consumer, OPT_fptrauth_init_fini_address_discrimination);
}

static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
Expand All @@ -3445,10 +3452,11 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination);
Opts.PointerAuthTypeInfoVTPtrDiscrimination =
Args.hasArg(OPT_fptrauth_type_info_vtable_pointer_discrimination);

Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini);
Opts.PointerAuthFunctionTypeDiscrimination =
Args.hasArg(OPT_fptrauth_function_pointer_type_discrimination);
Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini);
Opts.PointerAuthInitFiniAddressDiscrimination =
Args.hasArg(OPT_fptrauth_init_fini_address_discrimination);
}

/// Check if input file kind and language standard are compatible.
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/Headers/ptrauth.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ typedef enum {
The extra data is always 0. */
ptrauth_key_cxx_vtable_pointer = ptrauth_key_process_independent_data,

/* The key used to sign pointers in ELF .init_array/.fini_array. */
ptrauth_key_init_fini_pointer = ptrauth_key_process_independent_code,

/* Other pointers signed under the ABI use private ABI rules. */

} ptrauth_key;
Expand Down Expand Up @@ -247,6 +250,9 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t;
[[clang::ptrauth_vtable_pointer(key, address_discrimination, \
extra_discrimination)]]

/* The value is ptrauth_string_discriminator("init_fini") */
#define __ptrauth_init_fini_discriminator 0xd9d4

#else

#define ptrauth_strip(__value, __key) \
Expand Down
12 changes: 10 additions & 2 deletions clang/test/CodeGen/aarch64-elf-pauthabi.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
// RUN: -fptrauth-auth-traps \
// RUN: -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-init-fini %s | \
// RUN: -fptrauth-init-fini %s \
// RUN: -fptrauth-init-fini-address-discrimination %s | \
// RUN: FileCheck %s --check-prefix=ALL

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

// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \
// RUN: -fptrauth-calls -fptrauth-init-fini -fptrauth-init-fini-address-discrimination %s | \
// RUN: FileCheck %s --check-prefix=INITFINIADDR

// ALL: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// ALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 127}
// ALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 255}

// INTRIN: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// INTRIN: !{i32 1, !"aarch64-elf-pauthabi-version", i32 1}
Expand All @@ -56,4 +61,7 @@
// INITFINI: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// INITFINI: !{i32 1, !"aarch64-elf-pauthabi-version", i32 66}

// INITFINIADDR: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458}
// INITFINIADDR: !{i32 1, !"aarch64-elf-pauthabi-version", i32 194}

void foo() {}
39 changes: 39 additions & 0 deletions clang/test/CodeGen/ptrauth-init-fini.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// 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 -fptrauth-init-fini \
// RUN: -fptrauth-init-fini-address-discrimination -S -emit-llvm %s -o - | FileCheck --check-prefix=ADDRDISC %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-calls -fptrauth-init-fini-address-discrimination \
// 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 }]

// 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 inttoptr (i64 1 to ptr)), ptr null }]
// 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 inttoptr (i64 1 to ptr)), 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;
}
10 changes: 6 additions & 4 deletions clang/test/Driver/aarch64-ptrauth.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
// RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-address-discrimination \
// RUN: -fno-ptrauth-vtable-pointer-type-discrimination -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fno-ptrauth-type-info-vtable-pointer-discrimination -fptrauth-type-info-vtable-pointer-discrimination \
// RUN: -fno-ptrauth-init-fini -fptrauth-init-fini \
// RUN: -fno-ptrauth-indirect-gotos -fptrauth-indirect-gotos \
// RUN: -fno-ptrauth-init-fini -fptrauth-init-fini \
// RUN: -fno-ptrauth-init-fini-address-discrimination -fptrauth-init-fini-address-discrimination \
// RUN: %s 2>&1 | FileCheck %s --check-prefix=ALL
// ALL: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-init-fini" "-fptrauth-indirect-gotos"
// ALL: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos" "-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination"

// RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI1
// RUN: %clang -### -c --target=aarch64-linux-pauthtest %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI1
Expand All @@ -36,8 +37,8 @@

// RUN: not %clang -### -c --target=x86_64 -fptrauth-intrinsics -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps \
// RUN: -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination \
// RUN: -fptrauth-type-info-vtable-pointer-discrimination -fptrauth-indirect-gotos -fptrauth-init-fini %s 2>&1 | \
// RUN: FileCheck %s --check-prefix=ERR1
// RUN: -fptrauth-type-info-vtable-pointer-discrimination -fptrauth-indirect-gotos -fptrauth-init-fini \
// RUN: -fptrauth-init-fini-address-discrimination %s 2>&1 | FileCheck %s --check-prefix=ERR1
// ERR1: error: unsupported option '-fptrauth-intrinsics' for target '{{.*}}'
// ERR1-NEXT: error: unsupported option '-fptrauth-calls' for target '{{.*}}'
// ERR1-NEXT: error: unsupported option '-fptrauth-returns' for target '{{.*}}'
Expand All @@ -47,6 +48,7 @@
// ERR1-NEXT: error: unsupported option '-fptrauth-type-info-vtable-pointer-discrimination' for target '{{.*}}'
// ERR1-NEXT: error: unsupported option '-fptrauth-indirect-gotos' for target '{{.*}}'
// ERR1-NEXT: error: unsupported option '-fptrauth-init-fini' for target '{{.*}}'
// ERR1-NEXT: error: unsupported option '-fptrauth-init-fini-address-discrimination' for target '{{.*}}'

//// Only support PAuth ABI for Linux as for now.
// RUN: not %clang -o /dev/null -c --target=aarch64-unknown -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR2
Expand Down
Loading