Skip to content

[clang][ObjC][PAC] Add ptrauth protections to objective-c #147899

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
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
16 changes: 15 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1003,15 +1003,29 @@ Arm and AArch64 Support
`as specified here <https://github.com/ARM-software/acle/blob/main/main/acle.md#modal-8-bit-floating-point-extensions>`_
is now available.
- Support has been added for the following processors (command-line identifiers in parentheses):

- Arm Cortex-A320 (``cortex-a320``)

- For ARM targets, cc1as now considers the FPU's features for the selected CPU or Architecture.
- The ``+nosimd`` attribute is now fully supported for ARM. Previously, this had no effect when being used with
ARM targets, however this will now disable NEON instructions being generated. The ``simd`` option is
also now printed when the ``--print-supported-extensions`` option is used.
- When a feature that depends on NEON (``simd``) is used, NEON is now automatically enabled.
- When NEON is disabled (``+nosimd``), all features that depend on NEON will now be disabled.

- Support for __ptrauth type qualifier has been added.
- Pointer authentication

- Support for __ptrauth type qualifier has been added.
- Objective-C adoption of pointer authentication

- ``isa`` and ``super`` pointers are protected with address diversity and separate
usage specific discriminators.
- methodlist pointers and content are protected with address diversity and methodlist
pointers have a usage specific discriminator.
- ``class_ro_t`` pointers are protected with address diversity and usage specific
discriminators.
- ``SEL`` typed ivars are protected with address diversity and usage specific
discriminators.

- For AArch64, added support for generating executable-only code sections by using the
``-mexecute-only`` or ``-mpure-code`` compiler flags. (#GH125688)
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -2300,6 +2300,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
return getTypeDeclType(getObjCSelDecl());
}

PointerAuthQualifier getObjCMemberSelTypePtrAuth();

/// Retrieve the typedef declaration corresponding to the predefined
/// Objective-C 'Class' type.
TypedefDecl *getObjCClassDecl() const;
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,12 @@ FEATURE(ptrauth_indirect_gotos, LangOpts.PointerAuthIndirectGotos)
FEATURE(ptrauth_init_fini, LangOpts.PointerAuthInitFini)
FEATURE(ptrauth_init_fini_address_discrimination, LangOpts.PointerAuthInitFiniAddressDiscrimination)
FEATURE(ptrauth_elf_got, LangOpts.PointerAuthELFGOT)

FEATURE(ptrauth_objc_isa, LangOpts.PointerAuthObjcIsa)
FEATURE(ptrauth_objc_interface_sel, LangOpts.PointerAuthObjcInterfaceSel)
FEATURE(ptrauth_objc_signable_class, true)
FEATURE(ptrauth_objc_method_list_pointer, LangOpts.PointerAuthCalls)

