From f46421f8e0349f65f07ab3bd822e179bf983439f Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Wed, 17 Jul 2024 16:18:41 -0700 Subject: [PATCH 1/2] [clang] Implement type/address discrimination of type_info vtable. We want to be able to support full type and address discrimination of type_info on targets that don't have existing ABI compatibility constraints. This patch does not enable such behavior on any platform, it just adds the necessary machinery. In clang we add a new commandline argument to control the type_info vtable ABI: -fptrauth-type-info-vtable-pointer-discrimination and a feature flag to allow source level detection of the ABI: __has_feature(ptrauth_type_info_vtable_pointer_discrimination) --- clang/include/clang/Basic/Features.def | 1 + clang/include/clang/Basic/LangOptions.def | 1 + .../include/clang/Basic/PointerAuthOptions.h | 5 ++ clang/include/clang/Driver/Options.td | 2 + clang/lib/Frontend/CompilerInvocation.cpp | 17 +++- .../CodeGenCXX/ptrauth-type-info-vtable.cpp | 87 +++++++++++++++++++ 6 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp diff --git a/clang/include/clang/Basic/Features.def b/clang/include/clang/Basic/Features.def index 2f864ff1c0edfe..14572bc0407fca 100644 --- a/clang/include/clang/Basic/Features.def +++ b/clang/include/clang/Basic/Features.def @@ -108,6 +108,7 @@ 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_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) diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index a6f36b23f07dc8..8b09049b5cb97b 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -168,6 +168,7 @@ 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(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") diff --git a/clang/include/clang/Basic/PointerAuthOptions.h b/clang/include/clang/Basic/PointerAuthOptions.h index 197d63642ca6d2..61532094108436 100644 --- a/clang/include/clang/Basic/PointerAuthOptions.h +++ b/clang/include/clang/Basic/PointerAuthOptions.h @@ -25,6 +25,11 @@ namespace clang { constexpr unsigned PointerAuthKeyNone = -1; +/// Constant discriminator for std::type_info vtable pointers: 0xB1EA/45546 +/// The value is ptrauth_string_discriminator("_ZTVSt9type_info"), i.e., +/// the vtable type discriminator for classes derived from std::type_info. +constexpr uint16_t StdTypeInfoVTablePointerConstantDiscrimination = 0xB1EA; + class PointerAuthSchema { public: enum class Kind : unsigned { diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 9c6cebd77ff0aa..70dab1b16094dd 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -4249,6 +4249,8 @@ 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_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">; diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp index bf57addff1c6df..424fe53990c384 100644 --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -1488,8 +1488,15 @@ void CompilerInvocation::setDefaultPointerAuthOptions( Key::ASDA, LangOpts.PointerAuthVTPtrAddressDiscrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination ? Discrimination::Type : Discrimination::None); - Opts.CXXTypeInfoVTablePointer = - PointerAuthSchema(Key::ASDA, false, Discrimination::None); + + if (LangOpts.PointerAuthTypeInfoVTPtrDiscrimination) + Opts.CXXTypeInfoVTablePointer = + PointerAuthSchema(Key::ASDA, true, Discrimination::Constant, + StdTypeInfoVTablePointerConstantDiscrimination); + else + Opts.CXXTypeInfoVTablePointer = + PointerAuthSchema(Key::ASDA, false, Discrimination::None); + Opts.CXXVTTVTablePointers = PointerAuthSchema(Key::ASDA, false, Discrimination::None); Opts.CXXVirtualFunctionPointers = Opts.CXXVirtualVariadicFunctionPointers = @@ -3411,6 +3418,9 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts, GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination); if (Opts.PointerAuthVTPtrTypeDiscrimination) 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) @@ -3427,6 +3437,9 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args, Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination); Opts.PointerAuthVTPtrTypeDiscrimination = 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); diff --git a/clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp b/clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp new file mode 100644 index 00000000000000..5fde93c309c30c --- /dev/null +++ b/clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp @@ -0,0 +1,87 @@ +// RUN: %clang_cc1 -DENABLE_TID=0 -I%S -std=c++11 -triple=arm64e-apple-darwin \ +// RUN: -fptrauth-calls -fptrauth-intrinsics \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NODISC + +// RUN: %clang_cc1 -DENABLE_TID=1 -I%S -std=c++11 -triple=arm64e-apple-darwin \ +// RUN: -fptrauth-calls -fptrauth-intrinsics \ +// RUN: -fptrauth-vtable-pointer-type-discrimination \ +// RUN: -fptrauth-vtable-pointer-address-discrimination \ +// RUN: -fptrauth-type-info-vtable-pointer-discrimination \ +// RUN: %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,DISC + +// copied from typeinfo +namespace std { + +#if __has_cpp_attribute(clang::ptrauth_vtable_pointer) +# if __has_feature(ptrauth_type_info_vtable_pointer_discrimination) +# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \ + [[clang::ptrauth_vtable_pointer(process_independent, address_discrimination, type_discrimination)]] +# else +# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \ + [[clang::ptrauth_vtable_pointer(process_independent, no_address_discrimination, no_extra_discrimination)]] +# endif +#else +# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH +#endif + + class _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH type_info + { + type_info& operator=(const type_info&); + type_info(const type_info&); + + protected: + explicit type_info(const char* __n); + + public: + virtual ~type_info(); + + virtual void test_method(); + }; +} + +static_assert(__has_feature(ptrauth_type_info_vtable_pointer_discrimination) == ENABLE_TID, "incorrect feature state"); + +// CHECK: @disc_std_type_info = global i32 [[STDTYPEINFO_DISC:45546]] +extern "C" int disc_std_type_info = __builtin_ptrauth_string_discriminator("_ZTVSt9type_info"); + +// CHECK: @_ZTV10TestStruct = unnamed_addr constant { [4 x ptr] } { [4 x ptr] [ptr null, ptr @_ZTI10TestStruct, ptr ptrauth (ptr @_ZN10TestStructD1Ev, i32 0, i64 52216, ptr getelementptr inbounds ({ [4 x ptr] }, ptr @_ZTV10TestStruct, i32 0, i32 0, i32 2)), ptr ptrauth (ptr @_ZN10TestStructD0Ev, i32 0, i64 39671, ptr getelementptr inbounds ({ [4 x ptr] }, ptr @_ZTV10TestStruct, i32 0, i32 0, i32 3))] }, align 8 +// CHECK: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr] +// CHECK: @_ZTS10TestStruct = constant [13 x i8] c"10TestStruct\00", align 1 + +// NODISC: @_ZTI10TestStruct = constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2), ptr @_ZTS10TestStruct }, align 8 + +// DISC: @_ZTI10TestStruct = constant { ptr, ptr } { ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2, i64 [[STDTYPEINFO_DISC]]), ptr @_ZTS10TestStruct }, align 8 + +struct TestStruct { + virtual ~TestStruct(); + int a; +}; + +TestStruct::~TestStruct(){} + +extern "C" void test_vtable(std::type_info* t) { + t->test_method(); +} +// NODISC: define void @test_vtable(ptr noundef %t) +// NODISC: [[T_ADDR:%.*]] = alloca ptr, align 8 +// NODISC: store ptr %t, ptr [[T_ADDR]], align 8 +// NODISC: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8 +// NODISC: [[VPTR:%.*]] = load ptr, ptr [[T]], align 8 +// NODISC: [[CAST_VPTR:%.*]] = ptrtoint ptr [[VPTR]] to i64 +// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VPTR]], i32 2, i64 0) + +// DISC: define void @test_vtable(ptr noundef %t) +// DISC: [[T_ADDR:%.*]] = alloca ptr, align 8 +// DISC: store ptr %t, ptr [[T_ADDR]], align 8 +// DISC: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8 +// DISC: [[VPTR:%.*]] = load ptr, ptr [[T]], align 8 +// DISC: [[ADDR:%.*]] = ptrtoint ptr [[T]] to i64 +// DISC: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 [[STDTYPEINFO_DISC]]) +// DISC: [[VPTRI:%.*]] = ptrtoint ptr [[VPTR]] to i64 +// DISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VPTRI]], i32 2, i64 [[DISCRIMINATOR]]) + +extern "C" const void *ensure_typeinfo() { + return new TestStruct; +} From 486b202345b95dde4f687800d1a0896d797f0ead Mon Sep 17 00:00:00 2001 From: Ahmed Bougacha Date: Mon, 22 Jul 2024 16:35:22 -0700 Subject: [PATCH 2/2] Update clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp Co-authored-by: Daniil Kovalev --- clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp b/clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp index 5fde93c309c30c..d5f69e0485140f 100644 --- a/clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp +++ b/clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp @@ -39,7 +39,7 @@ namespace std { virtual void test_method(); }; -} +} // namespace std static_assert(__has_feature(ptrauth_type_info_vtable_pointer_discrimination) == ENABLE_TID, "incorrect feature state");