Skip to content
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

[clang] Implement type/address discrimination of type_info vtable. #99726

Merged
Show file tree
Hide file tree
Changes from 1 commit
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
1 change: 1 addition & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/PointerAuthOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;
Expand Down
17 changes: 15 additions & 2 deletions clang/lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 =
Expand Down Expand Up @@ -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)
Expand All @@ -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);
Expand Down
87 changes: 87 additions & 0 deletions clang/test/CodeGenCXX/ptrauth-type-info-vtable.cpp
Original file line number Diff line number Diff line change
@@ -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();
};
}
ahmedbougacha marked this conversation as resolved.
Show resolved Hide resolved

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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ahmedbougacha Here, we have

ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2, i64 [[STDTYPEINFO_DISC]])

This has constant discriminator, but does not have address discrimination, while it should be enabled with -fptrauth-type-info-vtable-pointer-discrimination. The correct output should be smth like (if we use a placeholder value ptr inttoptr (i64 1 to ptr) as storage address)

ptr ptrauth (ptr getelementptr inbounds (ptr, ptr @_ZTVN10__cxxabiv117__class_type_infoE, i64 2), i32 2, i64 [[STDTYPEINFO_DISC]], ptr inttoptr (i64 1 to ptr))

The root cause is described in my previous comment #99726.


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;
}