767 lines · cpp
1//===--- CGPointerAuth.cpp - IR generation for pointer authentication -----===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file contains common routines relating to the emission of10// pointer authentication operations.11//12//===----------------------------------------------------------------------===//13 14#include "CodeGenFunction.h"15#include "CodeGenModule.h"16#include "clang/CodeGen/CodeGenABITypes.h"17#include "clang/CodeGen/ConstantInitBuilder.h"18#include "llvm/Analysis/ValueTracking.h"19#include "llvm/Support/SipHash.h"20 21using namespace clang;22using namespace CodeGen;23 24/// Given a pointer-authentication schema, return a concrete "other"25/// discriminator for it.26llvm::ConstantInt *CodeGenModule::getPointerAuthOtherDiscriminator(27 const PointerAuthSchema &Schema, GlobalDecl Decl, QualType Type) {28 switch (Schema.getOtherDiscrimination()) {29 case PointerAuthSchema::Discrimination::None:30 return nullptr;31 32 case PointerAuthSchema::Discrimination::Type:33 assert(!Type.isNull() && "type not provided for type-discriminated schema");34 return llvm::ConstantInt::get(35 IntPtrTy, getContext().getPointerAuthTypeDiscriminator(Type));36 37 case PointerAuthSchema::Discrimination::Decl:38 assert(Decl.getDecl() &&39 "declaration not provided for decl-discriminated schema");40 return llvm::ConstantInt::get(IntPtrTy,41 getPointerAuthDeclDiscriminator(Decl));42 43 case PointerAuthSchema::Discrimination::Constant:44 return llvm::ConstantInt::get(IntPtrTy, Schema.getConstantDiscrimination());45 }46 llvm_unreachable("bad discrimination kind");47}48 49uint16_t CodeGen::getPointerAuthTypeDiscriminator(CodeGenModule &CGM,50 QualType FunctionType) {51 return CGM.getContext().getPointerAuthTypeDiscriminator(FunctionType);52}53 54uint16_t CodeGen::getPointerAuthDeclDiscriminator(CodeGenModule &CGM,55 GlobalDecl Declaration) {56 return CGM.getPointerAuthDeclDiscriminator(Declaration);57}58 59/// Return the "other" decl-specific discriminator for the given decl.60uint16_t61CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl Declaration) {62 uint16_t &EntityHash = PtrAuthDiscriminatorHashes[Declaration];63 64 if (EntityHash == 0) {65 StringRef Name = getMangledName(Declaration);66 EntityHash = llvm::getPointerAuthStableSipHash(Name);67 }68 69 return EntityHash;70}71 72/// Return the abstract pointer authentication schema for a pointer to the given73/// function type.74CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) {75 const auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers;76 if (!Schema)77 return CGPointerAuthInfo();78 79 assert(!Schema.isAddressDiscriminated() &&80 "function pointers cannot use address-specific discrimination");81 82 llvm::Constant *Discriminator = nullptr;83 if (T->isFunctionPointerType() || T->isFunctionReferenceType())84 T = T->getPointeeType();85 if (T->isFunctionType())86 Discriminator = getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), T);87 88 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),89 /*IsaPointer=*/false, /*AuthenticatesNull=*/false,90 Discriminator);91}92 93llvm::Value *94CodeGenFunction::EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress,95 llvm::Value *Discriminator) {96 StorageAddress = Builder.CreatePtrToInt(StorageAddress, IntPtrTy);97 auto Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_blend);98 return Builder.CreateCall(Intrinsic, {StorageAddress, Discriminator});99}100 101/// Emit the concrete pointer authentication informaton for the102/// given authentication schema.103CGPointerAuthInfo CodeGenFunction::EmitPointerAuthInfo(104 const PointerAuthSchema &Schema, llvm::Value *StorageAddress,105 GlobalDecl SchemaDecl, QualType SchemaType) {106 if (!Schema)107 return CGPointerAuthInfo();108 109 llvm::Value *Discriminator =110 CGM.getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType);111 112 if (Schema.isAddressDiscriminated()) {113 assert(StorageAddress &&114 "address not provided for address-discriminated schema");115 116 if (Discriminator)117 Discriminator =118 EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);119 else120 Discriminator = Builder.CreatePtrToInt(StorageAddress, IntPtrTy);121 }122 123 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),124 Schema.isIsaPointer(),125 Schema.authenticatesNullValues(), Discriminator);126}127 128CGPointerAuthInfo129CodeGenFunction::EmitPointerAuthInfo(PointerAuthQualifier Qual,130 Address StorageAddress) {131 assert(Qual && "don't call this if you don't know that the Qual is present");132 if (Qual.hasKeyNone())133 return CGPointerAuthInfo();134 135 llvm::Value *Discriminator = nullptr;136 if (unsigned Extra = Qual.getExtraDiscriminator())137 Discriminator = llvm::ConstantInt::get(IntPtrTy, Extra);138 139 if (Qual.isAddressDiscriminated()) {140 assert(StorageAddress.isValid() &&141 "address discrimination without address");142 llvm::Value *StoragePtr = StorageAddress.emitRawPointer(*this);143 if (Discriminator)144 Discriminator =145 EmitPointerAuthBlendDiscriminator(StoragePtr, Discriminator);146 else147 Discriminator = Builder.CreatePtrToInt(StoragePtr, IntPtrTy);148 }149 150 return CGPointerAuthInfo(Qual.getKey(), Qual.getAuthenticationMode(),151 Qual.isIsaPointer(), Qual.authenticatesNullValues(),152 Discriminator);153}154 155/// Return the natural pointer authentication for values of the given156/// pointee type.157static CGPointerAuthInfo158getPointerAuthInfoForPointeeType(CodeGenModule &CGM, QualType PointeeType) {159 if (PointeeType.isNull())160 return CGPointerAuthInfo();161 162 // Function pointers use the function-pointer schema by default.163 if (PointeeType->isFunctionType())164 return CGM.getFunctionPointerAuthInfo(PointeeType);165 166 // Normal data pointers never use direct pointer authentication by default.167 return CGPointerAuthInfo();168}169 170CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) {171 return ::getPointerAuthInfoForPointeeType(*this, T);172}173 174/// Return the natural pointer authentication for values of the given175/// pointer type.176static CGPointerAuthInfo getPointerAuthInfoForType(CodeGenModule &CGM,177 QualType PointerType) {178 assert(PointerType->isSignableType(CGM.getContext()));179 180 // Block pointers are currently not signed.181 if (PointerType->isBlockPointerType())182 return CGPointerAuthInfo();183 184 auto PointeeType = PointerType->getPointeeType();185 186 if (PointeeType.isNull())187 return CGPointerAuthInfo();188 189 return ::getPointerAuthInfoForPointeeType(CGM, PointeeType);190}191 192CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) {193 return ::getPointerAuthInfoForType(*this, T);194}195 196static std::pair<llvm::Value *, CGPointerAuthInfo>197emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV,198 SourceLocation Loc) {199 llvm::Value *Value = CGF.EmitLoadOfScalar(LV, Loc);200 CGPointerAuthInfo AuthInfo;201 if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth())202 AuthInfo = CGF.EmitPointerAuthInfo(PtrAuth, LV.getAddress());203 else204 AuthInfo = getPointerAuthInfoForType(CGF.CGM, LV.getType());205 return {Value, AuthInfo};206}207 208/// Retrieve a pointer rvalue and its ptrauth info. When possible, avoid209/// needlessly resigning the pointer.210std::pair<llvm::Value *, CGPointerAuthInfo>211CodeGenFunction::EmitOrigPointerRValue(const Expr *E) {212 assert(E->getType()->isSignableType(getContext()));213 214 E = E->IgnoreParens();215 if (const auto *Load = dyn_cast<ImplicitCastExpr>(E)) {216 if (Load->getCastKind() == CK_LValueToRValue) {217 E = Load->getSubExpr()->IgnoreParens();218 219 // We're semantically required to not emit loads of certain DREs naively.220 if (const auto *RefExpr = dyn_cast<DeclRefExpr>(E)) {221 if (ConstantEmission Result = tryEmitAsConstant(RefExpr)) {222 // Fold away a use of an intermediate variable.223 if (!Result.isReference())224 return {Result.getValue(),225 getPointerAuthInfoForType(CGM, RefExpr->getType())};226 227 // Fold away a use of an intermediate reference.228 LValue LV = Result.getReferenceLValue(*this, RefExpr);229 return emitLoadOfOrigPointerRValue(*this, LV, RefExpr->getLocation());230 }231 }232 233 // Otherwise, load and use the pointer234 LValue LV = EmitCheckedLValue(E, CodeGenFunction::TCK_Load);235 return emitLoadOfOrigPointerRValue(*this, LV, E->getExprLoc());236 }237 }238 239 // Fallback: just use the normal rules for the type.240 llvm::Value *Value = EmitScalarExpr(E);241 return {Value, getPointerAuthInfoForType(CGM, E->getType())};242}243 244llvm::Value *245CodeGenFunction::EmitPointerAuthQualify(PointerAuthQualifier DestQualifier,246 const Expr *E,247 Address DestStorageAddress) {248 assert(DestQualifier);249 auto [Value, CurAuthInfo] = EmitOrigPointerRValue(E);250 251 CGPointerAuthInfo DestAuthInfo =252 EmitPointerAuthInfo(DestQualifier, DestStorageAddress);253 return emitPointerAuthResign(Value, E->getType(), CurAuthInfo, DestAuthInfo,254 isPointerKnownNonNull(E));255}256 257llvm::Value *CodeGenFunction::EmitPointerAuthQualify(258 PointerAuthQualifier DestQualifier, llvm::Value *Value,259 QualType PointerType, Address DestStorageAddress, bool IsKnownNonNull) {260 assert(DestQualifier);261 262 CGPointerAuthInfo CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType);263 CGPointerAuthInfo DestAuthInfo =264 EmitPointerAuthInfo(DestQualifier, DestStorageAddress);265 return emitPointerAuthResign(Value, PointerType, CurAuthInfo, DestAuthInfo,266 IsKnownNonNull);267}268 269llvm::Value *CodeGenFunction::EmitPointerAuthUnqualify(270 PointerAuthQualifier CurQualifier, llvm::Value *Value, QualType PointerType,271 Address CurStorageAddress, bool IsKnownNonNull) {272 assert(CurQualifier);273 274 CGPointerAuthInfo CurAuthInfo =275 EmitPointerAuthInfo(CurQualifier, CurStorageAddress);276 CGPointerAuthInfo DestAuthInfo = getPointerAuthInfoForType(CGM, PointerType);277 return emitPointerAuthResign(Value, PointerType, CurAuthInfo, DestAuthInfo,278 IsKnownNonNull);279}280 281static bool isZeroConstant(const llvm::Value *Value) {282 if (const auto *CI = dyn_cast<llvm::ConstantInt>(Value))283 return CI->isZero();284 return false;285}286 287static bool equalAuthPolicies(const CGPointerAuthInfo &Left,288 const CGPointerAuthInfo &Right) {289 assert((Left.isSigned() || Right.isSigned()) &&290 "shouldn't be called if neither is signed");291 if (Left.isSigned() != Right.isSigned())292 return false;293 return Left.getKey() == Right.getKey() &&294 Left.getAuthenticationMode() == Right.getAuthenticationMode() &&295 Left.isIsaPointer() == Right.isIsaPointer() &&296 Left.authenticatesNullValues() == Right.authenticatesNullValues() &&297 Left.getDiscriminator() == Right.getDiscriminator();298}299 300// Return the discriminator or return zero if the discriminator is null.301static llvm::Value *getDiscriminatorOrZero(const CGPointerAuthInfo &Info,302 CGBuilderTy &Builder) {303 llvm::Value *Discriminator = Info.getDiscriminator();304 return Discriminator ? Discriminator : Builder.getSize(0);305}306 307llvm::Value *308CodeGenFunction::emitPointerAuthResignCall(llvm::Value *Value,309 const CGPointerAuthInfo &CurAuth,310 const CGPointerAuthInfo &NewAuth) {311 assert(CurAuth && NewAuth);312 313 if (CurAuth.getAuthenticationMode() !=314 PointerAuthenticationMode::SignAndAuth ||315 NewAuth.getAuthenticationMode() !=316 PointerAuthenticationMode::SignAndAuth) {317 llvm::Value *AuthedValue = EmitPointerAuthAuth(CurAuth, Value);318 return EmitPointerAuthSign(NewAuth, AuthedValue);319 }320 // Convert the pointer to intptr_t before signing it.321 auto *OrigType = Value->getType();322 Value = Builder.CreatePtrToInt(Value, IntPtrTy);323 324 auto *CurKey = Builder.getInt32(CurAuth.getKey());325 auto *NewKey = Builder.getInt32(NewAuth.getKey());326 327 llvm::Value *CurDiscriminator = getDiscriminatorOrZero(CurAuth, Builder);328 llvm::Value *NewDiscriminator = getDiscriminatorOrZero(NewAuth, Builder);329 330 // call i64 @llvm.ptrauth.resign(i64 %pointer,331 // i32 %curKey, i64 %curDiscriminator,332 // i32 %newKey, i64 %newDiscriminator)333 auto *Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_resign);334 Value = EmitRuntimeCall(335 Intrinsic, {Value, CurKey, CurDiscriminator, NewKey, NewDiscriminator});336 337 // Convert back to the original type.338 Value = Builder.CreateIntToPtr(Value, OrigType);339 return Value;340}341 342llvm::Value *CodeGenFunction::emitPointerAuthResign(343 llvm::Value *Value, QualType Type, const CGPointerAuthInfo &CurAuthInfo,344 const CGPointerAuthInfo &NewAuthInfo, bool IsKnownNonNull) {345 // Fast path: if neither schema wants a signature, we're done.346 if (!CurAuthInfo && !NewAuthInfo)347 return Value;348 349 llvm::Value *Null = nullptr;350 // If the value is obviously null, we're done.351 if (auto *PointerValue = dyn_cast<llvm::PointerType>(Value->getType())) {352 Null = CGM.getNullPointer(PointerValue, Type);353 } else {354 assert(Value->getType()->isIntegerTy());355 Null = llvm::ConstantInt::get(IntPtrTy, 0);356 }357 if (Value == Null)358 return Value;359 360 // If both schemas sign the same way, we're done.361 if (equalAuthPolicies(CurAuthInfo, NewAuthInfo)) {362 const llvm::Value *CurD = CurAuthInfo.getDiscriminator();363 const llvm::Value *NewD = NewAuthInfo.getDiscriminator();364 if (CurD == NewD)365 return Value;366 367 if ((CurD == nullptr && isZeroConstant(NewD)) ||368 (NewD == nullptr && isZeroConstant(CurD)))369 return Value;370 }371 372 llvm::BasicBlock *InitBB = Builder.GetInsertBlock();373 llvm::BasicBlock *ResignBB = nullptr, *ContBB = nullptr;374 375 // Null pointers have to be mapped to null, and the ptrauth_resign376 // intrinsic doesn't do that.377 if (!IsKnownNonNull && !llvm::isKnownNonZero(Value, CGM.getDataLayout())) {378 ContBB = createBasicBlock("resign.cont");379 ResignBB = createBasicBlock("resign.nonnull");380 381 auto *IsNonNull = Builder.CreateICmpNE(Value, Null);382 Builder.CreateCondBr(IsNonNull, ResignBB, ContBB);383 EmitBlock(ResignBB);384 }385 386 // Perform the auth/sign/resign operation.387 if (!NewAuthInfo)388 Value = EmitPointerAuthAuth(CurAuthInfo, Value);389 else if (!CurAuthInfo)390 Value = EmitPointerAuthSign(NewAuthInfo, Value);391 else392 Value = emitPointerAuthResignCall(Value, CurAuthInfo, NewAuthInfo);393 394 // Clean up with a phi if we branched before.395 if (ContBB) {396 EmitBlock(ContBB);397 auto *Phi = Builder.CreatePHI(Value->getType(), 2);398 Phi->addIncoming(Null, InitBB);399 Phi->addIncoming(Value, ResignBB);400 Value = Phi;401 }402 403 return Value;404}405 406void CodeGenFunction::EmitPointerAuthCopy(PointerAuthQualifier Qual, QualType T,407 Address DestAddress,408 Address SrcAddress) {409 assert(Qual);410 llvm::Value *Value = Builder.CreateLoad(SrcAddress);411 412 // If we're using address-discrimination, we have to re-sign the value.413 if (Qual.isAddressDiscriminated()) {414 CGPointerAuthInfo SrcPtrAuth = EmitPointerAuthInfo(Qual, SrcAddress);415 CGPointerAuthInfo DestPtrAuth = EmitPointerAuthInfo(Qual, DestAddress);416 Value = emitPointerAuthResign(Value, T, SrcPtrAuth, DestPtrAuth,417 /*IsKnownNonNull=*/false);418 }419 420 Builder.CreateStore(Value, DestAddress);421}422 423llvm::Constant *424CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,425 llvm::Constant *StorageAddress,426 llvm::ConstantInt *OtherDiscriminator) {427 llvm::Constant *AddressDiscriminator;428 if (StorageAddress) {429 assert(StorageAddress->getType() == DefaultPtrTy);430 AddressDiscriminator = StorageAddress;431 } else {432 AddressDiscriminator = llvm::Constant::getNullValue(DefaultPtrTy);433 }434 435 llvm::ConstantInt *IntegerDiscriminator;436 if (OtherDiscriminator) {437 assert(OtherDiscriminator->getType() == Int64Ty);438 IntegerDiscriminator = OtherDiscriminator;439 } else {440 IntegerDiscriminator = llvm::ConstantInt::get(Int64Ty, 0);441 }442 443 return llvm::ConstantPtrAuth::get(444 Pointer, llvm::ConstantInt::get(Int32Ty, Key), IntegerDiscriminator,445 AddressDiscriminator,446 /*DeactivationSymbol=*/llvm::Constant::getNullValue(DefaultPtrTy));447}448 449/// Does a given PointerAuthScheme require us to sign a value450bool CodeGenModule::shouldSignPointer(const PointerAuthSchema &Schema) {451 auto AuthenticationMode = Schema.getAuthenticationMode();452 return AuthenticationMode == PointerAuthenticationMode::SignAndStrip ||453 AuthenticationMode == PointerAuthenticationMode::SignAndAuth;454}455 456/// Sign a constant pointer using the given scheme, producing a constant457/// with the same IR type.458llvm::Constant *CodeGenModule::getConstantSignedPointer(459 llvm::Constant *Pointer, const PointerAuthSchema &Schema,460 llvm::Constant *StorageAddress, GlobalDecl SchemaDecl,461 QualType SchemaType) {462 assert(shouldSignPointer(Schema));463 llvm::ConstantInt *OtherDiscriminator =464 getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType);465 466 return getConstantSignedPointer(Pointer, Schema.getKey(), StorageAddress,467 OtherDiscriminator);468}469 470llvm::Constant *471CodeGen::getConstantSignedPointer(CodeGenModule &CGM, llvm::Constant *Pointer,472 unsigned Key, llvm::Constant *StorageAddress,473 llvm::ConstantInt *OtherDiscriminator) {474 return CGM.getConstantSignedPointer(Pointer, Key, StorageAddress,475 OtherDiscriminator);476}477 478/// If applicable, sign a given constant function pointer with the ABI rules for479/// functionType.480llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,481 QualType FunctionType) {482 assert(FunctionType->isFunctionType() ||483 FunctionType->isFunctionReferenceType() ||484 FunctionType->isFunctionPointerType());485 486 if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType))487 return getConstantSignedPointer(488 Pointer, PointerAuth.getKey(), /*StorageAddress=*/nullptr,489 cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));490 491 return Pointer;492}493 494llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,495 llvm::Type *Ty) {496 const auto *FD = cast<FunctionDecl>(GD.getDecl());497 QualType FuncType = FD->getType();498 499 // Annoyingly, K&R functions have prototypes in the clang AST, but500 // expressions referring to them are unprototyped.501 if (!FD->hasPrototype())502 if (const auto *Proto = FuncType->getAs<FunctionProtoType>())503 FuncType = Context.getFunctionNoProtoType(Proto->getReturnType(),504 Proto->getExtInfo());505 506 return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType);507}508 509CGPointerAuthInfo CodeGenModule::getMemberFunctionPointerAuthInfo(QualType FT) {510 assert(FT->getAs<MemberPointerType>() && "MemberPointerType expected");511 const auto &Schema = getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;512 if (!Schema)513 return CGPointerAuthInfo();514 515 assert(!Schema.isAddressDiscriminated() &&516 "function pointers cannot use address-specific discrimination");517 518 llvm::ConstantInt *Discriminator =519 getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), FT);520 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),521 /* IsIsaPointer */ false,522 /* AuthenticatesNullValues */ false, Discriminator);523}524 525llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer,526 QualType FT) {527 if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT))528 return getConstantSignedPointer(529 Pointer, PointerAuth.getKey(), nullptr,530 cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));531 532 if (const auto *MFT = dyn_cast<MemberPointerType>(FT.getTypePtr())) {533 if (MFT->hasPointeeToToCFIUncheckedCalleeFunctionType())534 Pointer = llvm::NoCFIValue::get(cast<llvm::GlobalValue>(Pointer));535 }536 537 return Pointer;538}539 540llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD,541 llvm::Type *Ty) {542 QualType FT = FD->getType();543 FT = getContext().getMemberPointerType(FT, /*Qualifier=*/std::nullopt,544 cast<CXXMethodDecl>(FD)->getParent());545 return getMemberFunctionPointer(getRawFunctionPointer(FD, Ty), FT);546}547 548std::optional<PointerAuthQualifier>549CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {550 auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers;551 if (!DefaultAuthentication)552 return std::nullopt;553 const CXXRecordDecl *PrimaryBase =554 Context.baseForVTableAuthentication(ThisClass);555 556 unsigned Key = DefaultAuthentication.getKey();557 bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated();558 auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination();559 unsigned TypeBasedDiscriminator =560 Context.getPointerAuthVTablePointerDiscriminator(PrimaryBase);561 unsigned Discriminator;562 if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) {563 Discriminator = TypeBasedDiscriminator;564 } else if (DefaultDiscrimination ==565 PointerAuthSchema::Discrimination::Constant) {566 Discriminator = DefaultAuthentication.getConstantDiscrimination();567 } else {568 assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None);569 Discriminator = 0;570 }571 if (auto ExplicitAuthentication =572 PrimaryBase->getAttr<VTablePointerAuthenticationAttr>()) {573 auto ExplicitAddressDiscrimination =574 ExplicitAuthentication->getAddressDiscrimination();575 auto ExplicitDiscriminator =576 ExplicitAuthentication->getExtraDiscrimination();577 578 unsigned ExplicitKey = ExplicitAuthentication->getKey();579 if (ExplicitKey == VTablePointerAuthenticationAttr::NoKey)580 return std::nullopt;581 582 if (ExplicitKey != VTablePointerAuthenticationAttr::DefaultKey) {583 if (ExplicitKey == VTablePointerAuthenticationAttr::ProcessIndependent)584 Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDA;585 else {586 assert(ExplicitKey ==587 VTablePointerAuthenticationAttr::ProcessDependent);588 Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDB;589 }590 }591 592 if (ExplicitAddressDiscrimination !=593 VTablePointerAuthenticationAttr::DefaultAddressDiscrimination)594 AddressDiscriminated =595 ExplicitAddressDiscrimination ==596 VTablePointerAuthenticationAttr::AddressDiscrimination;597 598 if (ExplicitDiscriminator ==599 VTablePointerAuthenticationAttr::TypeDiscrimination)600 Discriminator = TypeBasedDiscriminator;601 else if (ExplicitDiscriminator ==602 VTablePointerAuthenticationAttr::CustomDiscrimination)603 Discriminator = ExplicitAuthentication->getCustomDiscriminationValue();604 else if (ExplicitDiscriminator ==605 VTablePointerAuthenticationAttr::NoExtraDiscrimination)606 Discriminator = 0;607 }608 return PointerAuthQualifier::Create(Key, AddressDiscriminated, Discriminator,609 PointerAuthenticationMode::SignAndAuth,610 /* IsIsaPointer */ false,611 /* AuthenticatesNullValues */ false);612}613 614std::optional<PointerAuthQualifier>615CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) {616 if (!Record->getDefinition() || !Record->isPolymorphic())617 return std::nullopt;618 619 auto Existing = VTablePtrAuthInfos.find(Record);620 std::optional<PointerAuthQualifier> Authentication;621 if (Existing != VTablePtrAuthInfos.end()) {622 Authentication = Existing->getSecond();623 } else {624 Authentication = computeVTPointerAuthentication(Record);625 VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication));626 }627 return Authentication;628}629 630std::optional<CGPointerAuthInfo>631CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF,632 const CXXRecordDecl *Record,633 llvm::Value *StorageAddress) {634 auto Authentication = getVTablePointerAuthentication(Record);635 if (!Authentication)636 return std::nullopt;637 638 llvm::Value *Discriminator = nullptr;639 if (auto ExtraDiscriminator = Authentication->getExtraDiscriminator())640 Discriminator = llvm::ConstantInt::get(IntPtrTy, ExtraDiscriminator);641 642 if (Authentication->isAddressDiscriminated()) {643 assert(StorageAddress &&644 "address not provided for address-discriminated schema");645 if (Discriminator)646 Discriminator =647 CGF->EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);648 else649 Discriminator = CGF->Builder.CreatePtrToInt(StorageAddress, IntPtrTy);650 }651 652 return CGPointerAuthInfo(Authentication->getKey(),653 PointerAuthenticationMode::SignAndAuth,654 /* IsIsaPointer */ false,655 /* AuthenticatesNullValues */ false, Discriminator);656}657 658llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr,659 QualType SourceType,660 QualType DestType) {661 CGPointerAuthInfo CurAuthInfo, NewAuthInfo;662 if (SourceType->isSignableType(getContext()))663 CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);664 665 if (DestType->isSignableType(getContext()))666 NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);667 668 if (!CurAuthInfo && !NewAuthInfo)669 return ResultPtr;670 671 // If only one side of the cast is a function pointer, then we still need to672 // resign to handle casts to/from opaque pointers.673 if (!CurAuthInfo && DestType->isFunctionPointerType())674 CurAuthInfo = CGM.getFunctionPointerAuthInfo(SourceType);675 676 if (!NewAuthInfo && SourceType->isFunctionPointerType())677 NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType);678 679 return emitPointerAuthResign(ResultPtr, DestType, CurAuthInfo, NewAuthInfo,680 /*IsKnownNonNull=*/false);681}682 683Address CodeGenFunction::authPointerToPointerCast(Address Ptr,684 QualType SourceType,685 QualType DestType) {686 CGPointerAuthInfo CurAuthInfo, NewAuthInfo;687 if (SourceType->isSignableType(getContext()))688 CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);689 690 if (DestType->isSignableType(getContext()))691 NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);692 693 if (!CurAuthInfo && !NewAuthInfo)694 return Ptr;695 696 if (!CurAuthInfo && DestType->isFunctionPointerType()) {697 // When casting a non-signed pointer to a function pointer, just set the698 // auth info on Ptr to the assumed schema. The pointer will be resigned to699 // the effective type when used.700 Ptr.setPointerAuthInfo(CGM.getFunctionPointerAuthInfo(SourceType));701 return Ptr;702 }703 704 if (!NewAuthInfo && SourceType->isFunctionPointerType()) {705 NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType);706 Ptr = Ptr.getResignedAddress(NewAuthInfo, *this);707 Ptr.setPointerAuthInfo(CGPointerAuthInfo());708 return Ptr;709 }710 711 return Ptr;712}713 714Address CodeGenFunction::getAsNaturalAddressOf(Address Addr,715 QualType PointeeTy) {716 CGPointerAuthInfo Info =717 PointeeTy.isNull() ? CGPointerAuthInfo()718 : CGM.getPointerAuthInfoForPointeeType(PointeeTy);719 return Addr.getResignedAddress(Info, *this);720}721 722Address Address::getResignedAddress(const CGPointerAuthInfo &NewInfo,723 CodeGenFunction &CGF) const {724 assert(isValid() && "pointer isn't valid");725 CGPointerAuthInfo CurInfo = getPointerAuthInfo();726 llvm::Value *Val;727 728 // Nothing to do if neither the current or the new ptrauth info needs signing.729 if (!CurInfo.isSigned() && !NewInfo.isSigned())730 return Address(getBasePointer(), getElementType(), getAlignment(),731 isKnownNonNull());732 733 assert(ElementType && "Effective type has to be set");734 assert(!Offset && "unexpected non-null offset");735 736 // If the current and the new ptrauth infos are the same and the offset is737 // null, just cast the base pointer to the effective type.738 if (CurInfo == NewInfo && !hasOffset())739 Val = getBasePointer();740 else741 Val = CGF.emitPointerAuthResign(getBasePointer(), QualType(), CurInfo,742 NewInfo, isKnownNonNull());743 744 return Address(Val, getElementType(), getAlignment(), NewInfo,745 /*Offset=*/nullptr, isKnownNonNull());746}747 748llvm::Value *Address::emitRawPointerSlow(CodeGenFunction &CGF) const {749 return CGF.getAsNaturalPointerTo(*this, QualType());750}751 752llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const {753 assert(isSimple());754 return emitResignedPointer(getType(), CGF);755}756 757llvm::Value *LValue::emitResignedPointer(QualType PointeeTy,758 CodeGenFunction &CGF) const {759 assert(isSimple());760 return CGF.getAsNaturalAddressOf(Addr, PointeeTy).getBasePointer();761}762 763llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const {764 assert(isSimple());765 return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr;766}767