Skip to content

Commit 0d38b0d

Browse files
committed
[clang][ObjC][PAC] Add ptrauth protections to objective-c
This PR introduces the use of pointer authentication to objective-c[++]. This includes: * __ptrauth qualifier support for ivars * protection of isa and super fields * protection of SEL typed ivars * protection of class_ro_t data * protection of methodlist pointers and content
1 parent 34a1daa commit 0d38b0d

29 files changed

+979
-42
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,17 @@ Arm and AArch64 Support
10111011
- When a feature that depends on NEON (``simd``) is used, NEON is now automatically enabled.
10121012
- When NEON is disabled (``+nosimd``), all features that depend on NEON will now be disabled.
10131013

1014-
- Support for __ptrauth type qualifier has been added.
1014+
- Pointer authentication
1015+
- Support for __ptrauth type qualifier has been added.
1016+
- Objective-C hardening
1017+
- isa and super pointers are protected with address diversity and separate
1018+
usage specific discriminators.
1019+
- methodlist pointers and content are protected with address diversity and
1020+
methodlist pointers have a usage specific discriminator.
1021+
- class_ro_t pointers are protected with address diversity and usage
1022+
specific discriminators.
1023+
- SEL typed ivars are protected with address diversity and usage specific
1024+
discriminators.
10151025

10161026
- For AArch64, added support for generating executable-only code sections by using the
10171027
``-mexecute-only`` or ``-mpure-code`` compiler flags. (#GH125688)

clang/include/clang/AST/ASTContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2300,6 +2300,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
23002300
return getTypeDeclType(getObjCSelDecl());
23012301
}
23022302

2303+
PointerAuthQualifier getObjCMemberSelTypePtrAuth();
2304+
23032305
/// Retrieve the typedef declaration corresponding to the predefined
23042306
/// Objective-C 'Class' type.
23052307
TypedefDecl *getObjCClassDecl() const;

clang/include/clang/Basic/Features.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,12 @@ FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
119119
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
120120
FEATURE(ptrauth_init_fini_address_discrimination, LangOpts.PointerAuthInitFiniAddressDiscrimination)
121121
FEATURE(ptrauth_elf_got, LangOpts.PointerAuthELFGOT)
122+
123+
FEATURE(ptrauth_objc_isa, LangOpts.PointerAuthObjcIsa)
124+
FEATURE(ptrauth_objc_interface_sel, LangOpts.PointerAuthObjcInterfaceSel)
125+
FEATURE(ptrauth_objc_signable_class, true)
126+
FEATURE(ptrauth_objc_method_list_pointer, LangOpts.PointerAuthCalls)
127+
122128
EXTENSION(swiftcc,
123129
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
124130
clang::TargetInfo::CCCR_OK)

