xref: /freebsd/contrib/llvm-project/clang/lib/CodeGen/CGPointerAuth.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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.
getPointerAuthOtherDiscriminator(const PointerAuthSchema & Schema,GlobalDecl Decl,QualType Type)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 
getPointerAuthTypeDiscriminator(CodeGenModule & CGM,QualType FunctionType)49 uint16_t CodeGen::getPointerAuthTypeDiscriminator(CodeGenModule &CGM,
50                                                   QualType FunctionType) {
51   return CGM.getContext().getPointerAuthTypeDiscriminator(FunctionType);
52 }
53 
getPointerAuthDeclDiscriminator(CodeGenModule & CGM,GlobalDecl Declaration)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
getPointerAuthDeclDiscriminator(GlobalDecl Declaration)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.
getFunctionPointerAuthInfo(QualType T)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 *
EmitPointerAuthBlendDiscriminator(llvm::Value * StorageAddress,llvm::Value * Discriminator)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.
EmitPointerAuthInfo(const PointerAuthSchema & Schema,llvm::Value * StorageAddress,GlobalDecl SchemaDecl,QualType SchemaType)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 /// Return the natural pointer authentication for values of the given
129 /// pointee type.
130 static CGPointerAuthInfo
getPointerAuthInfoForPointeeType(CodeGenModule & CGM,QualType PointeeType)131 getPointerAuthInfoForPointeeType(CodeGenModule &CGM, QualType PointeeType) {
132   if (PointeeType.isNull())
133     return CGPointerAuthInfo();
134 
135   // Function pointers use the function-pointer schema by default.
136   if (PointeeType->isFunctionType())
137     return CGM.getFunctionPointerAuthInfo(PointeeType);
138 
139   // Normal data pointers never use direct pointer authentication by default.
140   return CGPointerAuthInfo();
141 }
142 
getPointerAuthInfoForPointeeType(QualType T)143 CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) {
144   return ::getPointerAuthInfoForPointeeType(*this, T);
145 }
146 
147 /// Return the natural pointer authentication for values of the given
148 /// pointer type.
getPointerAuthInfoForType(CodeGenModule & CGM,QualType PointerType)149 static CGPointerAuthInfo getPointerAuthInfoForType(CodeGenModule &CGM,
150                                                    QualType PointerType) {
151   assert(PointerType->isSignableType());
152 
153   // Block pointers are currently not signed.
154   if (PointerType->isBlockPointerType())
155     return CGPointerAuthInfo();
156 
157   auto PointeeType = PointerType->getPointeeType();
158 
159   if (PointeeType.isNull())
160     return CGPointerAuthInfo();
161 
162   return ::getPointerAuthInfoForPointeeType(CGM, PointeeType);
163 }
164 
getPointerAuthInfoForType(QualType T)165 CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) {
166   return ::getPointerAuthInfoForType(*this, T);
167 }
168 
isZeroConstant(const llvm::Value * Value)169 static bool isZeroConstant(const llvm::Value *Value) {
170   if (const auto *CI = dyn_cast<llvm::ConstantInt>(Value))
171     return CI->isZero();
172   return false;
173 }
174 
equalAuthPolicies(const CGPointerAuthInfo & Left,const CGPointerAuthInfo & Right)175 static bool equalAuthPolicies(const CGPointerAuthInfo &Left,
176                               const CGPointerAuthInfo &Right) {
177   assert((Left.isSigned() || Right.isSigned()) &&
178          "shouldn't be called if neither is signed");
179   if (Left.isSigned() != Right.isSigned())
180     return false;
181   return Left.getKey() == Right.getKey() &&
182          Left.getAuthenticationMode() == Right.getAuthenticationMode();
183 }
184 
185 // Return the discriminator or return zero if the discriminator is null.
getDiscriminatorOrZero(const CGPointerAuthInfo & Info,CGBuilderTy & Builder)186 static llvm::Value *getDiscriminatorOrZero(const CGPointerAuthInfo &Info,
187                                            CGBuilderTy &Builder) {
188   llvm::Value *Discriminator = Info.getDiscriminator();
189   return Discriminator ? Discriminator : Builder.getSize(0);
190 }
191 
192 llvm::Value *
emitPointerAuthResignCall(llvm::Value * Value,const CGPointerAuthInfo & CurAuth,const CGPointerAuthInfo & NewAuth)193 CodeGenFunction::emitPointerAuthResignCall(llvm::Value *Value,
194                                            const CGPointerAuthInfo &CurAuth,
195                                            const CGPointerAuthInfo &NewAuth) {
196   assert(CurAuth && NewAuth);
197 
198   if (CurAuth.getAuthenticationMode() !=
199           PointerAuthenticationMode::SignAndAuth ||
200       NewAuth.getAuthenticationMode() !=
201           PointerAuthenticationMode::SignAndAuth) {
202     llvm::Value *AuthedValue = EmitPointerAuthAuth(CurAuth, Value);
203     return EmitPointerAuthSign(NewAuth, AuthedValue);
204   }
205   // Convert the pointer to intptr_t before signing it.
206   auto *OrigType = Value->getType();
207   Value = Builder.CreatePtrToInt(Value, IntPtrTy);
208 
209   auto *CurKey = Builder.getInt32(CurAuth.getKey());
210   auto *NewKey = Builder.getInt32(NewAuth.getKey());
211 
212   llvm::Value *CurDiscriminator = getDiscriminatorOrZero(CurAuth, Builder);
213   llvm::Value *NewDiscriminator = getDiscriminatorOrZero(NewAuth, Builder);
214 
215   // call i64 @llvm.ptrauth.resign(i64 %pointer,
216   //                               i32 %curKey, i64 %curDiscriminator,
217   //                               i32 %newKey, i64 %newDiscriminator)
218   auto *Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_resign);
219   Value = EmitRuntimeCall(
220       Intrinsic, {Value, CurKey, CurDiscriminator, NewKey, NewDiscriminator});
221 
222   // Convert back to the original type.
223   Value = Builder.CreateIntToPtr(Value, OrigType);
224   return Value;
225 }
226 
emitPointerAuthResign(llvm::Value * Value,QualType Type,const CGPointerAuthInfo & CurAuthInfo,const CGPointerAuthInfo & NewAuthInfo,bool IsKnownNonNull)227 llvm::Value *CodeGenFunction::emitPointerAuthResign(
228     llvm::Value *Value, QualType Type, const CGPointerAuthInfo &CurAuthInfo,
229     const CGPointerAuthInfo &NewAuthInfo, bool IsKnownNonNull) {
230   // Fast path: if neither schema wants a signature, we're done.
231   if (!CurAuthInfo && !NewAuthInfo)
232     return Value;
233 
234   llvm::Value *Null = nullptr;
235   // If the value is obviously null, we're done.
236   if (auto *PointerValue = dyn_cast<llvm::PointerType>(Value->getType())) {
237     Null = CGM.getNullPointer(PointerValue, Type);
238   } else {
239     assert(Value->getType()->isIntegerTy());
240     Null = llvm::ConstantInt::get(IntPtrTy, 0);
241   }
242   if (Value == Null)
243     return Value;
244 
245   // If both schemas sign the same way, we're done.
246   if (equalAuthPolicies(CurAuthInfo, NewAuthInfo)) {
247     const llvm::Value *CurD = CurAuthInfo.getDiscriminator();
248     const llvm::Value *NewD = NewAuthInfo.getDiscriminator();
249     if (CurD == NewD)
250       return Value;
251 
252     if ((CurD == nullptr && isZeroConstant(NewD)) ||
253         (NewD == nullptr && isZeroConstant(CurD)))
254       return Value;
255   }
256 
257   llvm::BasicBlock *InitBB = Builder.GetInsertBlock();
258   llvm::BasicBlock *ResignBB = nullptr, *ContBB = nullptr;
259 
260   // Null pointers have to be mapped to null, and the ptrauth_resign
261   // intrinsic doesn't do that.
262   if (!IsKnownNonNull && !llvm::isKnownNonZero(Value, CGM.getDataLayout())) {
263     ContBB = createBasicBlock("resign.cont");
264     ResignBB = createBasicBlock("resign.nonnull");
265 
266     auto *IsNonNull = Builder.CreateICmpNE(Value, Null);
267     Builder.CreateCondBr(IsNonNull, ResignBB, ContBB);
268     EmitBlock(ResignBB);
269   }
270 
271   // Perform the auth/sign/resign operation.
272   if (!NewAuthInfo)
273     Value = EmitPointerAuthAuth(CurAuthInfo, Value);
274   else if (!CurAuthInfo)
275     Value = EmitPointerAuthSign(NewAuthInfo, Value);
276   else
277     Value = emitPointerAuthResignCall(Value, CurAuthInfo, NewAuthInfo);
278 
279   // Clean up with a phi if we branched before.
280   if (ContBB) {
281     EmitBlock(ContBB);
282     auto *Phi = Builder.CreatePHI(Value->getType(), 2);
283     Phi->addIncoming(Null, InitBB);
284     Phi->addIncoming(Value, ResignBB);
285     Value = Phi;
286   }
287 
288   return Value;
289 }
290 
291 llvm::Constant *
getConstantSignedPointer(llvm::Constant * Pointer,unsigned Key,llvm::Constant * StorageAddress,llvm::ConstantInt * OtherDiscriminator)292 CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
293                                         llvm::Constant *StorageAddress,
294                                         llvm::ConstantInt *OtherDiscriminator) {
295   llvm::Constant *AddressDiscriminator;
296   if (StorageAddress) {
297     assert(StorageAddress->getType() == UnqualPtrTy);
298     AddressDiscriminator = StorageAddress;
299   } else {
300     AddressDiscriminator = llvm::Constant::getNullValue(UnqualPtrTy);
301   }
302 
303   llvm::ConstantInt *IntegerDiscriminator;
304   if (OtherDiscriminator) {
305     assert(OtherDiscriminator->getType() == Int64Ty);
306     IntegerDiscriminator = OtherDiscriminator;
307   } else {
308     IntegerDiscriminator = llvm::ConstantInt::get(Int64Ty, 0);
309   }
310 
311   return llvm::ConstantPtrAuth::get(Pointer,
312                                     llvm::ConstantInt::get(Int32Ty, Key),
313                                     IntegerDiscriminator, AddressDiscriminator);
314 }
315 
316 /// Does a given PointerAuthScheme require us to sign a value
shouldSignPointer(const PointerAuthSchema & Schema)317 bool CodeGenModule::shouldSignPointer(const PointerAuthSchema &Schema) {
318   auto AuthenticationMode = Schema.getAuthenticationMode();
319   return AuthenticationMode == PointerAuthenticationMode::SignAndStrip ||
320          AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
321 }
322 
323 /// Sign a constant pointer using the given scheme, producing a constant
324 /// with the same IR type.
getConstantSignedPointer(llvm::Constant * Pointer,const PointerAuthSchema & Schema,llvm::Constant * StorageAddress,GlobalDecl SchemaDecl,QualType SchemaType)325 llvm::Constant *CodeGenModule::getConstantSignedPointer(
326     llvm::Constant *Pointer, const PointerAuthSchema &Schema,
327     llvm::Constant *StorageAddress, GlobalDecl SchemaDecl,
328     QualType SchemaType) {
329   assert(shouldSignPointer(Schema));
330   llvm::ConstantInt *OtherDiscriminator =
331       getPointerAuthOtherDiscriminator(Schema, SchemaDecl, SchemaType);
332 
333   return getConstantSignedPointer(Pointer, Schema.getKey(), StorageAddress,
334                                   OtherDiscriminator);
335 }
336 
337 /// If applicable, sign a given constant function pointer with the ABI rules for
338 /// functionType.
getFunctionPointer(llvm::Constant * Pointer,QualType FunctionType)339 llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,
340                                                   QualType FunctionType) {
341   assert(FunctionType->isFunctionType() ||
342          FunctionType->isFunctionReferenceType() ||
343          FunctionType->isFunctionPointerType());
344 
345   if (auto PointerAuth = getFunctionPointerAuthInfo(FunctionType))
346     return getConstantSignedPointer(
347         Pointer, PointerAuth.getKey(), /*StorageAddress=*/nullptr,
348         cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));
349 
350   return Pointer;
351 }
352 
getFunctionPointer(GlobalDecl GD,llvm::Type * Ty)353 llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
354                                                   llvm::Type *Ty) {
355   const auto *FD = cast<FunctionDecl>(GD.getDecl());
356   QualType FuncType = FD->getType();
357 
358   // Annoyingly, K&R functions have prototypes in the clang AST, but
359   // expressions referring to them are unprototyped.
360   if (!FD->hasPrototype())
361     if (const auto *Proto = FuncType->getAs<FunctionProtoType>())
362       FuncType = Context.getFunctionNoProtoType(Proto->getReturnType(),
363                                                 Proto->getExtInfo());
364 
365   return getFunctionPointer(getRawFunctionPointer(GD, Ty), FuncType);
366 }
367 
getMemberFunctionPointerAuthInfo(QualType FT)368 CGPointerAuthInfo CodeGenModule::getMemberFunctionPointerAuthInfo(QualType FT) {
369   assert(FT->getAs<MemberPointerType>() && "MemberPointerType expected");
370   const auto &Schema = getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;
371   if (!Schema)
372     return CGPointerAuthInfo();
373 
374   assert(!Schema.isAddressDiscriminated() &&
375          "function pointers cannot use address-specific discrimination");
376 
377   llvm::ConstantInt *Discriminator =
378       getPointerAuthOtherDiscriminator(Schema, GlobalDecl(), FT);
379   return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
380                            /* IsIsaPointer */ false,
381                            /* AuthenticatesNullValues */ false, Discriminator);
382 }
383 
getMemberFunctionPointer(llvm::Constant * Pointer,QualType FT)384 llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer,
385                                                         QualType FT) {
386   if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT))
387     return getConstantSignedPointer(
388         Pointer, PointerAuth.getKey(), nullptr,
389         cast_or_null<llvm::ConstantInt>(PointerAuth.getDiscriminator()));
390 
391   return Pointer;
392 }
393 
getMemberFunctionPointer(const FunctionDecl * FD,llvm::Type * Ty)394 llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD,
395                                                         llvm::Type *Ty) {
396   QualType FT = FD->getType();
397   FT = getContext().getMemberPointerType(
398       FT, cast<CXXMethodDecl>(FD)->getParent()->getTypeForDecl());
399   return getMemberFunctionPointer(getRawFunctionPointer(FD, Ty), FT);
400 }
401 
402 std::optional<PointerAuthQualifier>
computeVTPointerAuthentication(const CXXRecordDecl * ThisClass)403 CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {
404   auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers;
405   if (!DefaultAuthentication)
406     return std::nullopt;
407   const CXXRecordDecl *PrimaryBase =
408       Context.baseForVTableAuthentication(ThisClass);
409 
410   unsigned Key = DefaultAuthentication.getKey();
411   bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated();
412   auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination();
413   unsigned TypeBasedDiscriminator =
414       Context.getPointerAuthVTablePointerDiscriminator(PrimaryBase);
415   unsigned Discriminator;
416   if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) {
417     Discriminator = TypeBasedDiscriminator;
418   } else if (DefaultDiscrimination ==
419              PointerAuthSchema::Discrimination::Constant) {
420     Discriminator = DefaultAuthentication.getConstantDiscrimination();
421   } else {
422     assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None);
423     Discriminator = 0;
424   }
425   if (auto ExplicitAuthentication =
426           PrimaryBase->getAttr<VTablePointerAuthenticationAttr>()) {
427     auto ExplicitAddressDiscrimination =
428         ExplicitAuthentication->getAddressDiscrimination();
429     auto ExplicitDiscriminator =
430         ExplicitAuthentication->getExtraDiscrimination();
431 
432     unsigned ExplicitKey = ExplicitAuthentication->getKey();
433     if (ExplicitKey == VTablePointerAuthenticationAttr::NoKey)
434       return std::nullopt;
435 
436     if (ExplicitKey != VTablePointerAuthenticationAttr::DefaultKey) {
437       if (ExplicitKey == VTablePointerAuthenticationAttr::ProcessIndependent)
438         Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDA;
439       else {
440         assert(ExplicitKey ==
441                VTablePointerAuthenticationAttr::ProcessDependent);
442         Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDB;
443       }
444     }
445 
446     if (ExplicitAddressDiscrimination !=
447         VTablePointerAuthenticationAttr::DefaultAddressDiscrimination)
448       AddressDiscriminated =
449           ExplicitAddressDiscrimination ==
450           VTablePointerAuthenticationAttr::AddressDiscrimination;
451 
452     if (ExplicitDiscriminator ==
453         VTablePointerAuthenticationAttr::TypeDiscrimination)
454       Discriminator = TypeBasedDiscriminator;
455     else if (ExplicitDiscriminator ==
456              VTablePointerAuthenticationAttr::CustomDiscrimination)
457       Discriminator = ExplicitAuthentication->getCustomDiscriminationValue();
458     else if (ExplicitDiscriminator ==
459              VTablePointerAuthenticationAttr::NoExtraDiscrimination)
460       Discriminator = 0;
461   }
462   return PointerAuthQualifier::Create(Key, AddressDiscriminated, Discriminator,
463                                       PointerAuthenticationMode::SignAndAuth,
464                                       /* IsIsaPointer */ false,
465                                       /* AuthenticatesNullValues */ false);
466 }
467 
468 std::optional<PointerAuthQualifier>
getVTablePointerAuthentication(const CXXRecordDecl * Record)469 CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) {
470   if (!Record->getDefinition() || !Record->isPolymorphic())
471     return std::nullopt;
472 
473   auto Existing = VTablePtrAuthInfos.find(Record);
474   std::optional<PointerAuthQualifier> Authentication;
475   if (Existing != VTablePtrAuthInfos.end()) {
476     Authentication = Existing->getSecond();
477   } else {
478     Authentication = computeVTPointerAuthentication(Record);
479     VTablePtrAuthInfos.insert(std::make_pair(Record, Authentication));
480   }
481   return Authentication;
482 }
483 
484 std::optional<CGPointerAuthInfo>
getVTablePointerAuthInfo(CodeGenFunction * CGF,const CXXRecordDecl * Record,llvm::Value * StorageAddress)485 CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF,
486                                         const CXXRecordDecl *Record,
487                                         llvm::Value *StorageAddress) {
488   auto Authentication = getVTablePointerAuthentication(Record);
489   if (!Authentication)
490     return std::nullopt;
491 
492   llvm::Value *Discriminator = nullptr;
493   if (auto ExtraDiscriminator = Authentication->getExtraDiscriminator())
494     Discriminator = llvm::ConstantInt::get(IntPtrTy, ExtraDiscriminator);
495 
496   if (Authentication->isAddressDiscriminated()) {
497     assert(StorageAddress &&
498            "address not provided for address-discriminated schema");
499     if (Discriminator)
500       Discriminator =
501           CGF->EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);
502     else
503       Discriminator = CGF->Builder.CreatePtrToInt(StorageAddress, IntPtrTy);
504   }
505 
506   return CGPointerAuthInfo(Authentication->getKey(),
507                            PointerAuthenticationMode::SignAndAuth,
508                            /* IsIsaPointer */ false,
509                            /* AuthenticatesNullValues */ false, Discriminator);
510 }
511 
authPointerToPointerCast(llvm::Value * ResultPtr,QualType SourceType,QualType DestType)512 llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr,
513                                                        QualType SourceType,
514                                                        QualType DestType) {
515   CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
516   if (SourceType->isSignableType())
517     CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);
518 
519   if (DestType->isSignableType())
520     NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);
521 
522   if (!CurAuthInfo && !NewAuthInfo)
523     return ResultPtr;
524 
525   // If only one side of the cast is a function pointer, then we still need to
526   // resign to handle casts to/from opaque pointers.
527   if (!CurAuthInfo && DestType->isFunctionPointerType())
528     CurAuthInfo = CGM.getFunctionPointerAuthInfo(SourceType);
529 
530   if (!NewAuthInfo && SourceType->isFunctionPointerType())
531     NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
532 
533   return emitPointerAuthResign(ResultPtr, DestType, CurAuthInfo, NewAuthInfo,
534                                /*IsKnownNonNull=*/false);
535 }
536 
authPointerToPointerCast(Address Ptr,QualType SourceType,QualType DestType)537 Address CodeGenFunction::authPointerToPointerCast(Address Ptr,
538                                                   QualType SourceType,
539                                                   QualType DestType) {
540   CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
541   if (SourceType->isSignableType())
542     CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType);
543 
544   if (DestType->isSignableType())
545     NewAuthInfo = getPointerAuthInfoForType(CGM, DestType);
546 
547   if (!CurAuthInfo && !NewAuthInfo)
548     return Ptr;
549 
550   if (!CurAuthInfo && DestType->isFunctionPointerType()) {
551     // When casting a non-signed pointer to a function pointer, just set the
552     // auth info on Ptr to the assumed schema. The pointer will be resigned to
553     // the effective type when used.
554     Ptr.setPointerAuthInfo(CGM.getFunctionPointerAuthInfo(SourceType));
555     return Ptr;
556   }
557 
558   if (!NewAuthInfo && SourceType->isFunctionPointerType()) {
559     NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType);
560     Ptr = Ptr.getResignedAddress(NewAuthInfo, *this);
561     Ptr.setPointerAuthInfo(CGPointerAuthInfo());
562     return Ptr;
563   }
564 
565   return Ptr;
566 }
567 
getAsNaturalAddressOf(Address Addr,QualType PointeeTy)568 Address CodeGenFunction::getAsNaturalAddressOf(Address Addr,
569                                                QualType PointeeTy) {
570   CGPointerAuthInfo Info =
571       PointeeTy.isNull() ? CGPointerAuthInfo()
572                          : CGM.getPointerAuthInfoForPointeeType(PointeeTy);
573   return Addr.getResignedAddress(Info, *this);
574 }
575 
getResignedAddress(const CGPointerAuthInfo & NewInfo,CodeGenFunction & CGF) const576 Address Address::getResignedAddress(const CGPointerAuthInfo &NewInfo,
577                                     CodeGenFunction &CGF) const {
578   assert(isValid() && "pointer isn't valid");
579   CGPointerAuthInfo CurInfo = getPointerAuthInfo();
580   llvm::Value *Val;
581 
582   // Nothing to do if neither the current or the new ptrauth info needs signing.
583   if (!CurInfo.isSigned() && !NewInfo.isSigned())
584     return Address(getBasePointer(), getElementType(), getAlignment(),
585                    isKnownNonNull());
586 
587   assert(ElementType && "Effective type has to be set");
588   assert(!Offset && "unexpected non-null offset");
589 
590   // If the current and the new ptrauth infos are the same and the offset is
591   // null, just cast the base pointer to the effective type.
592   if (CurInfo == NewInfo && !hasOffset())
593     Val = getBasePointer();
594   else
595     Val = CGF.emitPointerAuthResign(getBasePointer(), QualType(), CurInfo,
596                                     NewInfo, isKnownNonNull());
597 
598   Val = CGF.Builder.CreateBitCast(Val, getType());
599   return Address(Val, getElementType(), getAlignment(), NewInfo,
600                  /*Offset=*/nullptr, isKnownNonNull());
601 }
602 
emitRawPointerSlow(CodeGenFunction & CGF) const603 llvm::Value *Address::emitRawPointerSlow(CodeGenFunction &CGF) const {
604   return CGF.getAsNaturalPointerTo(*this, QualType());
605 }
606 
getPointer(CodeGenFunction & CGF) const607 llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const {
608   assert(isSimple());
609   return emitResignedPointer(getType(), CGF);
610 }
611 
emitResignedPointer(QualType PointeeTy,CodeGenFunction & CGF) const612 llvm::Value *LValue::emitResignedPointer(QualType PointeeTy,
613                                          CodeGenFunction &CGF) const {
614   assert(isSimple());
615   return CGF.getAsNaturalAddressOf(Addr, PointeeTy).getBasePointer();
616 }
617 
emitRawPointer(CodeGenFunction & CGF) const618 llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const {
619   assert(isSimple());
620   return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr;
621 }
622