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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file contains common routines relating to the emission of 10 // 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 21 using namespace clang; 22 using namespace CodeGen; 23 24 /// Given a pointer-authentication schema, return a concrete "other" 25 /// discriminator for it. 26 llvm::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 49 uint16_t CodeGen::getPointerAuthTypeDiscriminator(CodeGenModule &CGM, 50 QualType FunctionType) { 51 return CGM.getContext().getPointerAuthTypeDiscriminator(FunctionType); 52 } 53 54 uint16_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. 60 uint16_t 61 CodeGenModule::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 given 73 /// function type. 74 CGPointerAuthInfo 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 93 llvm::Value * 94 CodeGenFunction::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 the 102 /// given authentication schema. 103 CGPointerAuthInfo 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 else 120 Discriminator = Builder.CreatePtrToInt(StorageAddress, IntPtrTy); 121 } 122 123 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(), 124 Schema.isIsaPointer(), 125 Schema.authenticatesNullValues(), Discriminator); 126 } 127 128 CGPointerAuthInfo 129 CodeGenFunction::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 else 147 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 given 156 /// pointee type. 157 static CGPointerAuthInfo 158 getPointerAuthInfoForPointeeType(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 170 CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) { 171 return ::getPointerAuthInfoForPointeeType(*this, T); 172 } 173 174 /// Return the natural pointer authentication for values of the given 175 /// pointer type. 176 static 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 192 CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) { 193 return ::getPointerAuthInfoForType(*this, T); 194 } 195 196 static std::pair<llvm::Value *, CGPointerAuthInfo> 197 emitLoadOfOrigPointerRValue(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 else 204 AuthInfo = getPointerAuthInfoForType(CGF.CGM, LV.getType()); 205 return {Value, AuthInfo}; 206 } 207 208 /// Retrieve a pointer rvalue and its ptrauth info. When possible, avoid 209 /// needlessly resigning the pointer. 210 std::pair<llvm::Value *, CGPointerAuthInfo> 211 CodeGenFunction::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 pointer 234 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 244 llvm::Value * 245 CodeGenFunction::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 257 llvm::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 269 llvm::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 281 static 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 287 static 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. 301 static llvm::Value *getDiscriminatorOrZero(const CGPointerAuthInfo &Info, 302 CGBuilderTy &Builder) { 303 llvm::Value *Discriminator = Info.getDiscriminator(); 304 return Discriminator ? Discriminator : Builder.getSize(0); 305 } 306 307 llvm::Value * 308 CodeGenFunction::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 342 llvm::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_resign 376 // 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 else 392 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 406 void 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 423 llvm::Constant * 424 CodeGenModule::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() == UnqualPtrTy); 430 AddressDiscriminator = StorageAddress; 431 } else { 432 AddressDiscriminator = llvm::Constant::getNullValue(UnqualPtrTy); 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(Pointer, 444 llvm::ConstantInt::get(Int32Ty, Key), 445 IntegerDiscriminator, AddressDiscriminator); 446 } 447 448 /// Does a given PointerAuthScheme require us to sign a value 449 bool CodeGenModule::shouldSignPointer(const PointerAuthSchema &Schema) { 450 auto AuthenticationMode = Schema.getAuthenticationMode(); 451 return AuthenticationMode == PointerAuthenticationMode::SignAndStrip || 452 AuthenticationMode == PointerAuthenticationMode::SignAndAuth; 453 } 454 455 /// Sign a constant pointer using the given scheme, producing a constant 456 /// with the same IR type. 457 llvm::Constant *CodeGenModule::getConstantSignedPointer( 458 llvm::Constant *Pointer, const PointerAuthSchema &Schema, 459 llvm::Constant *StorageAddress, GlobalDecl SchemaDecl, 460 QualType SchemaType) { 461 assert(shouldSignPointer(Schema)); 462 llvm::ConstantInt *OtherDiscriminator = 463 getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType); 464 465 return getConstantSignedPointer(Pointer, Schema.getKey(), StorageAddress, 466 OtherDiscriminator); 467 } 468 469 /// If applicable, sign a given constant function pointer with the ABI rules for 470 /// functionType. 471 llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer, 472 QualType FunctionType) { 473 assert(FunctionType->isFunctionType() || 474 FunctionType->isFunctionReferenceType() || 475 FunctionType->isFunctionPointerType()); 476 477 if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType)) 478 return getConstantSignedPointer( 479 Pointer, PointerAuth.getKey(), /*StorageAddress=*/nullptr, 480 cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator())); 481 482 return Pointer; 483 } 484 485 llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD, 486 llvm::Type *Ty) { 487 const auto *FD = cast<FunctionDecl>(GD.getDecl()); 488 QualType FuncType = FD->getType(); 489 490 // Annoyingly, K&R functions have prototypes in the clang AST, but 491 // expressions referring to them are unprototyped. 492 if (!FD->hasPrototype()) 493 if (const auto *Proto = FuncType->getAs<FunctionProtoType>()) 494 FuncType = Context.getFunctionNoProtoType(Proto->getReturnType(), 495 Proto->getExtInfo()); 496 497 return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType); 498 } 499 500 CGPointerAuthInfo CodeGenModule::getMemberFunctionPointerAuthInfo(QualType FT) { 501 assert(FT->getAs<MemberPointerType>() && "MemberPointerType expected"); 502 const auto &Schema = getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers; 503 if (!Schema) 504 return CGPointerAuthInfo(); 505 506 assert(!Schema.isAddressDiscriminated() && 507 "function pointers cannot use address-specific discrimination"); 508 509 llvm::ConstantInt *Discriminator = 510 getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), FT); 511 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(), 512 /* IsIsaPointer */ false, 513 /* AuthenticatesNullValues */ false, Discriminator); 514 } 515 516 llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer, 517 QualType FT) { 518 if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT)) 519 return getConstantSignedPointer( 520 Pointer, PointerAuth.getKey(), nullptr, 521 cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator())); 522 523 if (const auto *MFT = dyn_cast<MemberPointerType>(FT.getTypePtr())) { 524 if (MFT->hasPointeeToToCFIUncheckedCalleeFunctionType()) 525 Pointer = llvm::NoCFIValue::get(cast<llvm::GlobalValue>(Pointer)); 526 } 527 528 return Pointer; 529 } 530 531 llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD, 532 llvm::Type *Ty) { 533 QualType FT = FD->getType(); 534 FT = getContext().getMemberPointerType(FT, /*Qualifier=*/nullptr, 535 cast<CXXMethodDecl>(FD)->getParent()); 536 return getMemberFunctionPointer(getRawFunctionPointer(FD, Ty), FT); 537 } 538 539 std::optional<PointerAuthQualifier> 540 CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) { 541 auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers; 542 if (!DefaultAuthentication) 543 return std::nullopt; 544 const CXXRecordDecl *PrimaryBase = 545 Context.baseForVTableAuthentication(ThisClass); 546 547 unsigned Key = DefaultAuthentication.getKey(); 548 bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated(); 549 auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination(); 550 unsigned TypeBasedDiscriminator = 551 Context.getPointerAuthVTablePointerDiscriminator(PrimaryBase); 552 unsigned Discriminator; 553 if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) { 554 Discriminator = TypeBasedDiscriminator; 555 } else if (DefaultDiscrimination == 556 PointerAuthSchema::Discrimination::Constant) { 557 Discriminator = DefaultAuthentication.getConstantDiscrimination(); 558 } else { 559 assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None); 560 Discriminator = 0; 561 } 562 if (auto ExplicitAuthentication = 563 PrimaryBase->getAttr<VTablePointerAuthenticationAttr>()) { 564 auto ExplicitAddressDiscrimination = 565 ExplicitAuthentication->getAddressDiscrimination(); 566 auto ExplicitDiscriminator = 567 ExplicitAuthentication->getExtraDiscrimination(); 568 569 unsigned ExplicitKey = ExplicitAuthentication->getKey(); 570 if (ExplicitKey == VTablePointerAuthenticationAttr::NoKey) 571 return std::nullopt; 572 573 if (ExplicitKey != VTablePointerAuthenticationAttr::DefaultKey) { 574 if (ExplicitKey == VTablePointerAuthenticationAttr::ProcessIndependent) 575 Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDA; 576 else { 577 assert(ExplicitKey == 578 VTablePointerAuthenticationAttr::ProcessDependent); 579 Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDB; 580 } 581 } 582 583 if (ExplicitAddressDiscrimination != 584 VTablePointerAuthenticationAttr::DefaultAddressDiscrimination) 585 AddressDiscriminated = 586 ExplicitAddressDiscrimination == 587 VTablePointerAuthenticationAttr::AddressDiscrimination; 588 589 if (ExplicitDiscriminator == 590 VTablePointerAuthenticationAttr::TypeDiscrimination) 591 Discriminator = TypeBasedDiscriminator; 592 else if (ExplicitDiscriminator == 593 VTablePointerAuthenticationAttr::CustomDiscrimination) 594 Discriminator = ExplicitAuthentication->getCustomDiscriminationValue(); 595 else if (ExplicitDiscriminator == 596 VTablePointerAuthenticationAttr::NoExtraDiscrimination) 597 Discriminator = 0; 598 } 599 return PointerAuthQualifier::Create(Key, AddressDiscriminated, Discriminator, 600 PointerAuthenticationMode::SignAndAuth, 601 /* IsIsaPointer */ false, 602 /* AuthenticatesNullValues */ false); 603 } 604 605 std::optional<PointerAuthQualifier> 606 CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) { 607 if (!Record->getDefinition() || !Record->isPolymorphic()) 608 return std::nullopt; 609 610 auto Existing = VTablePtrAuthInfos.find(Record); 611 std::optional<PointerAuthQualifier> Authentication; 612 if (Existing != VTablePtrAuthInfos.end()) { 613 Authentication = Existing->getSecond(); 614 } else { 615 Authentication = computeVTPointerAuthentication(Record); 616 VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication)); 617 } 618 return Authentication; 619 } 620 621 std::optional<CGPointerAuthInfo> 622 CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF, 623 const CXXRecordDecl *Record, 624 llvm::Value *StorageAddress) { 625 auto Authentication = getVTablePointerAuthentication(Record); 626 if (!Authentication) 627 return std::nullopt; 628 629 llvm::Value *Discriminator = nullptr; 630 if (auto ExtraDiscriminator = Authentication->getExtraDiscriminator()) 631 Discriminator = llvm::ConstantInt::get(IntPtrTy, ExtraDiscriminator); 632 633 if (Authentication->isAddressDiscriminated()) { 634 assert(StorageAddress && 635 "address not provided for address-discriminated schema"); 636 if (Discriminator) 637 Discriminator = 638 CGF->EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator); 639 else 640 Discriminator = CGF->Builder.CreatePtrToInt(StorageAddress, IntPtrTy); 641 } 642 643 return CGPointerAuthInfo(Authentication->getKey(), 644 PointerAuthenticationMode::SignAndAuth, 645 /* IsIsaPointer */ false, 646 /* AuthenticatesNullValues */ false, Discriminator); 647 } 648 649 llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr, 650 QualType SourceType, 651 QualType DestType) { 652 CGPointerAuthInfo CurAuthInfo, NewAuthInfo; 653 if (SourceType->isSignableType(getContext())) 654 CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType); 655 656 if (DestType->isSignableType(getContext())) 657 NewAuthInfo = getPointerAuthInfoForType(CGM, DestType); 658 659 if (!CurAuthInfo && !NewAuthInfo) 660 return ResultPtr; 661 662 // If only one side of the cast is a function pointer, then we still need to 663 // resign to handle casts to/from opaque pointers. 664 if (!CurAuthInfo && DestType->isFunctionPointerType()) 665 CurAuthInfo = CGM.getFunctionPointerAuthInfo(SourceType); 666 667 if (!NewAuthInfo && SourceType->isFunctionPointerType()) 668 NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType); 669 670 return emitPointerAuthResign(ResultPtr, DestType, CurAuthInfo, NewAuthInfo, 671 /*IsKnownNonNull=*/false); 672 } 673 674 Address CodeGenFunction::authPointerToPointerCast(Address Ptr, 675 QualType SourceType, 676 QualType DestType) { 677 CGPointerAuthInfo CurAuthInfo, NewAuthInfo; 678 if (SourceType->isSignableType(getContext())) 679 CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType); 680 681 if (DestType->isSignableType(getContext())) 682 NewAuthInfo = getPointerAuthInfoForType(CGM, DestType); 683 684 if (!CurAuthInfo && !NewAuthInfo) 685 return Ptr; 686 687 if (!CurAuthInfo && DestType->isFunctionPointerType()) { 688 // When casting a non-signed pointer to a function pointer, just set the 689 // auth info on Ptr to the assumed schema. The pointer will be resigned to 690 // the effective type when used. 691 Ptr.setPointerAuthInfo(CGM.getFunctionPointerAuthInfo(SourceType)); 692 return Ptr; 693 } 694 695 if (!NewAuthInfo && SourceType->isFunctionPointerType()) { 696 NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType); 697 Ptr = Ptr.getResignedAddress(NewAuthInfo, *this); 698 Ptr.setPointerAuthInfo(CGPointerAuthInfo()); 699 return Ptr; 700 } 701 702 return Ptr; 703 } 704 705 Address CodeGenFunction::getAsNaturalAddressOf(Address Addr, 706 QualType PointeeTy) { 707 CGPointerAuthInfo Info = 708 PointeeTy.isNull() ? CGPointerAuthInfo() 709 : CGM.getPointerAuthInfoForPointeeType(PointeeTy); 710 return Addr.getResignedAddress(Info, *this); 711 } 712 713 Address Address::getResignedAddress(const CGPointerAuthInfo &NewInfo, 714 CodeGenFunction &CGF) const { 715 assert(isValid() && "pointer isn't valid"); 716 CGPointerAuthInfo CurInfo = getPointerAuthInfo(); 717 llvm::Value *Val; 718 719 // Nothing to do if neither the current or the new ptrauth info needs signing. 720 if (!CurInfo.isSigned() && !NewInfo.isSigned()) 721 return Address(getBasePointer(), getElementType(), getAlignment(), 722 isKnownNonNull()); 723 724 assert(ElementType && "Effective type has to be set"); 725 assert(!Offset && "unexpected non-null offset"); 726 727 // If the current and the new ptrauth infos are the same and the offset is 728 // null, just cast the base pointer to the effective type. 729 if (CurInfo == NewInfo && !hasOffset()) 730 Val = getBasePointer(); 731 else 732 Val = CGF.emitPointerAuthResign(getBasePointer(), QualType(), CurInfo, 733 NewInfo, isKnownNonNull()); 734 735 return Address(Val, getElementType(), getAlignment(), NewInfo, 736 /*Offset=*/nullptr, isKnownNonNull()); 737 } 738 739 llvm::Value *Address::emitRawPointerSlow(CodeGenFunction &CGF) const { 740 return CGF.getAsNaturalPointerTo(*this, QualType()); 741 } 742 743 llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const { 744 assert(isSimple()); 745 return emitResignedPointer(getType(), CGF); 746 } 747 748 llvm::Value *LValue::emitResignedPointer(QualType PointeeTy, 749 CodeGenFunction &CGF) const { 750 assert(isSimple()); 751 return CGF.getAsNaturalAddressOf(Addr, PointeeTy).getBasePointer(); 752 } 753 754 llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const { 755 assert(isSimple()); 756 return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr; 757 } 758