diff options
Diffstat (limited to 'clang/lib/CodeGen/CGPointerAuth.cpp')
| -rw-r--r-- | clang/lib/CodeGen/CGPointerAuth.cpp | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp new file mode 100644 index 000000000000..673f6e60bfc3 --- /dev/null +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -0,0 +1,294 @@ +//===--- CGPointerAuth.cpp - IR generation for pointer authentication -----===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains common routines relating to the emission of +// pointer authentication operations. +// +//===----------------------------------------------------------------------===// + +#include "CodeGenFunction.h" +#include "CodeGenModule.h" +#include "clang/CodeGen/CodeGenABITypes.h" +#include "clang/CodeGen/ConstantInitBuilder.h" +#include "llvm/Support/SipHash.h" + +using namespace clang; +using namespace CodeGen; + +/// Given a pointer-authentication schema, return a concrete "other" +/// discriminator for it. +llvm::ConstantInt *CodeGenModule::getPointerAuthOtherDiscriminator( + const PointerAuthSchema &Schema, GlobalDecl Decl, QualType Type) { + switch (Schema.getOtherDiscrimination()) { + case PointerAuthSchema::Discrimination::None: + return nullptr; + + case PointerAuthSchema::Discrimination::Type: + llvm_unreachable("type discrimination not implemented yet"); + + case PointerAuthSchema::Discrimination::Decl: + assert(Decl.getDecl() && + "declaration not provided for decl-discriminated schema"); + return llvm::ConstantInt::get(IntPtrTy, + getPointerAuthDeclDiscriminator(Decl)); + + case PointerAuthSchema::Discrimination::Constant: + return llvm::ConstantInt::get(IntPtrTy, Schema.getConstantDiscrimination()); + } + llvm_unreachable("bad discrimination kind"); +} + +uint16_t CodeGen::getPointerAuthDeclDiscriminator(CodeGenModule &CGM, + GlobalDecl Declaration) { + return CGM.getPointerAuthDeclDiscriminator(Declaration); +} + +/// Return the "other" decl-specific discriminator for the given decl. +uint16_t +CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl Declaration) { + uint16_t &EntityHash = PtrAuthDiscriminatorHashes[Declaration]; + + if (EntityHash == 0) { + StringRef Name = getMangledName(Declaration); + EntityHash = llvm::getPointerAuthStableSipHash(Name); + } + + return EntityHash; +} + +/// Return the abstract pointer authentication schema for a pointer to the given +/// function type. +CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) { + const auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers; + if (!Schema) + return CGPointerAuthInfo(); + + assert(!Schema.isAddressDiscriminated() && + "function pointers cannot use address-specific discrimination"); + + assert(!Schema.hasOtherDiscrimination() && + "function pointers don't support any discrimination yet"); + + return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(), + /*IsaPointer=*/false, /*AuthenticatesNull=*/false, + /*Discriminator=*/nullptr); +} + +llvm::Value * +CodeGenFunction::EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress, + llvm::Value *Discriminator) { + StorageAddress = Builder.CreatePtrToInt(StorageAddress, IntPtrTy); + auto Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_blend); + return Builder.CreateCall(Intrinsic, {StorageAddress, Discriminator}); +} + +/// Emit the concrete pointer authentication informaton for the +/// given authentication schema. +CGPointerAuthInfo CodeGenFunction::EmitPointerAuthInfo( + const PointerAuthSchema &Schema, llvm::Value *StorageAddress, + GlobalDecl SchemaDecl, QualType SchemaType) { + if (!Schema) + return CGPointerAuthInfo(); + + llvm::Value *Discriminator = + CGM.getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType); + + if (Schema.isAddressDiscriminated()) { + assert(StorageAddress && + "address not provided for address-discriminated schema"); + + if (Discriminator) + Discriminator = + EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator); + else + Discriminator = Builder.CreatePtrToInt(StorageAddress, IntPtrTy); + } + + return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(), + Schema.isIsaPointer(), + Schema.authenticatesNullValues(), Discriminator); +} + +llvm::Constant * +CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, + llvm::Constant *StorageAddress, + llvm::ConstantInt *OtherDiscriminator) { + llvm::Constant *AddressDiscriminator; + if (StorageAddress) { + assert(StorageAddress->getType() == UnqualPtrTy); + AddressDiscriminator = StorageAddress; + } else { + AddressDiscriminator = llvm::Constant::getNullValue(UnqualPtrTy); + } + + llvm::ConstantInt *IntegerDiscriminator; + if (OtherDiscriminator) { + assert(OtherDiscriminator->getType() == Int64Ty); + IntegerDiscriminator = OtherDiscriminator; + } else { + IntegerDiscriminator = llvm::ConstantInt::get(Int64Ty, 0); + } + + return llvm::ConstantPtrAuth::get(Pointer, + llvm::ConstantInt::get(Int32Ty, Key), + IntegerDiscriminator, AddressDiscriminator); +} + +/// Does a given PointerAuthScheme require us to sign a value +bool CodeGenModule::shouldSignPointer(const PointerAuthSchema &Schema) { + auto AuthenticationMode = Schema.getAuthenticationMode(); + return AuthenticationMode == PointerAuthenticationMode::SignAndStrip || + AuthenticationMode == PointerAuthenticationMode::SignAndAuth; +} + +/// Sign a constant pointer using the given scheme, producing a constant +/// with the same IR type. +llvm::Constant *CodeGenModule::getConstantSignedPointer( + llvm::Constant *Pointer, const PointerAuthSchema &Schema, + llvm::Constant *StorageAddress, GlobalDecl SchemaDecl, + QualType SchemaType) { + assert(shouldSignPointer(Schema)); + llvm::ConstantInt *OtherDiscriminator = + getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType); + + return getConstantSignedPointer(Pointer, Schema.getKey(), StorageAddress, + OtherDiscriminator); +} + +/// If applicable, sign a given constant function pointer with the ABI rules for +/// functionType. +llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer, + QualType FunctionType) { + assert(FunctionType->isFunctionType() || + FunctionType->isFunctionReferenceType() || + FunctionType->isFunctionPointerType()); + + if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType)) + return getConstantSignedPointer( + Pointer, PointerAuth.getKey(), /*StorageAddress=*/nullptr, + cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator())); + + return Pointer; +} + +llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD, + llvm::Type *Ty) { + const auto *FD = cast<FunctionDecl>(GD.getDecl()); + QualType FuncType = FD->getType(); + return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType); +} + +std::optional<PointerAuthQualifier> +CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) { + auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers; + if (!DefaultAuthentication) + return std::nullopt; + const CXXRecordDecl *PrimaryBase = + Context.baseForVTableAuthentication(ThisClass); + + unsigned Key = DefaultAuthentication.getKey(); + bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated(); + auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination(); + unsigned TypeBasedDiscriminator = + Context.getPointerAuthVTablePointerDiscriminator(PrimaryBase); + unsigned Discriminator; + if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) { + Discriminator = TypeBasedDiscriminator; + } else if (DefaultDiscrimination == + PointerAuthSchema::Discrimination::Constant) { + Discriminator = DefaultAuthentication.getConstantDiscrimination(); + } else { + assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None); + Discriminator = 0; + } + if (auto ExplicitAuthentication = + PrimaryBase->getAttr<VTablePointerAuthenticationAttr>()) { + auto ExplicitAddressDiscrimination = + ExplicitAuthentication->getAddressDiscrimination(); + auto ExplicitDiscriminator = + ExplicitAuthentication->getExtraDiscrimination(); + + unsigned ExplicitKey = ExplicitAuthentication->getKey(); + if (ExplicitKey == VTablePointerAuthenticationAttr::NoKey) + return std::nullopt; + + if (ExplicitKey != VTablePointerAuthenticationAttr::DefaultKey) { + if (ExplicitKey == VTablePointerAuthenticationAttr::ProcessIndependent) + Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDA; + else { + assert(ExplicitKey == + VTablePointerAuthenticationAttr::ProcessDependent); + Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDB; + } + } + + if (ExplicitAddressDiscrimination != + VTablePointerAuthenticationAttr::DefaultAddressDiscrimination) + AddressDiscriminated = + ExplicitAddressDiscrimination == + VTablePointerAuthenticationAttr::AddressDiscrimination; + + if (ExplicitDiscriminator == + VTablePointerAuthenticationAttr::TypeDiscrimination) + Discriminator = TypeBasedDiscriminator; + else if (ExplicitDiscriminator == + VTablePointerAuthenticationAttr::CustomDiscrimination) + Discriminator = ExplicitAuthentication->getCustomDiscriminationValue(); + else if (ExplicitDiscriminator == + VTablePointerAuthenticationAttr::NoExtraDiscrimination) + Discriminator = 0; + } + return PointerAuthQualifier::Create(Key, AddressDiscriminated, Discriminator, + PointerAuthenticationMode::SignAndAuth, + /* IsIsaPointer */ false, + /* AuthenticatesNullValues */ false); +} + +std::optional<PointerAuthQualifier> +CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) { + if (!Record->getDefinition() || !Record->isPolymorphic()) + return std::nullopt; + + auto Existing = VTablePtrAuthInfos.find(Record); + std::optional<PointerAuthQualifier> Authentication; + if (Existing != VTablePtrAuthInfos.end()) { + Authentication = Existing->getSecond(); + } else { + Authentication = computeVTPointerAuthentication(Record); + VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication)); + } + return Authentication; +} + +std::optional<CGPointerAuthInfo> +CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF, + const CXXRecordDecl *Record, + llvm::Value *StorageAddress) { + auto Authentication = getVTablePointerAuthentication(Record); + if (!Authentication) + return std::nullopt; + + llvm::Value *Discriminator = nullptr; + if (auto ExtraDiscriminator = Authentication->getExtraDiscriminator()) + Discriminator = llvm::ConstantInt::get(IntPtrTy, ExtraDiscriminator); + + if (Authentication->isAddressDiscriminated()) { + assert(StorageAddress && + "address not provided for address-discriminated schema"); + if (Discriminator) + Discriminator = + CGF->EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator); + else + Discriminator = CGF->Builder.CreatePtrToInt(StorageAddress, IntPtrTy); + } + + return CGPointerAuthInfo(Authentication->getKey(), + PointerAuthenticationMode::SignAndAuth, + /* IsIsaPointer */ false, + /* AuthenticatesNullValues */ false, Discriminator); +} |
