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 | Ty: IntPtrTy, V: getContext().getPointerAuthTypeDiscriminator(T: Type)); |
36 | |
37 | case PointerAuthSchema::Discrimination::Decl: |
38 | assert(Decl.getDecl() && |
39 | "declaration not provided for decl-discriminated schema" ); |
40 | return llvm::ConstantInt::get(Ty: IntPtrTy, |
41 | V: getPointerAuthDeclDiscriminator(GD: Decl)); |
42 | |
43 | case PointerAuthSchema::Discrimination::Constant: |
44 | return llvm::ConstantInt::get(Ty: IntPtrTy, V: 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(T: FunctionType); |
52 | } |
53 | |
54 | uint16_t CodeGen::getPointerAuthDeclDiscriminator(CodeGenModule &CGM, |
55 | GlobalDecl Declaration) { |
56 | return CGM.getPointerAuthDeclDiscriminator(GD: 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(GD: Declaration); |
66 | EntityHash = llvm::getPointerAuthStableSipHash(S: 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, Decl: GlobalDecl(), Type: 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(V: StorageAddress, DestTy: IntPtrTy); |
97 | auto Intrinsic = CGM.getIntrinsic(IID: llvm::Intrinsic::ptrauth_blend); |
98 | return Builder.CreateCall(Callee: Intrinsic, Args: {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, Decl: SchemaDecl, Type: 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(V: StorageAddress, DestTy: 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 |
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(T: PointeeType); |
138 | |
139 | // Normal data pointers never use direct pointer authentication by default. |
140 | return CGPointerAuthInfo(); |
141 | } |
142 | |
143 | CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) { |
144 | return ::getPointerAuthInfoForPointeeType(CGM&: *this, PointeeType: T); |
145 | } |
146 | |
147 | /// Return the natural pointer authentication for values of the given |
148 | /// pointer type. |
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 | |
165 | CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) { |
166 | return ::getPointerAuthInfoForType(CGM&: *this, PointerType: T); |
167 | } |
168 | |
169 | static bool isZeroConstant(const llvm::Value *Value) { |
170 | if (const auto *CI = dyn_cast<llvm::ConstantInt>(Val: Value)) |
171 | return CI->isZero(); |
172 | return false; |
173 | } |
174 | |
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. |
186 | static llvm::Value *getDiscriminatorOrZero(const CGPointerAuthInfo &Info, |
187 | CGBuilderTy &Builder) { |
188 | llvm::Value *Discriminator = Info.getDiscriminator(); |
189 | return Discriminator ? Discriminator : Builder.getSize(N: 0); |
190 | } |
191 | |
192 | llvm::Value * |
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(Info: CurAuth, Pointer: Value); |
203 | return EmitPointerAuthSign(Info: NewAuth, Pointer: AuthedValue); |
204 | } |
205 | // Convert the pointer to intptr_t before signing it. |
206 | auto *OrigType = Value->getType(); |
207 | Value = Builder.CreatePtrToInt(V: Value, DestTy: IntPtrTy); |
208 | |
209 | auto *CurKey = Builder.getInt32(C: CurAuth.getKey()); |
210 | auto *NewKey = Builder.getInt32(C: NewAuth.getKey()); |
211 | |
212 | llvm::Value *CurDiscriminator = getDiscriminatorOrZero(Info: CurAuth, Builder); |
213 | llvm::Value *NewDiscriminator = getDiscriminatorOrZero(Info: 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(IID: llvm::Intrinsic::ptrauth_resign); |
219 | Value = EmitRuntimeCall( |
220 | callee: Intrinsic, args: {Value, CurKey, CurDiscriminator, NewKey, NewDiscriminator}); |
221 | |
222 | // Convert back to the original type. |
223 | Value = Builder.CreateIntToPtr(V: Value, DestTy: OrigType); |
224 | return Value; |
225 | } |
226 | |
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>(Val: Value->getType())) { |
237 | Null = CGM.getNullPointer(T: PointerValue, QT: Type); |
238 | } else { |
239 | assert(Value->getType()->isIntegerTy()); |
240 | Null = llvm::ConstantInt::get(Ty: IntPtrTy, V: 0); |
241 | } |
242 | if (Value == Null) |
243 | return Value; |
244 | |
245 | // If both schemas sign the same way, we're done. |
246 | if (equalAuthPolicies(Left: CurAuthInfo, Right: 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(Value: NewD)) || |
253 | (NewD == nullptr && isZeroConstant(Value: 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(V: Value, Q: CGM.getDataLayout())) { |
263 | ContBB = createBasicBlock(name: "resign.cont" ); |
264 | ResignBB = createBasicBlock(name: "resign.nonnull" ); |
265 | |
266 | auto *IsNonNull = Builder.CreateICmpNE(LHS: Value, RHS: Null); |
267 | Builder.CreateCondBr(Cond: IsNonNull, True: ResignBB, False: ContBB); |
268 | EmitBlock(BB: ResignBB); |
269 | } |
270 | |
271 | // Perform the auth/sign/resign operation. |
272 | if (!NewAuthInfo) |
273 | Value = EmitPointerAuthAuth(Info: CurAuthInfo, Pointer: Value); |
274 | else if (!CurAuthInfo) |
275 | Value = EmitPointerAuthSign(Info: NewAuthInfo, Pointer: Value); |
276 | else |
277 | Value = emitPointerAuthResignCall(Value, CurAuth: CurAuthInfo, NewAuth: NewAuthInfo); |
278 | |
279 | // Clean up with a phi if we branched before. |
280 | if (ContBB) { |
281 | EmitBlock(BB: ContBB); |
282 | auto *Phi = Builder.CreatePHI(Ty: Value->getType(), NumReservedValues: 2); |
283 | Phi->addIncoming(V: Null, BB: InitBB); |
284 | Phi->addIncoming(V: Value, BB: ResignBB); |
285 | Value = Phi; |
286 | } |
287 | |
288 | return Value; |
289 | } |
290 | |
291 | llvm::Constant * |
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(Ty: 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(Ty: Int64Ty, V: 0); |
309 | } |
310 | |
311 | return llvm::ConstantPtrAuth::get(Ptr: Pointer, |
312 | Key: llvm::ConstantInt::get(Ty: Int32Ty, V: Key), |
313 | Disc: IntegerDiscriminator, AddrDisc: AddressDiscriminator); |
314 | } |
315 | |
316 | /// Does a given PointerAuthScheme require us to sign a value |
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. |
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, Decl: SchemaDecl, Type: SchemaType); |
332 | |
333 | return getConstantSignedPointer(Pointer, Key: Schema.getKey(), StorageAddress, |
334 | OtherDiscriminator); |
335 | } |
336 | |
337 | /// If applicable, sign a given constant function pointer with the ABI rules for |
338 | /// 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(T: FunctionType)) |
346 | return getConstantSignedPointer( |
347 | Pointer, Key: PointerAuth.getKey(), /*StorageAddress=*/nullptr, |
348 | OtherDiscriminator: cast_or_null<llvm::ConstantInt>(Val: PointerAuth.getDiscriminator())); |
349 | |
350 | return Pointer; |
351 | } |
352 | |
353 | llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD, |
354 | llvm::Type *Ty) { |
355 | const auto *FD = cast<FunctionDecl>(Val: 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(ResultTy: Proto->getReturnType(), |
363 | Info: Proto->getExtInfo()); |
364 | |
365 | return getFunctionPointer(Pointer: getRawFunctionPointer(GD, Ty), FunctionType: FuncType); |
366 | } |
367 | |
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, Decl: GlobalDecl(), Type: FT); |
379 | return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(), |
380 | /* IsIsaPointer */ false, |
381 | /* AuthenticatesNullValues */ false, Discriminator); |
382 | } |
383 | |
384 | llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer, |
385 | QualType FT) { |
386 | if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT)) |
387 | return getConstantSignedPointer( |
388 | Pointer, Key: PointerAuth.getKey(), StorageAddress: nullptr, |
389 | OtherDiscriminator: cast_or_null<llvm::ConstantInt>(Val: PointerAuth.getDiscriminator())); |
390 | |
391 | return Pointer; |
392 | } |
393 | |
394 | llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD, |
395 | llvm::Type *Ty) { |
396 | QualType FT = FD->getType(); |
397 | FT = getContext().getMemberPointerType( |
398 | T: FT, Cls: cast<CXXMethodDecl>(Val: FD)->getParent()->getTypeForDecl()); |
399 | return getMemberFunctionPointer(Pointer: getRawFunctionPointer(GD: FD, Ty), FT); |
400 | } |
401 | |
402 | std::optional<PointerAuthQualifier> |
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(RD: 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, IsAddressDiscriminated: AddressDiscriminated, ExtraDiscriminator: Discriminator, |
463 | AuthenticationMode: PointerAuthenticationMode::SignAndAuth, |
464 | /* IsIsaPointer */ false, |
465 | /* AuthenticatesNullValues */ false); |
466 | } |
467 | |
468 | std::optional<PointerAuthQualifier> |
469 | CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) { |
470 | if (!Record->getDefinition() || !Record->isPolymorphic()) |
471 | return std::nullopt; |
472 | |
473 | auto Existing = VTablePtrAuthInfos.find(Val: Record); |
474 | std::optional<PointerAuthQualifier> Authentication; |
475 | if (Existing != VTablePtrAuthInfos.end()) { |
476 | Authentication = Existing->getSecond(); |
477 | } else { |
478 | Authentication = computeVTPointerAuthentication(ThisClass: Record); |
479 | VTablePtrAuthInfos.insert(KV: std::make_pair(x&: Record, y&: Authentication)); |
480 | } |
481 | return Authentication; |
482 | } |
483 | |
484 | std::optional<CGPointerAuthInfo> |
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 = Authentication->getExtraDiscriminator()) |
494 | Discriminator = llvm::ConstantInt::get(Ty: IntPtrTy, V: 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(V: StorageAddress, DestTy: IntPtrTy); |
504 | } |
505 | |
506 | return CGPointerAuthInfo(Authentication->getKey(), |
507 | PointerAuthenticationMode::SignAndAuth, |
508 | /* IsIsaPointer */ false, |
509 | /* AuthenticatesNullValues */ false, Discriminator); |
510 | } |
511 | |
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, PointerType: SourceType); |
518 | |
519 | if (DestType->isSignableType()) |
520 | NewAuthInfo = getPointerAuthInfoForType(CGM, PointerType: 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(T: SourceType); |
529 | |
530 | if (!NewAuthInfo && SourceType->isFunctionPointerType()) |
531 | NewAuthInfo = CGM.getFunctionPointerAuthInfo(T: DestType); |
532 | |
533 | return emitPointerAuthResign(Value: ResultPtr, Type: DestType, CurAuthInfo, NewAuthInfo, |
534 | /*IsKnownNonNull=*/false); |
535 | } |
536 | |
537 | Address CodeGenFunction::authPointerToPointerCast(Address Ptr, |
538 | QualType SourceType, |
539 | QualType DestType) { |
540 | CGPointerAuthInfo CurAuthInfo, NewAuthInfo; |
541 | if (SourceType->isSignableType()) |
542 | CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType: SourceType); |
543 | |
544 | if (DestType->isSignableType()) |
545 | NewAuthInfo = getPointerAuthInfoForType(CGM, PointerType: 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(T: SourceType)); |
555 | return Ptr; |
556 | } |
557 | |
558 | if (!NewAuthInfo && SourceType->isFunctionPointerType()) { |
559 | NewAuthInfo = CGM.getFunctionPointerAuthInfo(T: DestType); |
560 | Ptr = Ptr.getResignedAddress(NewInfo: NewAuthInfo, CGF&: *this); |
561 | Ptr.setPointerAuthInfo(CGPointerAuthInfo()); |
562 | return Ptr; |
563 | } |
564 | |
565 | return Ptr; |
566 | } |
567 | |
568 | Address CodeGenFunction::getAsNaturalAddressOf(Address Addr, |
569 | QualType PointeeTy) { |
570 | CGPointerAuthInfo Info = |
571 | PointeeTy.isNull() ? CGPointerAuthInfo() |
572 | : CGM.getPointerAuthInfoForPointeeType(T: PointeeTy); |
573 | return Addr.getResignedAddress(NewInfo: Info, CGF&: *this); |
574 | } |
575 | |
576 | 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(Value: getBasePointer(), Type: QualType(), CurAuthInfo: CurInfo, |
596 | NewAuthInfo: NewInfo, IsKnownNonNull: isKnownNonNull()); |
597 | |
598 | Val = CGF.Builder.CreateBitCast(V: Val, DestTy: getType()); |
599 | return Address(Val, getElementType(), getAlignment(), NewInfo, |
600 | /*Offset=*/nullptr, isKnownNonNull()); |
601 | } |
602 | |
603 | llvm::Value *Address::emitRawPointerSlow(CodeGenFunction &CGF) const { |
604 | return CGF.getAsNaturalPointerTo(Addr: *this, PointeeType: QualType()); |
605 | } |
606 | |
607 | llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const { |
608 | assert(isSimple()); |
609 | return emitResignedPointer(PointeeTy: getType(), CGF); |
610 | } |
611 | |
612 | llvm::Value *LValue::emitResignedPointer(QualType PointeeTy, |
613 | CodeGenFunction &CGF) const { |
614 | assert(isSimple()); |
615 | return CGF.getAsNaturalAddressOf(Addr: Addr, PointeeTy).getBasePointer(); |
616 | } |
617 | |
618 | llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const { |
619 | assert(isSimple()); |
620 | return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr; |
621 | } |
622 | |