clang/include/clang/Basic/LangOptions.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,11 @@ LANGOPT(PointerAuthInitFiniAddressDiscrimination, 1, 0, NotCompatible,
133133
LANGOPT(PointerAuthELFGOT, 1, 0, NotCompatible, "authenticate pointers from GOT")
134134
LANGOPT(AArch64JumpTableHardening, 1, 0, NotCompatible, "use hardened lowering for jump-table dispatch")
135135

136+
LANGOPT(PointerAuthObjcIsa, 1, 0, NotCompatible, "authentication of isa and super pointers in ObjC instances")
137+
LANGOPT(PointerAuthObjcInterfaceSel, 1, 0, NotCompatible, "authentication of SEL fields of ObjC interfaces")
138+
LANGOPT(PointerAuthObjcInterfaceSelKey, 16, 0, NotCompatible, "authentication key for SEL fields of ObjC interfaces")
139+
LANGOPT(PointerAuthObjcClassROPointers, 1, 0, Benign, "class_ro_t pointer authentication")
140+
136141
LANGOPT(DoubleSquareBracketAttributes, 1, 0, NotCompatible, "'[[]]' attributes extension for all language standard modes")
137142
LANGOPT(ExperimentalLateParseAttributes, 1, 0, NotCompatible, "experimental late parsing of attributes")
138143

clang/include/clang/Basic/PointerAuthOptions.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,26 @@ namespace clang {
2727
/// .fini_array. The value is ptrauth_string_discriminator("init_fini")
2828
constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4;
2929

30+
/// Constant discriminator to be used with method list pointers. The value is
31+
/// ptrauth_string_discriminator("method_list_t")
32+
constexpr uint16_t MethodListPointerConstantDiscriminator = 0xC310;
33+
34+
/// Constant discriminator to be used with objective-c isa pointers. The value
35+
/// is ptrauth_string_discriminator("isa")
36+
constexpr uint16_t IsaPointerConstantDiscriminator = 0x6AE1;
37+
38+
/// Constant discriminator to be used with objective-c superclass pointers.
39+
/// The value is ptrauth_string_discriminator("objc_class:superclass")
40+
constexpr uint16_t SuperPointerConstantDiscriminator = 0xB5AB;
41+
42+
/// Constant discriminator to be used with objective-c sel pointers. The value
43+
/// is ptrauth_string_discriminator("sel")
44+
constexpr uint16_t SelPointerConstantDiscriminator = 0x57c2;
45+
46+
/// Constant discriminator to be used with objective-c class_ro_t pointers.
47+
/// The value is ptrauth_string_discriminator("class_data_bits")
48+
constexpr uint16_t ClassROConstantDiscriminator = 0x61F8;
49+
3050
constexpr unsigned PointerAuthKeyNone = -1;
3151

3252
/// Constant discriminator for std::type_info vtable pointers: 0xB1EA/45546
@@ -202,6 +222,21 @@ struct PointerAuthOptions {
202222

203223
/// The ABI for function addresses in .init_array and .fini_array
204224
PointerAuthSchema InitFiniPointers;
225+
226+
/// The ABI for Objective-C method lists.
227+
PointerAuthSchema ObjCMethodListFunctionPointers;
228+
229+
/// The ABI for a reference to an Objective-C method list in _class_ro_t.
230+
PointerAuthSchema ObjCMethodListPointer;
231+
232+
/// The ABI for Objective-C isa pointers.
233+
PointerAuthSchema ObjCIsaPointers;
234+
235+
/// The ABI for Objective-C superclass pointers.
236+
PointerAuthSchema ObjCSuperPointers;
237+
238+
/// The ABI for Objective-C class_ro_t pointers.
239+
PointerAuthSchema ObjCClassROPointers;
205240
};
206241

207242
} // end namespace clang

clang/include/clang/Driver/Options.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4504,6 +4504,9 @@ defm ptrauth_init_fini_address_discrimination : OptInCC1FFlag<"ptrauth-init-fini
45044504
"Enable address discrimination of function pointers in init/fini arrays">;
45054505
defm ptrauth_elf_got : OptInCC1FFlag<"ptrauth-elf-got", "Enable authentication of pointers from GOT (ELF only)">;
45064506
defm aarch64_jump_table_hardening: OptInCC1FFlag<"aarch64-jump-table-hardening", "Use hardened lowering for jump-table dispatch">;
4507+
defm ptrauth_objc_isa : OptInCC1FFlag<"ptrauth-objc-isa", "Enable signing and authentication of Objective-C object's 'isa' field">;
4508+
defm ptrauth_objc_interface_sel : OptInCC1FFlag<"ptrauth-objc-interface-sel", "Enable signing and authentication of Objective-C object's 'SEL' fields">;
4509+
defm ptrauth_objc_class_ro : OptInCC1FFlag<"ptrauth-objc-class-ro", "Enable signing and authentication for ObjC class_ro pointers">;
45074510
}
45084511

45094512
def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,

clang/lib/AST/ASTContext.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9783,6 +9783,17 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
97839783
return ObjCProtocolClassDecl;
97849784
}
97859785

