Skip to content

Commit b6dbda6

Browse files
[clang] Implement type/address discrimination of type_info vtable. (llvm#99726)
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) Co-authored-by: Oliver Hunt <[email protected]>
1 parent d4da96d commit b6dbda6

File tree

6 files changed

+111
-2
lines changed

6 files changed

+111
-2
lines changed

clang/include/clang/Basic/Features.def

+1
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ FEATURE(ptrauth_calls, LangOpts.PointerAuthCalls)
108108
FEATURE(ptrauth_returns, LangOpts.PointerAuthReturns)
109109
FEATURE(ptrauth_vtable_pointer_address_discrimination, LangOpts.PointerAuthVTPtrAddressDiscrimination)
110110
FEATURE(ptrauth_vtable_pointer_type_discrimination, LangOpts.PointerAuthVTPtrTypeDiscrimination)
111+
FEATURE(ptrauth_type_info_vtable_pointer_discrimination, LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
111112
FEATURE(ptrauth_member_function_pointer_type_discrimination, LangOpts.PointerAuthCalls)
112113
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
113114
FEATURE(ptrauth_function_pointer_type_discrimination, LangOpts.PointerAuthFunctionTypeDiscrimination)

clang/include/clang/Basic/LangOptions.def

+1
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ LANGOPT(PointerAuthReturns, 1, 0, "return pointer authentication")
168168
LANGOPT(PointerAuthAuthTraps, 1, 0, "pointer authentication failure traps")
169169
LANGOPT(PointerAuthVTPtrAddressDiscrimination, 1, 0, "incorporate address discrimination in authenticated vtable pointers")
170170
LANGOPT(PointerAuthVTPtrTypeDiscrimination, 1, 0, "incorporate type discrimination in authenticated vtable pointers")
171+
LANGOPT(PointerAuthTypeInfoVTPtrDiscrimination, 1, 0, "incorporate type and address discrimination in authenticated vtable pointers for std::type_info")
171172
LANGOPT(PointerAuthInitFini, 1, 0, "sign function pointers in init/fini arrays")
172173
BENIGN_LANGOPT(PointerAuthFunctionTypeDiscrimination, 1, 0,
173174
"Use type discrimination when signing function pointers")

clang/include/clang/Basic/PointerAuthOptions.h

+5
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@ namespace clang {
2525

2626
constexpr unsigned PointerAuthKeyNone = -1;
2727

28+
/// Constant discriminator for std::type_info vtable pointers: 0xB1EA/45546
29+
/// The value is ptrauth_string_discriminator("_ZTVSt9type_info"), i.e.,
30+
/// the vtable type discriminator for classes derived from std::type_info.
31+
constexpr uint16_t StdTypeInfoVTablePointerConstantDiscrimination = 0xB1EA;
32+
2833
class PointerAuthSchema {
2934
public:
3035
enum class Kind : unsigned {

clang/include/clang/Driver/Options.td

+2
Original file line numberDiff line numberDiff line change
@@ -4249,6 +4249,8 @@ defm ptrauth_vtable_pointer_address_discrimination :
42494249
OptInCC1FFlag<"ptrauth-vtable-pointer-address-discrimination", "Enable address discrimination of vtable pointers">;
42504250
defm ptrauth_vtable_pointer_type_discrimination :
42514251
OptInCC1FFlag<"ptrauth-vtable-pointer-type-discrimination", "Enable type discrimination of vtable pointers">;
4252+
defm ptrauth_type_info_vtable_pointer_discrimination :
4253+
OptInCC1FFlag<"ptrauth-type-info-vtable-pointer-discrimination", "Enable type and address discrimination of vtable pointer of std::type_info">;
42524254
defm ptrauth_init_fini : OptInCC1FFlag<"ptrauth-init-fini", "Enable signing of function pointers in init/fini arrays">;
42534255
defm ptrauth_function_pointer_type_discrimination : OptInCC1FFlag<"ptrauth-function-pointer-type-discrimination",
42544256
"Enable type discrimination on C function pointers">;

clang/lib/Frontend/CompilerInvocation.cpp

+15-2
Original file line numberDiff line numberDiff line change
@@ -1488,8 +1488,15 @@ void CompilerInvocation::setDefaultPointerAuthOptions(
14881488
Key::ASDA, LangOpts.PointerAuthVTPtrAddressDiscrimination,
14891489
LangOpts.PointerAuthVTPtrTypeDiscrimination ? Discrimination::Type
14901490
: Discrimination::None);
1491-
Opts.CXXTypeInfoVTablePointer =
1492-
PointerAuthSchema(Key::ASDA, false, Discrimination::None);
1491+
1492+
if (LangOpts.PointerAuthTypeInfoVTPtrDiscrimination)
1493+
Opts.CXXTypeInfoVTablePointer =
1494+
PointerAuthSchema(Key::ASDA, true, Discrimination::Constant,
1495+
StdTypeInfoVTablePointerConstantDiscrimination);
1496+
else
1497+
Opts.CXXTypeInfoVTablePointer =
1498+
PointerAuthSchema(Key::ASDA, false, Discrimination::None);
1499+
14931500
Opts.CXXVTTVTablePointers =
14941501
PointerAuthSchema(Key::ASDA, false, Discrimination::None);
14951502
Opts.CXXVirtualFunctionPointers = Opts.CXXVirtualVariadicFunctionPointers =
@@ -3411,6 +3418,9 @@ static void GeneratePointerAuthArgs(const LangOptions &Opts,
34113418
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_address_discrimination);
34123419
if (Opts.PointerAuthVTPtrTypeDiscrimination)
34133420
GenerateArg(Consumer, OPT_fptrauth_vtable_pointer_type_discrimination);
3421+
if (Opts.PointerAuthTypeInfoVTPtrDiscrimination)
3422+
GenerateArg(Consumer, OPT_fptrauth_type_info_vtable_pointer_discrimination);
3423+
34143424
if (Opts.PointerAuthInitFini)
34153425
GenerateArg(Consumer, OPT_fptrauth_init_fini);
34163426
if (Opts.PointerAuthFunctionTypeDiscrimination)
@@ -3427,6 +3437,9 @@ static void ParsePointerAuthArgs(LangOptions &Opts, ArgList &Args,
34273437
Args.hasArg(OPT_fptrauth_vtable_pointer_address_discrimination);
34283438
Opts.PointerAuthVTPtrTypeDiscrimination =
34293439
Args.hasArg(OPT_fptrauth_vtable_pointer_type_discrimination);
3440+
Opts.PointerAuthTypeInfoVTPtrDiscrimination =
3441+
Args.hasArg(OPT_fptrauth_type_info_vtable_pointer_discrimination);
3442+
34303443
Opts.PointerAuthInitFini = Args.hasArg(OPT_fptrauth_init_fini);
34313444
Opts.PointerAuthFunctionTypeDiscrimination =
34323445
Args.hasArg(OPT_fptrauth_function_pointer_type_discrimination);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
// RUN: %clang_cc1 -DENABLE_TID=0 -I%S -std=c++11 -triple=arm64e-apple-darwin \
2+
// RUN: -fptrauth-calls -fptrauth-intrinsics \
3+
// RUN: -fptrauth-vtable-pointer-type-discrimination \
4+
// RUN: -fptrauth-vtable-pointer-address-discrimination \
5+
// RUN: %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,NODISC
6+
7+
// RUN: %clang_cc1 -DENABLE_TID=1 -I%S -std=c++11 -triple=arm64e-apple-darwin \
8+
// RUN: -fptrauth-calls -fptrauth-intrinsics \
9+
// RUN: -fptrauth-vtable-pointer-type-discrimination \
10+
// RUN: -fptrauth-vtable-pointer-address-discrimination \
11+
// RUN: -fptrauth-type-info-vtable-pointer-discrimination \
12+
// RUN: %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,DISC
13+
14+
// copied from typeinfo
15+
namespace std {
16+
17+
#if __has_cpp_attribute(clang::ptrauth_vtable_pointer)
18+
# if __has_feature(ptrauth_type_info_vtable_pointer_discrimination)
19+
# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \
20+
[[clang::ptrauth_vtable_pointer(process_independent, address_discrimination, type_discrimination)]]
21+
# else
22+
# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH \
23+
[[clang::ptrauth_vtable_pointer(process_independent, no_address_discrimination, no_extra_discrimination)]]
24+
# endif
25+
#else
26+
# define _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH
27+
#endif
28+
29+
class _LIBCPP_TYPE_INFO_VTABLE_POINTER_AUTH type_info
30+
{
31+
type_info& operator=(const type_info&);
32+
type_info(const type_info&);
33+
34+
protected:
35+
explicit type_info(const char* __n);
36+
37+
public:
38+
virtual ~type_info();
39+
40+
virtual void test_method();
41+
};
42+
} // namespace std
43+
44+
static_assert(__has_feature(ptrauth_type_info_vtable_pointer_discrimination) == ENABLE_TID, "incorrect feature state");
45+
46+
// CHECK: @disc_std_type_info = global i32 [[STDTYPEINFO_DISC:45546]]
47+
extern "C" int disc_std_type_info = __builtin_ptrauth_string_discriminator("_ZTVSt9type_info");
48+
49+
// 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
50+
// CHECK: @_ZTVN10__cxxabiv117__class_type_infoE = external global [0 x ptr]
51+
// CHECK: @_ZTS10TestStruct = constant [13 x i8] c"10TestStruct\00", align 1
52+
53+
// 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
54+
55+
// 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
56+
57+
struct TestStruct {
58+
virtual ~TestStruct();
59+
int a;
60+
};
61+
62+
TestStruct::~TestStruct(){}
63+
64+
extern "C" void test_vtable(std::type_info* t) {
65+
t->test_method();
66+
}
67+
// NODISC: define void @test_vtable(ptr noundef %t)
68+
// NODISC: [[T_ADDR:%.*]] = alloca ptr, align 8
69+
// NODISC: store ptr %t, ptr [[T_ADDR]], align 8
70+
// NODISC: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8
71+
// NODISC: [[VPTR:%.*]] = load ptr, ptr [[T]], align 8
72+
// NODISC: [[CAST_VPTR:%.*]] = ptrtoint ptr [[VPTR]] to i64
73+
// NODISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[CAST_VPTR]], i32 2, i64 0)
74+
75+
// DISC: define void @test_vtable(ptr noundef %t)
76+
// DISC: [[T_ADDR:%.*]] = alloca ptr, align 8
77+
// DISC: store ptr %t, ptr [[T_ADDR]], align 8
78+
// DISC: [[T:%.*]] = load ptr, ptr [[T_ADDR]], align 8
79+
// DISC: [[VPTR:%.*]] = load ptr, ptr [[T]], align 8
80+
// DISC: [[ADDR:%.*]] = ptrtoint ptr [[T]] to i64
81+
// DISC: [[DISCRIMINATOR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[ADDR]], i64 [[STDTYPEINFO_DISC]])
82+
// DISC: [[VPTRI:%.*]] = ptrtoint ptr [[VPTR]] to i64
83+
// DISC: [[AUTHED:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[VPTRI]], i32 2, i64 [[DISCRIMINATOR]])
84+
85+
extern "C" const void *ensure_typeinfo() {
86+
return new TestStruct;
87+
}

0 commit comments

Comments
 (0)