summaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CGPointerAuth.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen/CGPointerAuth.cpp')
-rw-r--r--clang/lib/CodeGen/CGPointerAuth.cpp294
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);
+}