9786+
PointerAuthQualifier ASTContext::getObjCMemberSelTypePtrAuth() {
9787+
if (!getLangOpts().PointerAuthObjcInterfaceSel)
9788+
return PointerAuthQualifier();
9789+
return PointerAuthQualifier::Create(
9790+
getLangOpts().PointerAuthObjcInterfaceSelKey,
9791+
/*isAddressDiscriminated=*/true, SelPointerConstantDiscriminator,
9792+
PointerAuthenticationMode::SignAndAuth,
9793+
/*isIsaPointer=*/false,
9794+
/*authenticatesNullValues=*/false);
9795+
}
9796+
97869797
//===----------------------------------------------------------------------===//
97879798
// __builtin_va_list Construction Functions
97889799
//===----------------------------------------------------------------------===//

clang/lib/CodeGen/CGBlocks.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -853,9 +853,24 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
853853
offset += size;
854854
index++;
855855
};
856+
auto addSignedHeaderField =
857+
[&](llvm::Value *Value, const PointerAuthSchema &Schema,
858+
GlobalDecl Decl, QualType Type, CharUnits Size, const Twine &Name) {
859+
auto StorageAddress = projectField(index, Name);
860+
if (Schema) {
861+
auto AuthInfo = EmitPointerAuthInfo(
862+
Schema, StorageAddress.emitRawPointer(*this), Decl, Type);
863+
Value = EmitPointerAuthSign(AuthInfo, Value);
864+
}
865+
Builder.CreateStore(Value, StorageAddress);
866+
offset += Size;
867+
index++;
868+
};
856869

857870
if (!IsOpenCL) {
858-
addHeaderField(isa, getPointerSize(), "block.isa");
871+
addSignedHeaderField(
872+
isa, CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers, GlobalDecl(),
873+
QualType(), getPointerSize(), "block.isa");
859874
addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
860875
getIntSize(), "block.flags");
861876
addHeaderField(llvm::ConstantInt::get(IntTy, 0), getIntSize(),
@@ -1285,7 +1300,9 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
12851300
if (IsWindows)
12861301
fields.addNullPointer(CGM.Int8PtrPtrTy);
12871302
else
1288-
fields.add(CGM.getNSConcreteGlobalBlock());
1303+
fields.addSignedPointer(CGM.getNSConcreteGlobalBlock(),
1304+
CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
1305+
GlobalDecl(), QualType());
12891306

12901307
// __flags
12911308
BlockFlags flags = BLOCK_IS_GLOBAL;

clang/lib/CodeGen/CGObjC.cpp

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1193,16 +1193,23 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
11931193
ivarAddr = ivarAddr.withElementType(bitcastType);
11941194
llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load");
11951195
load->setAtomic(llvm::AtomicOrdering::Unordered);
1196+
llvm::Value *ivarVal = load;
1197+
if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) {
1198+
CGPointerAuthInfo SrcInfo = EmitPointerAuthInfo(PAQ, ivarAddr);
1199+
CGPointerAuthInfo TargetInfo =
1200+
CGM.getPointerAuthInfoForType(getterMethod->getReturnType());
1201+
ivarVal = emitPointerAuthResign(ivarVal, ivar->getType(), SrcInfo,
1202+
TargetInfo, /*isKnownNonNull=*/false);
1203+
}
11961204

11971205
// Store that value into the return address. Doing this with a
11981206
// bitcast is likely to produce some pretty ugly IR, but it's not
11991207
// the *most* terrible thing in the world.
12001208
llvm::Type *retTy = ConvertType(getterMethod->getReturnType());
12011209
uint64_t retTySize = CGM.getDataLayout().getTypeSizeInBits(retTy);
1202-
llvm::Value *ivarVal = load;
12031210
if (ivarSize > retTySize) {
12041211
bitcastType = llvm::Type::getIntNTy(getLLVMContext(), retTySize);
1205-
ivarVal = Builder.CreateTrunc(load, bitcastType);
1212+
ivarVal = Builder.CreateTrunc(ivarVal, bitcastType);
12061213
}
12071214
Builder.CreateStore(ivarVal, ReturnValue.withElementType(bitcastType));
12081215