EXTENSION(swiftcc,
PP.getTargetInfo().checkCallingConvention(CC_Swift) ==
clang::TargetInfo::CCCR_OK)
Expand Down
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/LangOptions.def
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ LANGOPT(PointerAuthInitFiniAddressDiscrimination, 1, 0, NotCompatible,
LANGOPT(PointerAuthELFGOT, 1, 0, NotCompatible, "authenticate pointers from GOT")
LANGOPT(AArch64JumpTableHardening, 1, 0, NotCompatible, "use hardened lowering for jump-table dispatch")

LANGOPT(PointerAuthObjcIsa, 1, 0, NotCompatible, "authentication of isa and super pointers in ObjC instances")
LANGOPT(PointerAuthObjcInterfaceSel, 1, 0, NotCompatible, "authentication of SEL fields of ObjC interfaces")
LANGOPT(PointerAuthObjcInterfaceSelKey, 16, 0, NotCompatible, "authentication key for SEL fields of ObjC interfaces")
LANGOPT(PointerAuthObjcClassROPointers, 1, 0, Benign, "class_ro_t pointer authentication")

LANGOPT(DoubleSquareBracketAttributes, 1, 0, NotCompatible, "'[[]]' attributes extension for all language standard modes")
LANGOPT(ExperimentalLateParseAttributes, 1, 0, NotCompatible, "experimental late parsing of attributes")

Expand Down
35 changes: 35 additions & 0 deletions clang/include/clang/Basic/PointerAuthOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,26 @@ namespace clang {
/// .fini_array. The value is ptrauth_string_discriminator("init_fini")
constexpr uint16_t InitFiniPointerConstantDiscriminator = 0xD9D4;

/// Constant discriminator to be used with method list pointers. The value is
/// ptrauth_string_discriminator("method_list_t")
constexpr uint16_t MethodListPointerConstantDiscriminator = 0xC310;

/// Constant discriminator to be used with objective-c isa pointers. The value
/// is ptrauth_string_discriminator("isa")
constexpr uint16_t IsaPointerConstantDiscriminator = 0x6AE1;

/// Constant discriminator to be used with objective-c superclass pointers.
/// The value is ptrauth_string_discriminator("objc_class:superclass")
constexpr uint16_t SuperPointerConstantDiscriminator = 0xB5AB;

/// Constant discriminator to be used with objective-c sel pointers. The value
/// is ptrauth_string_discriminator("sel")
constexpr uint16_t SelPointerConstantDiscriminator = 0x57c2;

/// Constant discriminator to be used with objective-c class_ro_t pointers.
/// The value is ptrauth_string_discriminator("class_data_bits")
constexpr uint16_t ClassROConstantDiscriminator = 0x61F8;

constexpr unsigned PointerAuthKeyNone = -1;

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

/// The ABI for function addresses in .init_array and .fini_array
PointerAuthSchema InitFiniPointers;

/// The ABI for Objective-C method lists.
PointerAuthSchema ObjCMethodListFunctionPointers;

/// The ABI for a reference to an Objective-C method list in _class_ro_t.
PointerAuthSchema ObjCMethodListPointer;

/// The ABI for Objective-C isa pointers.
PointerAuthSchema ObjCIsaPointers;

/// The ABI for Objective-C superclass pointers.
PointerAuthSchema ObjCSuperPointers;

/// The ABI for Objective-C class_ro_t pointers.
PointerAuthSchema ObjCClassROPointers;
};

} // end namespace clang
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -4504,6 +4504,9 @@ defm ptrauth_init_fini_address_discrimination : OptInCC1FFlag<"ptrauth-init-fini
"Enable address discrimination of function pointers in init/fini arrays">;
defm ptrauth_elf_got : OptInCC1FFlag<"ptrauth-elf-got", "Enable authentication of pointers from GOT (ELF only)">;
defm aarch64_jump_table_hardening: OptInCC1FFlag<"aarch64-jump-table-hardening", "Use hardened lowering for jump-table dispatch">;
defm ptrauth_objc_isa : OptInCC1FFlag<"ptrauth-objc-isa", "Enable signing and authentication of Objective-C object's 'isa' field">;
defm ptrauth_objc_interface_sel : OptInCC1FFlag<"ptrauth-objc-interface-sel", "Enable signing and authentication of Objective-C object's 'SEL' fields">;
defm ptrauth_objc_class_ro : OptInCC1FFlag<"ptrauth-objc-class-ro", "Enable signing and authentication for ObjC class_ro pointers">;
}

def fenable_matrix : Flag<["-"], "fenable-matrix">, Group<f_Group>,
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9783,6 +9783,17 @@ ObjCInterfaceDecl *ASTContext::getObjCProtocolDecl() const {
return ObjCProtocolClassDecl;
}

PointerAuthQualifier ASTContext::getObjCMemberSelTypePtrAuth() {
if (!getLangOpts().PointerAuthObjcInterfaceSel)
return PointerAuthQualifier();
return PointerAuthQualifier::Create(
getLangOpts().PointerAuthObjcInterfaceSelKey,
/*isAddressDiscriminated=*/true, SelPointerConstantDiscriminator,
PointerAuthenticationMode::SignAndAuth,
/*isIsaPointer=*/false,
/*authenticatesNullValues=*/false);
}

//===----------------------------------------------------------------------===//
// __builtin_va_list Construction Functions
//===----------------------------------------------------------------------===//
Expand Down
21 changes: 19 additions & 2 deletions clang/lib/CodeGen/CGBlocks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -853,9 +853,24 @@ llvm::Value *CodeGenFunction::EmitBlockLiteral(const CGBlockInfo &blockInfo) {
offset += size;
index++;
};
auto addSignedHeaderField =
[&](llvm::Value *Value, const PointerAuthSchema &Schema,
GlobalDecl Decl, QualType Type, CharUnits Size, const Twine &Name) {
auto StorageAddress = projectField(index, Name);
if (Schema) {
auto AuthInfo = EmitPointerAuthInfo(
Schema, StorageAddress.emitRawPointer(*this), Decl, Type);
Value = EmitPointerAuthSign(AuthInfo, Value);
}
Builder.CreateStore(Value, StorageAddress);
offset += Size;
index++;
};

