diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index fe4d1c4afcca6..b762e44e755ec 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -103,6 +103,12 @@ FEATURE(thread_sanitizer, LangOpts.Sanitize.has(SanitizerKind::Thread)) FEATURE(dataflow_sanitizer, LangOpts.Sanitize.has(SanitizerKind::DataFlow)) FEATURE(scudo, LangOpts.Sanitize.hasOneOf(SanitizerKind::Scudo)) FEATURE(ptrauth_intrinsics, LangOpts.PointerAuthIntrinsics) +FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls) +FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns) +FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination) +FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination) +FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls) +FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini) EXTENSION(swiftcc, PP.getTargetInfo().checkCallingConvention(CC_Swift) == clang::TargetInfo::CCCR_OK) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index c967d8b22292a..09eb92d6f10d2 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -162,6 +162,12 @@ LANGOPT(RelaxedTemplateTemplateArgs, 1, 1, "C++17 relaxed matching of template t LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library features") LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics") +LANGOPT(PointerAuthCalls , 1, 0, "function pointer authentication") +LANGOPT(PointerAuthReturns, 1, 0, "return pointer authentication") +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(PointerAuthInitFini, 1, 0, "sign 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") diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 1429528975853..73a2518480e9b 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4180,6 +4180,14 @@ defm strict_return : BoolFOption<"strict-return", let Flags = [TargetSpecific] in { defm ptrauth_intrinsics : OptInCC1FFlag<"ptrauth-intrinsics", "Enable pointer authentication intrinsics">; +defm ptrauth_calls : OptInCC1FFlag<"ptrauth-calls", "Enable signing and authentication of all indirect calls">; +defm ptrauth_returns : OptInCC1FFlag<"ptrauth-returns", "Enable signing and authentication of return addresses">; +defm ptrauth_auth_traps : OptInCC1FFlag<"ptrauth-auth-traps", "Enable traps on authentication failures">; +defm ptrauth_vtable_pointer_address_discrimination : + OptInCC1FFlag<"ptrauth-vtable-pointer-address-discrimination", "Enable address discrimination of vtable pointers">; +defm ptrauth_vtable_pointer_type_discrimination : + OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">; +defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">; } def fenable_matrix : Flag<["-"], "fenable-matrix">, Group, diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c8898ce196c1e..489c08a4d4819 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -53,6 +53,7 @@ #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Analysis/TargetLibraryInfo.h" +#include "llvm/BinaryFormat/ELF.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/IR/AttributeMask.h" #include "llvm/IR/CallingConv.h" @@ -1190,6 +1191,37 @@ void CodeGenModule::Release() { if (!LangOpts.isSignReturnAddressWithAKey()) getModule().addModuleFlag(llvm::Module::Min, "sign-return-address-with-bkey", 1); + + if (getTriple().isOSLinux()) { + assert(getTriple().isOSBinFormatELF()); + using namespace llvm::ELF; + uint64_t PAuthABIVersion = + (LangOpts.PointerAuthIntrinsics + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_INTRINSICS) | + (LangOpts.PointerAuthCalls + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_CALLS) | + (LangOpts.PointerAuthReturns + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_RETURNS) | + (LangOpts.PointerAuthAuthTraps + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_AUTHTRAPS) | + (LangOpts.PointerAuthVTPtrAddressDiscrimination + << AARCH64_PAUTH_PLATFORM_LLVM_LINUX_VERSION_VPTRADDRDISCR) | + (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"); + if (PAuthABIVersion != 0) { + getModule().addModuleFlag(llvm::Module::Error, + "aarch64-elf-pauthabi-platform", + AARCH64_PAUTH_PLATFORM_LLVM_LINUX); + getModule().addModuleFlag(llvm::Module::Error, + "aarch64-elf-pauthabi-version", + PAuthABIVersion); + } + } } if (CodeGenOpts.StackClashProtector) diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index 0a2ea96de7382..775dc249999e1 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -1756,6 +1756,20 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args, Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_intrinsics, options::OPT_fno_ptrauth_intrinsics); + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_calls, + options::OPT_fno_ptrauth_calls); + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_returns, + options::OPT_fno_ptrauth_returns); + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_auth_traps, + options::OPT_fno_ptrauth_auth_traps); + Args.addOptInFlag( + CmdArgs, options::OPT_fptrauth_vtable_pointer_address_discrimination, + options::OPT_fno_ptrauth_vtable_pointer_address_discrimination); + Args.addOptInFlag( + CmdArgs, options::OPT_fptrauth_vtable_pointer_type_discrimination, + options::OPT_fno_ptrauth_vtable_pointer_type_discrimination); + Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_init_fini, + options::OPT_fno_ptrauth_init_fini); } void Clang::AddLoongArchTargetArgs(const ArgList &Args, diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index 948fe08c863a6..dbb5f5662ebf1 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -3346,11 +3346,31 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts, ArgumentConsumer Consumer) { if (Opts.PointerAuthIntrinsics) GenerateArg(Consumer, OPT_fptrauth_intrinsics); + if (Opts.PointerAuthCalls) + GenerateArg(Consumer, OPT_fptrauth_calls); + if (Opts.PointerAuthReturns) + GenerateArg(Consumer, OPT_fptrauth_returns); + if (Opts.PointerAuthAuthTraps) + GenerateArg(Consumer, OPT_fptrauth_auth_traps); + if (Opts.PointerAuthVTPtrAddressDiscrimination) + GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination); + if (Opts.PointerAuthVTPtrTypeDiscrimination) + GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination); + if (Opts.PointerAuthInitFini) + GenerateArg(Consumer, OPT_fptrauth_init_fini); } static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args, DiagnosticsEngine &Diags) { Opts.PointerAuthIntrinsics = Args.hasArg(OPT_fptrauth_intrinsics); + Opts.PointerAuthCalls = Args.hasArg(OPT_fptrauth_calls); + Opts.PointerAuthReturns = Args.hasArg(OPT_fptrauth_returns); + Opts.PointerAuthAuthTraps = Args.hasArg(OPT_fptrauth_auth_traps); + Opts.PointerAuthVTPtrAddressDiscrimination = + Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination); + Opts.PointerAuthVTPtrTypeDiscrimination = + Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination); + Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini); } /// Check if input file kind and language standard are compatible. diff --git a/clang/test/CodeGen/aarch64-elf-pauthabi.c b/clang/test/CodeGen/aarch64-elf-pauthabi.c new file mode 100644 index 0000000000000..aa83ee3e0d7b0 --- /dev/null +++ b/clang/test/CodeGen/aarch64-elf-pauthabi.c @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-auth-traps \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini %s | \ +// RUN: FileCheck %s --check-prefix=ALL + +// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \ +// RUN: -fptrauth-intrinsics %s | FileCheck %s --check-prefix=INTRIN + +// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \ +// RUN: -fptrauth-calls %s | FileCheck %s --check-prefix=CALL + +// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \ +// RUN: -fptrauth-returns %s | FileCheck %s --check-prefix=RET + +// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \ +// RUN: -fptrauth-auth-traps %s | FileCheck %s --check-prefix=TRAP + +// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \ +// RUN: -fptrauth-calls -fptrauth-vtable-pointer-address-discrimination %s | \ +// RUN: FileCheck %s --check-prefix=VPTRADDR + +// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \ +// RUN: -fptrauth-calls -fptrauth-vtable-pointer-type-discrimination %s | \ +// RUN: FileCheck %s --check-prefix=VPTRTYPE + +// RUN: %clang_cc1 -triple aarch64-linux -emit-llvm -o - \ +// RUN: -fptrauth-calls -fptrauth-init-fini %s | \ +// RUN: FileCheck %s --check-prefix=INITFINI + +// ALL: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// ALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 127} + +// INTRIN: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// INTRIN: !{i32 1, !"aarch64-elf-pauthabi-version", i32 1} + +// CALL: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// CALL: !{i32 1, !"aarch64-elf-pauthabi-version", i32 2} + +// RET: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// RET: !{i32 1, !"aarch64-elf-pauthabi-version", i32 4} + +// TRAP: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// TRAP: !{i32 1, !"aarch64-elf-pauthabi-version", i32 8} + +// VPTRADDR: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// VPTRADDR: !{i32 1, !"aarch64-elf-pauthabi-version", i32 18} + +// VPTRTYPE: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// VPTRTYPE: !{i32 1, !"aarch64-elf-pauthabi-version", i32 34} + +// INITFINI: !{i32 1, !"aarch64-elf-pauthabi-platform", i32 268435458} +// INITFINI: !{i32 1, !"aarch64-elf-pauthabi-version", i32 66} + +void foo() {} diff --git a/clang/test/Driver/aarch64-ptrauth.c b/clang/test/Driver/aarch64-ptrauth.c index 1a69b2c6edfb1..fa0125f4b22a9 100644 --- a/clang/test/Driver/aarch64-ptrauth.c +++ b/clang/test/Driver/aarch64-ptrauth.c @@ -1,5 +1,25 @@ -// RUN: %clang -### -c --target=aarch64 -fno-ptrauth-intrinsics -fptrauth-intrinsics %s 2>&1 | FileCheck %s --check-prefix=INTRIN -// INTRIN: "-cc1"{{.*}} "-fptrauth-intrinsics" +// RUN: %clang -### -c --target=aarch64 %s 2>&1 | FileCheck %s --check-prefix NONE +// NONE: "-cc1" +// NONE-NOT: "-fptrauth- -// RUN: not %clang -### -c --target=x86_64 -fptrauth-intrinsics %s 2>&1 | FileCheck %s --check-prefix=ERR -// ERR: error: unsupported option '-fptrauth-intrinsics' for target '{{.*}}' +// RUN: %clang -### -c --target=aarch64 \ +// RUN: -fno-ptrauth-intrinsics -fptrauth-intrinsics \ +// RUN: -fno-ptrauth-calls -fptrauth-calls \ +// RUN: -fno-ptrauth-returns -fptrauth-returns \ +// RUN: -fno-ptrauth-auth-traps -fptrauth-auth-traps \ +// 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-init-fini -fptrauth-init-fini \ +// 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-init-fini" + +// 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-init-fini %s 2>&1 | FileCheck %s --check-prefix=ERR +// ERR: error: unsupported option '-fptrauth-intrinsics' for target '{{.*}}' +// ERR-NEXT: error: unsupported option '-fptrauth-calls' for target '{{.*}}' +// ERR-NEXT: error: unsupported option '-fptrauth-returns' for target '{{.*}}' +// ERR-NEXT: error: unsupported option '-fptrauth-auth-traps' for target '{{.*}}' +// ERR-NEXT: error: unsupported option '-fptrauth-vtable-pointer-address-discrimination' for target '{{.*}}' +// ERR-NEXT: error: unsupported option '-fptrauth-vtable-pointer-type-discrimination' for target '{{.*}}' +// ERR-NEXT: error: unsupported option '-fptrauth-init-fini' for target '{{.*}}' diff --git a/clang/test/Preprocessor/ptrauth_feature.c b/clang/test/Preprocessor/ptrauth_feature.c index e45c6ea90fd11..80e239110ffc7 100644 --- a/clang/test/Preprocessor/ptrauth_feature.c +++ b/clang/test/Preprocessor/ptrauth_feature.c @@ -1,5 +1,59 @@ -// RUN: %clang_cc1 %s -E -triple=arm64-- | FileCheck %s --check-prefixes=NOINTRIN -// RUN: %clang_cc1 %s -E -triple=arm64-- -fptrauth-intrinsics | FileCheck %s --check-prefixes=INTRIN +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=NOINTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,NOCALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,NORETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,NOVPTR_ADDR_DISCR,VPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-init-fini | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,NOVPTR_TYPE_DISCR,INITFINI + +// RUN: %clang_cc1 -E %s -triple=aarch64 \ +// RUN: -fptrauth-intrinsics \ +// RUN: -fptrauth-calls \ +// RUN: -fptrauth-returns \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-vtable-pointer-type-discrimination | \ +// RUN: FileCheck %s --check-prefixes=INTRIN,CALLS,RETS,VPTR_ADDR_DISCR,VPTR_TYPE_DISCR,NOINITFINI #if __has_feature(ptrauth_intrinsics) // INTRIN: has_ptrauth_intrinsics @@ -8,3 +62,52 @@ void has_ptrauth_intrinsics() {} // NOINTRIN: no_ptrauth_intrinsics void no_ptrauth_intrinsics() {} #endif + +#if __has_feature(ptrauth_calls) +// CALLS: has_ptrauth_calls +void has_ptrauth_calls() {} +#else +// NOCALLS: no_ptrauth_calls +void no_ptrauth_calls() {} +#endif + +// This is always enabled when ptrauth_calls is enabled +#if __has_feature(ptrauth_member_function_pointer_type_discrimination) +// CALLS: has_ptrauth_member_function_pointer_type_discrimination +void has_ptrauth_member_function_pointer_type_discrimination() {} +#else +// NOCALLS: no_ptrauth_member_function_pointer_type_discrimination +void no_ptrauth_member_function_pointer_type_discrimination() {} +#endif + +#if __has_feature(ptrauth_returns) +// RETS: has_ptrauth_returns +void has_ptrauth_returns() {} +#else +// NORETS: no_ptrauth_returns +void no_ptrauth_returns() {} +#endif + +#if __has_feature(ptrauth_vtable_pointer_address_discrimination) +// VPTR_ADDR_DISCR: has_ptrauth_vtable_pointer_address_discrimination +void has_ptrauth_vtable_pointer_address_discrimination() {} +#else +// NOVPTR_ADDR_DISCR: no_ptrauth_vtable_pointer_address_discrimination +void no_ptrauth_vtable_pointer_address_discrimination() {} +#endif + +#if __has_feature(ptrauth_vtable_pointer_type_discrimination) +// VPTR_TYPE_DISCR: has_ptrauth_vtable_pointer_type_discrimination +void has_ptrauth_vtable_pointer_type_discrimination() {} +#else +// NOVPTR_TYPE_DISCR: no_ptrauth_vtable_pointer_type_discrimination +void no_ptrauth_vtable_pointer_type_discrimination() {} +#endif + +#if __has_feature(ptrauth_init_fini) +// INITFINI: has_ptrauth_init_fini +void has_ptrauth_init_fini() {} +#else +// NOINITFINI: no_ptrauth_init_fini +void no_ptrauth_init_fini() {} +#endif