|
15 | 15 | #include "CodeGenModule.h"
|
16 | 16 | #include "clang/CodeGen/CodeGenABITypes.h"
|
17 | 17 | #include "clang/CodeGen/ConstantInitBuilder.h"
|
| 18 | +#include "llvm/Analysis/ValueTracking.h" |
18 | 19 | #include "llvm/Support/SipHash.h"
|
19 | 20 |
|
20 | 21 | using namespace clang;
|
@@ -165,6 +166,128 @@ CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) {
|
165 | 166 | return ::getPointerAuthInfoForType(*this, T);
|
166 | 167 | }
|
167 | 168 |
|
| 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 | + |
| 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(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(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 | + |
| 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 | + |
168 | 291 | llvm::Constant *
|
169 | 292 | CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
|
170 | 293 | llvm::Constant *StorageAddress,
|
@@ -351,3 +474,110 @@ CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF,
|
351 | 474 | /* IsIsaPointer */ false,
|
352 | 475 | /* AuthenticatesNullValues */ false, Discriminator);
|
353 | 476 | }
|
| 477 | + |
| 478 | +llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr, |
| 479 | + QualType SourceType, |
| 480 | + QualType DestType) { |
| 481 | + CGPointerAuthInfo CurAuthInfo, NewAuthInfo; |
| 482 | + if (SourceType->isSignableType()) |
| 483 | + CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType); |
| 484 | + |
| 485 | + if (DestType->isSignableType()) |
| 486 | + NewAuthInfo = getPointerAuthInfoForType(CGM, DestType); |
| 487 | + |
| 488 | + if (!CurAuthInfo && !NewAuthInfo) |
| 489 | + return ResultPtr; |
| 490 | + |
| 491 | + // If only one side of the cast is a function pointer, then we still need to |
| 492 | + // resign to handle casts to/from opaque pointers. |
| 493 | + if (!CurAuthInfo && DestType->isFunctionPointerType()) |
| 494 | + CurAuthInfo = CGM.getFunctionPointerAuthInfo(SourceType); |
| 495 | + |
| 496 | + if (!NewAuthInfo && SourceType->isFunctionPointerType()) |
| 497 | + NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType); |
| 498 | + |
| 499 | + return emitPointerAuthResign(ResultPtr, DestType, CurAuthInfo, NewAuthInfo, |
| 500 | + /*IsKnownNonNull=*/false); |
| 501 | +} |
| 502 | + |
| 503 | +Address CodeGenFunction::authPointerToPointerCast(Address Ptr, |
| 504 | + QualType SourceType, |
| 505 | + QualType DestType) { |
| 506 | + CGPointerAuthInfo CurAuthInfo, NewAuthInfo; |
| 507 | + if (SourceType->isSignableType()) |
| 508 | + CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType); |
| 509 | + |
| 510 | + if (DestType->isSignableType()) |
| 511 | + NewAuthInfo = getPointerAuthInfoForType(CGM, DestType); |
| 512 | + |
| 513 | + if (!CurAuthInfo && !NewAuthInfo) |
| 514 | + return Ptr; |
| 515 | + |
| 516 | + if (!CurAuthInfo && DestType->isFunctionPointerType()) { |
| 517 | + // When casting a non-signed pointer to a function pointer, just set the |
| 518 | + // auth info on Ptr to the assumed schema. The pointer will be resigned to |
| 519 | + // the effective type when used. |
| 520 | + Ptr.setPointerAuthInfo(CGM.getFunctionPointerAuthInfo(SourceType)); |
| 521 | + return Ptr; |
| 522 | + } |
| 523 | + |
| 524 | + if (!NewAuthInfo && SourceType->isFunctionPointerType()) { |
| 525 | + NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType); |
| 526 | + Ptr = Ptr.getResignedAddress(NewAuthInfo, *this); |
| 527 | + Ptr.setPointerAuthInfo(CGPointerAuthInfo()); |
| 528 | + return Ptr; |
| 529 | + } |
| 530 | + |
| 531 | + return Ptr; |
| 532 | +} |
| 533 | + |
| 534 | +Address CodeGenFunction::getAsNaturalAddressOf(Address Addr, |
| 535 | + QualType PointeeTy) { |
| 536 | + CGPointerAuthInfo Info = |
| 537 | + PointeeTy.isNull() ? CGPointerAuthInfo() |
| 538 | + : CGM.getPointerAuthInfoForPointeeType(PointeeTy); |
| 539 | + return Addr.getResignedAddress(Info, *this); |
| 540 | +} |
| 541 | + |
| 542 | +Address Address::getResignedAddress(const CGPointerAuthInfo &NewInfo, |
| 543 | + CodeGenFunction &CGF) const { |
| 544 | + assert(isValid() && "pointer isn't valid"); |
| 545 | + CGPointerAuthInfo CurInfo = getPointerAuthInfo(); |
| 546 | + llvm::Value *Val; |
| 547 | + |
| 548 | + // Nothing to do if neither the current or the new ptrauth info needs signing. |
| 549 | + if (!CurInfo.isSigned() && !NewInfo.isSigned()) |
| 550 | + return Address(getBasePointer(), getElementType(), getAlignment(), |
| 551 | + isKnownNonNull()); |
| 552 | + |
| 553 | + assert(ElementType && "Effective type has to be set"); |
| 554 | + assert(!Offset && "unexpected non-null offset"); |
| 555 | + |
| 556 | + // If the current and the new ptrauth infos are the same and the offset is |
| 557 | + // null, just cast the base pointer to the effective type. |
| 558 | + if (CurInfo == NewInfo && !hasOffset()) |
| 559 | + Val = getBasePointer(); |
| 560 | + else |
| 561 | + Val = CGF.emitPointerAuthResign(getBasePointer(), QualType(), CurInfo, |
| 562 | + NewInfo, isKnownNonNull()); |
| 563 | + |
| 564 | + Val = CGF.Builder.CreateBitCast(Val, getType()); |
| 565 | + return Address(Val, getElementType(), getAlignment(), NewInfo, |
| 566 | + /*Offset=*/nullptr, isKnownNonNull()); |
| 567 | +} |
| 568 | + |
| 569 | +llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const { |
| 570 | + assert(isSimple()); |
| 571 | + return emitResignedPointer(getType(), CGF); |
| 572 | +} |
| 573 | + |
| 574 | +llvm::Value *LValue::emitResignedPointer(QualType PointeeTy, |
| 575 | + CodeGenFunction &CGF) const { |
| 576 | + assert(isSimple()); |
| 577 | + return CGF.getAsNaturalAddressOf(Addr, PointeeTy).getBasePointer(); |
| 578 | +} |
| 579 | + |
| 580 | +llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const { |
| 581 | + assert(isSimple()); |
| 582 | + return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr; |
| 583 | +} |
0 commit comments