if (!IsOpenCL) {
addHeaderField(isa, getPointerSize(), "block.isa");
addSignedHeaderField(
isa, CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers, GlobalDecl(),
QualType(), getPointerSize(), "block.isa");
addHeaderField(llvm::ConstantInt::get(IntTy, flags.getBitMask()),
getIntSize(), "block.flags");
addHeaderField(llvm::ConstantInt::get(IntTy, 0), getIntSize(),
Expand Down Expand Up @@ -1285,7 +1300,9 @@ static llvm::Constant *buildGlobalBlock(CodeGenModule &CGM,
if (IsWindows)
fields.addNullPointer(CGM.Int8PtrPtrTy);
else
fields.add(CGM.getNSConcreteGlobalBlock());
fields.addSignedPointer(CGM.getNSConcreteGlobalBlock(),
CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
GlobalDecl(), QualType());

// __flags
BlockFlags flags = BLOCK_IS_GLOBAL;
Expand Down
52 changes: 48 additions & 4 deletions clang/lib/CodeGen/CGObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1193,16 +1193,23 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
ivarAddr = ivarAddr.withElementType(bitcastType);
llvm::LoadInst *load = Builder.CreateLoad(ivarAddr, "load");
load->setAtomic(llvm::AtomicOrdering::Unordered);
llvm::Value *ivarVal = load;
if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) {
CGPointerAuthInfo SrcInfo = EmitPointerAuthInfo(PAQ, ivarAddr);
CGPointerAuthInfo TargetInfo =
CGM.getPointerAuthInfoForType(getterMethod->getReturnType());
ivarVal = emitPointerAuthResign(ivarVal, ivar->getType(), SrcInfo,
TargetInfo, /*isKnownNonNull=*/false);
}

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

Expand All @@ -1214,6 +1221,16 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
case PropertyImplStrategy::GetSetProperty: {
llvm::FunctionCallee getPropertyFn =
CGM.getObjCRuntime().GetPropertyGetFunction();

if (ivar->getType().getPointerAuth()) {
// This currently cannot be hit, but if we ever allow objc pointers
// to be signed, this will become possible. Reaching here would require
// a copy, weak, etc property backed by an authenticated pointer.
CGM.ErrorUnsupported(propImpl,
"Obj-C getter requiring pointer authentication");
return;
}

if (!getPropertyFn) {
CGM.ErrorUnsupported(propImpl, "Obj-C getter requiring atomic copy");
return;
Expand Down Expand Up @@ -1269,7 +1286,9 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
LValue LV = EmitLValueForIvar(TypeOfSelfObject(), LoadObjCSelf(), ivar, 0);

QualType ivarType = ivar->getType();
switch (getEvaluationKind(ivarType)) {
auto EvaluationKind = getEvaluationKind(ivarType);
assert(!ivarType.getPointerAuth() || EvaluationKind == TEK_Scalar);
switch (EvaluationKind) {
case TEK_Complex: {
ComplexPairTy pair = EmitLoadOfComplex(LV, SourceLocation());
EmitStoreOfComplex(pair, MakeAddrLValue(ReturnValue, ivarType),
Expand All @@ -1287,6 +1306,11 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
case TEK_Scalar: {
llvm::Value *value;
if (propType->isReferenceType()) {
if (ivarType.getPointerAuth()) {
CGM.ErrorUnsupported(propImpl,
"Obj-C getter for authenticated reference type");
return;
}
value = LV.getAddress().emitRawPointer(*this);
} else {
// We want to load and autoreleaseReturnValue ARC __weak ivars.
Expand All @@ -1300,7 +1324,19 @@ CodeGenFunction::generateObjCGetterBody(const ObjCImplementationDecl *classImpl,
// Otherwise we want to do a simple load, suppressing the
// final autorelease.
} else {
value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal();
if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) {
Address ivarAddr = LV.getAddress();
llvm::LoadInst *LoadInst = Builder.CreateLoad(ivarAddr, "load");
llvm::Value *Load = LoadInst;
auto SrcInfo = EmitPointerAuthInfo(PAQ, ivarAddr);
auto TargetInfo =
CGM.getPointerAuthInfoForType(getterMethod->getReturnType());
Load = emitPointerAuthResign(Load, ivarType, SrcInfo, TargetInfo,
/*isKnownNonNull=*/false);
value = Load;
} else
value = EmitLoadOfLValue(LV, SourceLocation()).getScalarVal();

AutoreleaseResult = false;
}

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

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

if (PointerAuthQualifier PAQ = ivar->getType().getPointerAuth()) {
QualType PropertyType = propImpl->getPropertyDecl()->getType();
CGPointerAuthInfo SrcInfo = CGM.getPointerAuthInfoForType(PropertyType);
CGPointerAuthInfo TargetInfo = EmitPointerAuthInfo(PAQ, ivarAddr);
load = emitPointerAuthResign(load, ivar->getType(), SrcInfo, TargetInfo,
/*isKnownNonNull=*/false);
}

// Perform an atomic store. There are no memory ordering requirements.
llvm::StoreInst *store = Builder.CreateStore(load, ivarAddr);
store->setAtomic(llvm::AtomicOrdering::Unordered);
Expand Down
Loading