@@ -1214,6 +1221,16 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
12141221
case PropertyImplStrategy::GetSetProperty: {
12151222
llvm::FunctionCallee getPropertyFn =
12161223
CGM.getObjCRuntime().GetPropertyGetFunction();
1224+
1225+
if (ivar->getType().getPointerAuth()) {
1226+
// This currently cannot be hit, but if we ever allow objc pointers
1227+
// to be signed, this will become possible. Reaching here would require
1228+
// a copy, weak, etc property backed by an authenticated pointer.
1229+
CGM.ErrorUnsupported(propImpl,
1230+
"Obj-C getter requiring pointer authentication");
1231+
return;
1232+
}
1233+
12171234
if (!getPropertyFn) {
12181235
CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy");
12191236
return;
@@ -1269,7 +1286,9 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
12691286
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);
12701287

12711288
QualType ivarType = ivar->getType();
1272-
switch (getEvaluationKind(ivarType)) {
1289+
auto EvaluationKind = getEvaluationKind(ivarType);
1290+
assert(!ivarType.getPointerAuth() || EvaluationKind == TEK_Scalar);
1291+
switch (EvaluationKind) {
12731292
case TEK_Complex: {
12741293
ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation());
12751294
EmitStoreOfComplex(pair, MakeAddrLValue(ReturnValue, ivarType),
@@ -1287,6 +1306,11 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
12871306
case TEK_Scalar: {
12881307
llvm::Value *value;
12891308
if (propType->isReferenceType()) {
1309+
if (ivarType.getPointerAuth()) {
1310+
CGM.ErrorUnsupported(propImpl,
1311+
"Obj-C getter for authenticated reference type");
1312+
return;
1313+
}
12901314
value = LV.getAddress().emitRawPointer(*this);
12911315
} else {
12921316
// We want to load and autoreleaseReturnValue ARC __weak ivars.
@@ -1300,7 +1324,19 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
13001324
// Otherwise we want to do a simple load, suppressing the
13011325
// final autorelease.
13021326
} else {
1303-
value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal();
1327+
if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) {
1328+
Address ivarAddr = LV.getAddress();
1329+
llvm::LoadInst *LoadInst = Builder.CreateLoad(ivarAddr, "load");
1330+
llvm::Value *Load = LoadInst;
1331+
auto SrcInfo = EmitPointerAuthInfo(PAQ, ivarAddr);
1332+
auto TargetInfo =
1333+
CGM.getPointerAuthInfoForType(getterMethod->getReturnType());
1334+
Load = emitPointerAuthResign(Load, ivarType, SrcInfo, TargetInfo,
1335+
/*isKnownNonNull=*/false);
1336+
value = Load;
1337+
} else
1338+
value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal();
1339+
13041340
AutoreleaseResult = false;
13051341
}
13061342

@@ -1490,6 +1526,14 @@ CodeGenFunction::generateObjCSetterBody(const ObjCImplementationDecl *classImpl,
14901526

14911527
llvm::Value *load = Builder.CreateLoad(argAddr);
14921528

1529+
if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) {
1530+
QualType PropertyType = propImpl->getPropertyDecl()->getType();
1531+
CGPointerAuthInfo SrcInfo = CGM.getPointerAuthInfoForType(PropertyType);
1532+
CGPointerAuthInfo TargetInfo = EmitPointerAuthInfo(PAQ, ivarAddr);
1533+
load = emitPointerAuthResign(load, ivar->getType(), SrcInfo, TargetInfo,
1534+
/*isKnownNonNull=*/false);
1535+
}
1536+
14931537
// Perform an atomic store. There are no memory ordering requirements.
14941538
llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr);
14951539
store->setAtomic(llvm::AtomicOrdering::Unordered);

0 commit comments

Comments
 (0)