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 CGPointerAuthInfo
EmitPointerAuthInfo(PointerAuthQualifier Qual,Address StorageAddress)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
getPointerAuthInfoForPointeeType(CodeGenModule & CGM,QualType PointeeType)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
getPointerAuthInfoForPointeeType(QualType T)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.
getPointerAuthInfoForType(CodeGenModule & CGM,QualType PointerType)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
getPointerAuthInfoForType(QualType T)192 CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) {
193 return ::getPointerAuthInfoForType(*this, T);
194 }
195
196 static std::pair<llvm::Value *, CGPointerAuthInfo>
emitLoadOfOrigPointerRValue(CodeGenFunction & CGF,const LValue & LV,SourceLocation Loc)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>
EmitOrigPointerRValue(const Expr * E)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 *
EmitPointerAuthQualify(PointerAuthQualifier DestQualifier,const Expr * E,Address DestStorageAddress)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
EmitPointerAuthQualify(PointerAuthQualifier DestQualifier,llvm::Value * Value,QualType PointerType,Address DestStorageAddress,bool IsKnownNonNull)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
EmitPointerAuthUnqualify(PointerAuthQualifier CurQualifier,llvm::Value * Value,QualType PointerType,Address CurStorageAddress,bool IsKnownNonNull)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
isZeroConstant(const llvm::Value * Value)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
equalAuthPolicies(const CGPointerAuthInfo & Left,const CGPointerAuthInfo & Right)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.
getDiscriminatorOrZero(const CGPointerAuthInfo & Info,CGBuilderTy & Builder)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 *
emitPointerAuthResignCall(llvm::Value * Value,const CGPointerAuthInfo & CurAuth,const CGPointerAuthInfo & NewAuth)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
emitPointerAuthResign(llvm::Value * Value,QualType Type,const CGPointerAuthInfo & CurAuthInfo,const CGPointerAuthInfo & NewAuthInfo,bool IsKnownNonNull)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
EmitPointerAuthCopy(PointerAuthQualifier Qual,QualType T,Address DestAddress,Address SrcAddress)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 *
getConstantSignedPointer(llvm::Constant * Pointer,unsigned Key,llvm::Constant * StorageAddress,llvm::ConstantInt * OtherDiscriminator)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
shouldSignPointer(const PointerAuthSchema & Schema)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.
getConstantSignedPointer(llvm::Constant * Pointer,const PointerAuthSchema & Schema,llvm::Constant * StorageAddress,GlobalDecl SchemaDecl,QualType SchemaType)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.
getFunctionPointer(llvm::Constant * Pointer,QualType 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
getFunctionPointer(GlobalDecl GD,llvm::Type * Ty)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
getMemberFunctionPointerAuthInfo(QualType FT)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
getMemberFunctionPointer(llvm::Constant * Pointer,QualType FT)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
getMemberFunctionPointer(const FunctionDecl * FD,llvm::Type * Ty)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>
computeVTPointerAuthentication(const CXXRecordDecl * ThisClass)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>
getVTablePointerAuthentication(const CXXRecordDecl * Record)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>
getVTablePointerAuthInfo(CodeGenFunction * CGF,const CXXRecordDecl * Record,llvm::Value * StorageAddress)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
authPointerToPointerCast(llvm::Value * ResultPtr,QualType SourceType,QualType DestType)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
authPointerToPointerCast(Address Ptr,QualType SourceType,QualType DestType)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
getAsNaturalAddressOf(Address Addr,QualType PointeeTy)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
getResignedAddress(const CGPointerAuthInfo & NewInfo,CodeGenFunction & CGF) const713 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
emitRawPointerSlow(CodeGenFunction & CGF) const739 llvm::Value *Address::emitRawPointerSlow(CodeGenFunction &CGF) const {
740 return CGF.getAsNaturalPointerTo(*this, QualType());
741 }
742
getPointer(CodeGenFunction & CGF) const743 llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const {
744 assert(isSimple());
745 return emitResignedPointer(getType(), CGF);
746 }
747
emitResignedPointer(QualType PointeeTy,CodeGenFunction & CGF) const748 llvm::Value *LValue::emitResignedPointer(QualType PointeeTy,
749 CodeGenFunction &CGF) const {
750 assert(isSimple());
751 return CGF.getAsNaturalAddressOf(Addr, PointeeTy).getBasePointer();
752 }
753
emitRawPointer(CodeGenFunction & CGF) const754 llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const {
755 assert(isSimple());
756 return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr;
757 }
758