Author: Akira Hatanaka Date: 2024-07-18T07:51:17-07:00 New Revision: f6b06b42a3f4f59ff33da20d42358f2768eaf726
URL: https://github.com/llvm/llvm-project/commit/f6b06b42a3f4f59ff33da20d42358f2768eaf726 DIFF: https://github.com/llvm/llvm-project/commit/f6b06b42a3f4f59ff33da20d42358f2768eaf726.diff LOG: [PAC] Implement function pointer re-signing (#98847) Re-signing occurs when function type discrimination is enabled and a function pointer is converted to another function pointer type that requires signing using a different discriminator. A function pointer is re-signed using discriminator zero when it's converted to a pointer to a non-function type such as `void*`. --------- Co-authored-by: Ahmed Bougacha <ah...@bougacha.org> Co-authored-by: John McCall <rjmcc...@apple.com> Added: clang/test/CodeGen/ptrauth-function-lvalue-cast-disc.c clang/test/CodeGen/ptrauth-function-type-discriminator-cast.c Modified: clang/lib/CodeGen/Address.h clang/lib/CodeGen/CGBuilder.h clang/lib/CodeGen/CGExpr.cpp clang/lib/CodeGen/CGExprScalar.cpp clang/lib/CodeGen/CGPointerAuth.cpp clang/lib/CodeGen/CGValue.h clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/Headers/ptrauth.h Removed: ################################################################################ diff --git a/clang/lib/CodeGen/Address.h b/clang/lib/CodeGen/Address.h index 35ec370a139c9..1c4d2e103b5e7 100644 --- a/clang/lib/CodeGen/Address.h +++ b/clang/lib/CodeGen/Address.h @@ -14,6 +14,7 @@ #ifndef LLVM_CLANG_LIB_CODEGEN_ADDRESS_H #define LLVM_CLANG_LIB_CODEGEN_ADDRESS_H +#include "CGPointerAuthInfo.h" #include "clang/AST/CharUnits.h" #include "clang/AST/Type.h" #include "llvm/ADT/PointerIntPair.h" @@ -108,6 +109,22 @@ class RawAddress { /// Like RawAddress, an abstract representation of an aligned address, but the /// pointer contained in this class is possibly signed. +/// +/// This is designed to be an IR-level abstraction, carrying just the +/// information necessary to perform IR operations on an address like loads and +/// stores. In particular, it doesn't carry C type information or allow the +/// representation of things like bit-fields; clients working at that level +/// should generally be using `LValue`. +/// +/// An address may be either *raw*, meaning that it's an ordinary machine +/// pointer, or *signed*, meaning that the pointer carries an embedded +/// pointer-authentication signature. Representing signed pointers directly in +/// this abstraction allows the authentication to be delayed as long as possible +/// without forcing IRGen to use totally diff erent code paths for signed and +/// unsigned values or to separately propagate signature information through +/// every API that manipulates addresses. Pointer arithmetic on signed addresses +/// (e.g. drilling down to a struct field) is accumulated into a separate offset +/// which is applied when the address is finally accessed. class Address { friend class CGBuilderTy; @@ -121,7 +138,11 @@ class Address { CharUnits Alignment; - /// Offset from the base pointer. + /// The ptrauth information needed to authenticate the base pointer. + CGPointerAuthInfo PtrAuthInfo; + + /// Offset from the base pointer. This is non-null only when the base + /// pointer is signed. llvm::Value *Offset = nullptr; llvm::Value *emitRawPointerSlow(CodeGenFunction &CGF) const; @@ -140,12 +161,14 @@ class Address { } Address(llvm::Value *BasePtr, llvm::Type *ElementType, CharUnits Alignment, - llvm::Value *Offset, KnownNonNull_t IsKnownNonNull = NotKnownNonNull) + CGPointerAuthInfo PtrAuthInfo, llvm::Value *Offset, + KnownNonNull_t IsKnownNonNull = NotKnownNonNull) : Pointer(BasePtr, IsKnownNonNull), ElementType(ElementType), - Alignment(Alignment), Offset(Offset) {} + Alignment(Alignment), PtrAuthInfo(PtrAuthInfo), Offset(Offset) {} Address(RawAddress RawAddr) - : Pointer(RawAddr.isValid() ? RawAddr.getPointer() : nullptr), + : Pointer(RawAddr.isValid() ? RawAddr.getPointer() : nullptr, + RawAddr.isValid() ? RawAddr.isKnownNonNull() : NotKnownNonNull), ElementType(RawAddr.isValid() ? RawAddr.getElementType() : nullptr), Alignment(RawAddr.isValid() ? RawAddr.getAlignment() : CharUnits::Zero()) {} @@ -192,6 +215,9 @@ class Address { /// Return the IR name of the pointer value. llvm::StringRef getName() const { return Pointer.getPointer()->getName(); } + const CGPointerAuthInfo &getPointerAuthInfo() const { return PtrAuthInfo; } + void setPointerAuthInfo(const CGPointerAuthInfo &Info) { PtrAuthInfo = Info; } + // This function is called only in CGBuilderBaseTy::CreateElementBitCast. void setElementType(llvm::Type *Ty) { assert(hasOffset() && @@ -199,6 +225,8 @@ class Address { ElementType = Ty; } + bool isSigned() const { return PtrAuthInfo.isSigned(); } + /// Whether the pointer is known not to be null. KnownNonNull_t isKnownNonNull() const { assert(isValid()); @@ -215,6 +243,9 @@ class Address { llvm::Value *getOffset() const { return Offset; } + Address getResignedAddress(const CGPointerAuthInfo &NewInfo, + CodeGenFunction &CGF) const; + /// Return the pointer contained in this class after authenticating it and /// adding offset to it if necessary. llvm::Value *emitRawPointer(CodeGenFunction &CGF) const { @@ -240,7 +271,8 @@ class Address { /// alignment. Address withElementType(llvm::Type *ElemTy) const { if (!hasOffset()) - return Address(getBasePointer(), ElemTy, getAlignment(), nullptr, + return Address(getBasePointer(), ElemTy, getAlignment(), + getPointerAuthInfo(), /*Offset=*/nullptr, isKnownNonNull()); Address A(*this); A.ElementType = ElemTy; diff --git a/clang/lib/CodeGen/CGBuilder.h b/clang/lib/CodeGen/CGBuilder.h index 0bc4fda62979c..5d59d5a4ae2c1 100644 --- a/clang/lib/CodeGen/CGBuilder.h +++ b/clang/lib/CodeGen/CGBuilder.h @@ -190,8 +190,8 @@ class CGBuilderTy : public CGBuilderBaseTy { const llvm::Twine &Name = "") { if (!Addr.hasOffset()) return Address(CreateAddrSpaceCast(Addr.getBasePointer(), Ty, Name), - ElementTy, Addr.getAlignment(), nullptr, - Addr.isKnownNonNull()); + ElementTy, Addr.getAlignment(), Addr.getPointerAuthInfo(), + /*Offset=*/nullptr, Addr.isKnownNonNull()); // Eagerly force a raw address if these is an offset. return RawAddress( CreateAddrSpaceCast(Addr.emitRawPointer(*getCGF()), Ty, Name), diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 5fdd3cc490e59..6a0af00b9e186 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1312,7 +1312,8 @@ static Address EmitPointerWithAlignment(const Expr *E, LValueBaseInfo *BaseInfo, if (CE->getCastKind() == CK_AddressSpaceConversion) Addr = CGF.Builder.CreateAddrSpaceCast( Addr, CGF.ConvertType(E->getType()), ElemTy); - return Addr; + return CGF.authPointerToPointerCast(Addr, CE->getSubExpr()->getType(), + CE->getType()); } break; diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index 084dc54537eb7..a17d68424bbce 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -2374,7 +2374,9 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { DestLV.setTBAAInfo(TBAAAccessInfo::getMayAliasInfo()); return EmitLoadOfLValue(DestLV, CE->getExprLoc()); } - return Builder.CreateBitCast(Src, DstTy); + + llvm::Value *Result = Builder.CreateBitCast(Src, DstTy); + return CGF.authPointerToPointerCast(Result, E->getType(), DestTy); } case CK_AddressSpaceConversion: { Expr::EvalResult Result; @@ -2524,6 +2526,8 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { if (DestTy.mayBeDynamicClass()) IntToPtr = Builder.CreateLaunderInvariantGroup(IntToPtr); } + + IntToPtr = CGF.authPointerToPointerCast(IntToPtr, E->getType(), DestTy); return IntToPtr; } case CK_PointerToIntegral: { @@ -2539,6 +2543,7 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) { PtrExpr = Builder.CreateStripInvariantGroup(PtrExpr); } + PtrExpr = CGF.authPointerToPointerCast(PtrExpr, E->getType(), DestTy); return Builder.CreatePtrToInt(PtrExpr, ConvertType(DestTy)); } case CK_ToVoid: { diff --git a/clang/lib/CodeGen/CGPointerAuth.cpp b/clang/lib/CodeGen/CGPointerAuth.cpp index 621d567dde721..7fe62c0788742 100644 --- a/clang/lib/CodeGen/CGPointerAuth.cpp +++ b/clang/lib/CodeGen/CGPointerAuth.cpp @@ -15,6 +15,7 @@ #include "CodeGenModule.h" #include "clang/CodeGen/CodeGenABITypes.h" #include "clang/CodeGen/ConstantInitBuilder.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/Support/SipHash.h" using namespace clang; @@ -165,6 +166,128 @@ CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) { return ::getPointerAuthInfoForType(*this, T); } +static bool isZeroConstant(const llvm::Value *Value) { + if (const auto *CI = dyn_cast<llvm::ConstantInt>(Value)) + return CI->isZero(); + return false; +} + +static bool equalAuthPolicies(const CGPointerAuthInfo &Left, + const CGPointerAuthInfo &Right) { + assert((Left.isSigned() || Right.isSigned()) && + "shouldn't be called if neither is signed"); + if (Left.isSigned() != Right.isSigned()) + return false; + return Left.getKey() == Right.getKey() && + Left.getAuthenticationMode() == Right.getAuthenticationMode(); +} + +// Return the discriminator or return zero if the discriminator is null. +static llvm::Value *getDiscriminatorOrZero(const CGPointerAuthInfo &Info, + CGBuilderTy &Builder) { + llvm::Value *Discriminator = Info.getDiscriminator(); + return Discriminator ? Discriminator : Builder.getSize(0); +} + +llvm::Value * +CodeGenFunction::emitPointerAuthResignCall(llvm::Value *Value, + const CGPointerAuthInfo &CurAuth, + const CGPointerAuthInfo &NewAuth) { + assert(CurAuth && NewAuth); + + if (CurAuth.getAuthenticationMode() != + PointerAuthenticationMode::SignAndAuth || + NewAuth.getAuthenticationMode() != + PointerAuthenticationMode::SignAndAuth) { + llvm::Value *AuthedValue = EmitPointerAuthAuth(CurAuth, Value); + return EmitPointerAuthSign(NewAuth, AuthedValue); + } + // Convert the pointer to intptr_t before signing it. + auto *OrigType = Value->getType(); + Value = Builder.CreatePtrToInt(Value, IntPtrTy); + + auto *CurKey = Builder.getInt32(CurAuth.getKey()); + auto *NewKey = Builder.getInt32(NewAuth.getKey()); + + llvm::Value *CurDiscriminator = getDiscriminatorOrZero(CurAuth, Builder); + llvm::Value *NewDiscriminator = getDiscriminatorOrZero(NewAuth, Builder); + + // call i64 @llvm.ptrauth.resign(i64 %pointer, + // i32 %curKey, i64 %curDiscriminator, + // i32 %newKey, i64 %newDiscriminator) + auto *Intrinsic = CGM.getIntrinsic(llvm::Intrinsic::ptrauth_resign); + Value = EmitRuntimeCall( + Intrinsic, {Value, CurKey, CurDiscriminator, NewKey, NewDiscriminator}); + + // Convert back to the original type. + Value = Builder.CreateIntToPtr(Value, OrigType); + return Value; +} + +llvm::Value *CodeGenFunction::emitPointerAuthResign( + llvm::Value *Value, QualType Type, const CGPointerAuthInfo &CurAuthInfo, + const CGPointerAuthInfo &NewAuthInfo, bool IsKnownNonNull) { + // Fast path: if neither schema wants a signature, we're done. + if (!CurAuthInfo && !NewAuthInfo) + return Value; + + llvm::Value *Null = nullptr; + // If the value is obviously null, we're done. + if (auto *PointerValue = dyn_cast<llvm::PointerType>(Value->getType())) { + Null = CGM.getNullPointer(PointerValue, Type); + } else { + assert(Value->getType()->isIntegerTy()); + Null = llvm::ConstantInt::get(IntPtrTy, 0); + } + if (Value == Null) + return Value; + + // If both schemas sign the same way, we're done. + if (equalAuthPolicies(CurAuthInfo, NewAuthInfo)) { + const llvm::Value *CurD = CurAuthInfo.getDiscriminator(); + const llvm::Value *NewD = NewAuthInfo.getDiscriminator(); + if (CurD == NewD) + return Value; + + if ((CurD == nullptr && isZeroConstant(NewD)) || + (NewD == nullptr && isZeroConstant(CurD))) + return Value; + } + + llvm::BasicBlock *InitBB = Builder.GetInsertBlock(); + llvm::BasicBlock *ResignBB = nullptr, *ContBB = nullptr; + + // Null pointers have to be mapped to null, and the ptrauth_resign + // intrinsic doesn't do that. + if (!IsKnownNonNull && !llvm::isKnownNonZero(Value, CGM.getDataLayout())) { + ContBB = createBasicBlock("resign.cont"); + ResignBB = createBasicBlock("resign.nonnull"); + + auto *IsNonNull = Builder.CreateICmpNE(Value, Null); + Builder.CreateCondBr(IsNonNull, ResignBB, ContBB); + EmitBlock(ResignBB); + } + + // Perform the auth/sign/resign operation. + if (!NewAuthInfo) + Value = EmitPointerAuthAuth(CurAuthInfo, Value); + else if (!CurAuthInfo) + Value = EmitPointerAuthSign(NewAuthInfo, Value); + else + Value = emitPointerAuthResignCall(Value, CurAuthInfo, NewAuthInfo); + + // Clean up with a phi if we branched before. + if (ContBB) { + EmitBlock(ContBB); + auto *Phi = Builder.CreatePHI(Value->getType(), 2); + Phi->addIncoming(Null, InitBB); + Phi->addIncoming(Value, ResignBB); + Value = Phi; + } + + return Value; +} + llvm::Constant * CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key, llvm::Constant *StorageAddress, @@ -351,3 +474,110 @@ CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF, /* IsIsaPointer */ false, /* AuthenticatesNullValues */ false, Discriminator); } + +llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr, + QualType SourceType, + QualType DestType) { + CGPointerAuthInfo CurAuthInfo, NewAuthInfo; + if (SourceType->isSignableType()) + CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType); + + if (DestType->isSignableType()) + NewAuthInfo = getPointerAuthInfoForType(CGM, DestType); + + if (!CurAuthInfo && !NewAuthInfo) + return ResultPtr; + + // If only one side of the cast is a function pointer, then we still need to + // resign to handle casts to/from opaque pointers. + if (!CurAuthInfo && DestType->isFunctionPointerType()) + CurAuthInfo = CGM.getFunctionPointerAuthInfo(SourceType); + + if (!NewAuthInfo && SourceType->isFunctionPointerType()) + NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType); + + return emitPointerAuthResign(ResultPtr, DestType, CurAuthInfo, NewAuthInfo, + /*IsKnownNonNull=*/false); +} + +Address CodeGenFunction::authPointerToPointerCast(Address Ptr, + QualType SourceType, + QualType DestType) { + CGPointerAuthInfo CurAuthInfo, NewAuthInfo; + if (SourceType->isSignableType()) + CurAuthInfo = getPointerAuthInfoForType(CGM, SourceType); + + if (DestType->isSignableType()) + NewAuthInfo = getPointerAuthInfoForType(CGM, DestType); + + if (!CurAuthInfo && !NewAuthInfo) + return Ptr; + + if (!CurAuthInfo && DestType->isFunctionPointerType()) { + // When casting a non-signed pointer to a function pointer, just set the + // auth info on Ptr to the assumed schema. The pointer will be resigned to + // the effective type when used. + Ptr.setPointerAuthInfo(CGM.getFunctionPointerAuthInfo(SourceType)); + return Ptr; + } + + if (!NewAuthInfo && SourceType->isFunctionPointerType()) { + NewAuthInfo = CGM.getFunctionPointerAuthInfo(DestType); + Ptr = Ptr.getResignedAddress(NewAuthInfo, *this); + Ptr.setPointerAuthInfo(CGPointerAuthInfo()); + return Ptr; + } + + return Ptr; +} + +Address CodeGenFunction::getAsNaturalAddressOf(Address Addr, + QualType PointeeTy) { + CGPointerAuthInfo Info = + PointeeTy.isNull() ? CGPointerAuthInfo() + : CGM.getPointerAuthInfoForPointeeType(PointeeTy); + return Addr.getResignedAddress(Info, *this); +} + +Address Address::getResignedAddress(const CGPointerAuthInfo &NewInfo, + CodeGenFunction &CGF) const { + assert(isValid() && "pointer isn't valid"); + CGPointerAuthInfo CurInfo = getPointerAuthInfo(); + llvm::Value *Val; + + // Nothing to do if neither the current or the new ptrauth info needs signing. + if (!CurInfo.isSigned() && !NewInfo.isSigned()) + return Address(getBasePointer(), getElementType(), getAlignment(), + isKnownNonNull()); + + assert(ElementType && "Effective type has to be set"); + assert(!Offset && "unexpected non-null offset"); + + // If the current and the new ptrauth infos are the same and the offset is + // null, just cast the base pointer to the effective type. + if (CurInfo == NewInfo && !hasOffset()) + Val = getBasePointer(); + else + Val = CGF.emitPointerAuthResign(getBasePointer(), QualType(), CurInfo, + NewInfo, isKnownNonNull()); + + Val = CGF.Builder.CreateBitCast(Val, getType()); + return Address(Val, getElementType(), getAlignment(), NewInfo, + /*Offset=*/nullptr, isKnownNonNull()); +} + +llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const { + assert(isSimple()); + return emitResignedPointer(getType(), CGF); +} + +llvm::Value *LValue::emitResignedPointer(QualType PointeeTy, + CodeGenFunction &CGF) const { + assert(isSimple()); + return CGF.getAsNaturalAddressOf(Addr, PointeeTy).getBasePointer(); +} + +llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const { + assert(isSimple()); + return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr; +} diff --git a/clang/lib/CodeGen/CGValue.h b/clang/lib/CodeGen/CGValue.h index f1ba3cf95ae59..c4ec8d207d2e3 100644 --- a/clang/lib/CodeGen/CGValue.h +++ b/clang/lib/CodeGen/CGValue.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_LIB_CODEGEN_CGVALUE_H #include "Address.h" +#include "CGPointerAuthInfo.h" #include "CodeGenTBAA.h" #include "EHScopeStack.h" #include "clang/AST/ASTContext.h" @@ -233,9 +234,6 @@ class LValue { // this lvalue. bool Nontemporal : 1; - // The pointer is known not to be null. - bool IsKnownNonNull : 1; - LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; @@ -263,7 +261,6 @@ class LValue { this->ImpreciseLifetime = false; this->Nontemporal = false; this->ThreadLocalRef = false; - this->IsKnownNonNull = false; this->BaseIvarExp = nullptr; } @@ -349,28 +346,26 @@ class LValue { LValueBaseInfo getBaseInfo() const { return BaseInfo; } void setBaseInfo(LValueBaseInfo Info) { BaseInfo = Info; } - KnownNonNull_t isKnownNonNull() const { - return (KnownNonNull_t)IsKnownNonNull; - } + KnownNonNull_t isKnownNonNull() const { return Addr.isKnownNonNull(); } LValue setKnownNonNull() { - IsKnownNonNull = true; + Addr.setKnownNonNull(); return *this; } // simple lvalue - llvm::Value *getPointer(CodeGenFunction &CGF) const { - assert(isSimple()); - return Addr.getBasePointer(); - } - llvm::Value *emitRawPointer(CodeGenFunction &CGF) const { - assert(isSimple()); - return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr; - } + llvm::Value *getPointer(CodeGenFunction &CGF) const; + llvm::Value *emitResignedPointer(QualType PointeeTy, + CodeGenFunction &CGF) const; + llvm::Value *emitRawPointer(CodeGenFunction &CGF) const; Address getAddress() const { return Addr; } void setAddress(Address address) { Addr = address; } + CGPointerAuthInfo getPointerAuthInfo() const { + return Addr.getPointerAuthInfo(); + } + // vector elt lvalue Address getVectorAddress() const { assert(isVectorElt()); diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index ea4635c039cb2..551db09165dbe 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -195,34 +195,46 @@ CodeGenFunction::CGFPOptionsRAII::~CGFPOptionsRAII() { CGF.Builder.setDefaultConstrainedRounding(OldRounding); } -static LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T, - bool ForPointeeType, - CodeGenFunction &CGF) { +static LValue +makeNaturalAlignAddrLValue(llvm::Value *V, QualType T, bool ForPointeeType, + bool MightBeSigned, CodeGenFunction &CGF, + KnownNonNull_t IsKnownNonNull = NotKnownNonNull) { LValueBaseInfo BaseInfo; TBAAAccessInfo TBAAInfo; CharUnits Alignment = CGF.CGM.getNaturalTypeAlignment(T, &BaseInfo, &TBAAInfo, ForPointeeType); - Address Addr = Address(V, CGF.ConvertTypeForMem(T), Alignment); + Address Addr = + MightBeSigned + ? CGF.makeNaturalAddressForPointer(V, T, Alignment, false, nullptr, + nullptr, IsKnownNonNull) + : Address(V, CGF.ConvertTypeForMem(T), Alignment, IsKnownNonNull); return CGF.MakeAddrLValue(Addr, T, BaseInfo, TBAAInfo); } -LValue CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T) { - return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false, *this); +LValue +CodeGenFunction::MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T, + KnownNonNull_t IsKnownNonNull) { + return ::makeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false, + /*MightBeSigned*/ true, *this, + IsKnownNonNull); } LValue CodeGenFunction::MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T) { - return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true, *this); + return ::makeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true, + /*MightBeSigned*/ true, *this); } LValue CodeGenFunction::MakeNaturalAlignRawAddrLValue(llvm::Value *V, QualType T) { - return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false, *this); + return ::makeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ false, + /*MightBeSigned*/ false, *this); } LValue CodeGenFunction::MakeNaturalAlignPointeeRawAddrLValue(llvm::Value *V, QualType T) { - return ::MakeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true, *this); + return ::makeNaturalAlignAddrLValue(V, T, /*ForPointeeType*/ true, + /*MightBeSigned*/ false, *this); } llvm::Type *CodeGenFunction::ConvertTypeForMem(QualType T) { diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 9fe4391237819..d83e38cab8e2d 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -202,7 +202,7 @@ template <> struct DominatingValue<Address> { } static type restore(CodeGenFunction &CGF, saved_type value) { return Address(DominatingLLVMValue::restore(CGF, value.BasePtr), - value.ElementType, value.Alignment, + value.ElementType, value.Alignment, CGPointerAuthInfo(), DominatingLLVMValue::restore(CGF, value.Offset)); } }; @@ -2689,7 +2689,8 @@ class CodeGenFunction : public CodeGenTypeCache { if (Alignment.isZero()) Alignment = CGM.getNaturalTypeAlignment(T, BaseInfo, TBAAInfo, ForPointeeType); - return Address(Ptr, ConvertTypeForMem(T), Alignment, nullptr, + return Address(Ptr, ConvertTypeForMem(T), Alignment, + CGM.getPointerAuthInfoForPointeeType(T), /*Offset=*/nullptr, IsKnownNonNull); } @@ -2730,7 +2731,9 @@ class CodeGenFunction : public CodeGenTypeCache { /// an l-value with the natural pointee alignment of T. LValue MakeNaturalAlignPointeeAddrLValue(llvm::Value *V, QualType T); - LValue MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T); + LValue + MakeNaturalAlignAddrLValue(llvm::Value *V, QualType T, + KnownNonNull_t IsKnownNonNull = NotKnownNonNull); /// Same as MakeNaturalAlignPointeeAddrLValue except that the pointer is known /// to be unsigned. @@ -4424,10 +4427,6 @@ class CodeGenFunction : public CodeGenTypeCache { CXXDtorType Type, const CXXRecordDecl *RD); - llvm::Value *getAsNaturalPointerTo(Address Addr, QualType PointeeType) { - return Addr.getBasePointer(); - } - bool isPointerKnownNonNull(const Expr *E); /// Create the discriminator from the storage address and the entity hash. @@ -4437,16 +4436,36 @@ class CodeGenFunction : public CodeGenTypeCache { llvm::Value *StorageAddress, GlobalDecl SchemaDecl, QualType SchemaType); - llvm::Value *EmitPointerAuthSign(QualType PointeeType, llvm::Value *Pointer); + llvm::Value *EmitPointerAuthSign(const CGPointerAuthInfo &Info, llvm::Value *Pointer); + llvm::Value *EmitPointerAuthAuth(const CGPointerAuthInfo &Info, llvm::Value *Pointer); + llvm::Value *emitPointerAuthResign(llvm::Value *Pointer, QualType PointerType, + const CGPointerAuthInfo &CurAuthInfo, + const CGPointerAuthInfo &NewAuthInfo, + bool IsKnownNonNull); + llvm::Value *emitPointerAuthResignCall(llvm::Value *Pointer, + const CGPointerAuthInfo &CurInfo, + const CGPointerAuthInfo &NewInfo); + void EmitPointerAuthOperandBundle( const CGPointerAuthInfo &Info, SmallVectorImpl<llvm::OperandBundleDef> &Bundles); + llvm::Value *authPointerToPointerCast(llvm::Value *ResultPtr, + QualType SourceType, QualType DestType); + Address authPointerToPointerCast(Address Ptr, QualType SourceType, + QualType DestType); + + Address getAsNaturalAddressOf(Address Addr, QualType PointeeTy); + + llvm::Value *getAsNaturalPointerTo(Address Addr, QualType PointeeType) { + return getAsNaturalAddressOf(Addr, PointeeType).getBasePointer(); + } + // Return the copy constructor name with the prefix "__copy_constructor_" // removed. static std::string getNonTrivialCopyConstructorStr(QualType QT, diff --git a/clang/lib/Headers/ptrauth.h b/clang/lib/Headers/ptrauth.h index 40ac6dcac2ab8..e0bc8c4f9acf7 100644 --- a/clang/lib/Headers/ptrauth.h +++ b/clang/lib/Headers/ptrauth.h @@ -58,6 +58,21 @@ typedef __UINTPTR_TYPE__ ptrauth_generic_signature_t; /* Authenticating a pointer that was not signed with the given key and extra-data value will (likely) fail by trapping. */ +/* The null function pointer is always the all-zero bit pattern. + Signing an all-zero bit pattern will embed a (likely) non-zero + signature in the result, and so the result will not seem to be + a null function pointer. Authenticating this value will yield + a null function pointer back. However, authenticating an + all-zero bit pattern will probably fail, because the + authentication will expect a (likely) non-zero signature to + embedded in the value. + + Because of this, if a pointer may validly be null, you should + check for null before attempting to authenticate it with one + of these intrinsics. This is not necessary when using the + __ptrauth qualifier; the compiler will perform this check + automatically. */ + #if __has_feature(ptrauth_intrinsics) /* Strip the signature from a value without authenticating it. diff --git a/clang/test/CodeGen/ptrauth-function-lvalue-cast-disc.c b/clang/test/CodeGen/ptrauth-function-lvalue-cast-disc.c new file mode 100644 index 0000000000000..7d76649e2e49c --- /dev/null +++ b/clang/test/CodeGen/ptrauth-function-lvalue-cast-disc.c @@ -0,0 +1,68 @@ +// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- -fptrauth-function-pointer-type-discrimination | FileCheck -check-prefixes CHECK,TYPE %s +// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -emit-llvm -o- | FileCheck -check-prefixes CHECK,ZERO %s + +typedef void (*fptr_t)(void); + +char *cptr; +void (*fptr)(void); + +// CHECK-LABEL: define void @test1 +void test1() { + // TYPE: [[LOAD:%.*]] = load ptr, ptr @cptr + // TYPE: [[TOINT:%.*]] = ptrtoint ptr [[LOAD]] to i64 + // TYPE: call i64 @llvm.ptrauth.resign(i64 [[TOINT]], i32 0, i64 0, i32 0, i64 18983) + // TYPE: call void {{.*}}() [ "ptrauth"(i32 0, i64 18983) ] + // ZERO-NOT: @llvm.ptrauth.resign + + (*(fptr_t)cptr)(); +} + +// CHECK-LABEL: define i8 @test2 +char test2() { + return *(char *)fptr; + + // TYPE: [[LOAD:%.*]] = load ptr, ptr @fptr + // TYPE: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null + // TYPE-NEXT: br i1 [[CMP]], label %[[NONNULL:.*]], label %[[CONT:.*]] + + // TYPE: [[NONNULL]]: + // TYPE: [[TOINT:%.*]] = ptrtoint ptr [[LOAD]] to i64 + // TYPE: [[CALL:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[TOINT]], i32 0, i64 18983, i32 0, i64 0) + // TYPE: [[TOPTR:%.*]] = inttoptr i64 [[CALL]] to ptr + + // TYPE: [[CONT]]: + // TYPE: phi ptr [ null, {{.*}} ], [ [[TOPTR]], %[[NONNULL]] ] + // ZERO-NOT: @llvm.ptrauth.resign +} + +// CHECK-LABEL: define void @test4 +void test4() { + (*((fptr_t)(&*((char *)(&*(fptr_t)cptr)))))(); + + // CHECK: [[LOAD:%.*]] = load ptr, ptr @cptr + // TYPE-NEXT: [[CAST4:%.*]] = ptrtoint ptr [[LOAD]] to i64 + // TYPE-NEXT: [[RESIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[CAST4]], i32 0, i64 0, i32 0, i64 18983) + // TYPE-NEXT: [[CAST5:%.*]] = inttoptr i64 [[RESIGN]] to ptr + // TYPE-NEXT: call void [[CAST5]]() [ "ptrauth"(i32 0, i64 18983) ] + // ZERO-NOT: @llvm.ptrauth.resign + // ZERO: call void [[LOAD]]() [ "ptrauth"(i32 0, i64 0) ] +} + +void *vptr; +// CHECK-LABEL: define void @test5 +void test5() { + vptr = &*(char *)fptr; + + // TYPE: [[LOAD:%.*]] = load ptr, ptr @fptr + // TYPE-NEXT: [[CMP]] = icmp ne ptr [[LOAD]], null + // TYPE-NEXT: br i1 [[CMP]], label %[[NONNULL:.*]], label %[[CONT:.*]] + + // TYPE: [[NONNULL]]: + // TYPE: [[RESIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 {{.*}}, i32 0, i64 18983, i32 0, i64 0) + // TYPE: [[CAST:%.*]] = inttoptr i64 [[RESIGN]] to ptr + + // TYPE: [[CONT]]: + // TYPE: [[PHI:%.*]] = phi ptr [ null, {{.*}} ], [ [[CAST]], %[[NONNULL]] ] + // TYPE: store ptr [[PHI]], ptr @vptr + // ZERO-NOT: @llvm.ptrauth.resign +} diff --git a/clang/test/CodeGen/ptrauth-function-type-discriminator-cast.c b/clang/test/CodeGen/ptrauth-function-type-discriminator-cast.c new file mode 100644 index 0000000000000..cdf9ee4907525 --- /dev/null +++ b/clang/test/CodeGen/ptrauth-function-type-discriminator-cast.c @@ -0,0 +1,94 @@ +// RUN: %clang_cc1 %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,TYPE +// RUN: %clang_cc1 %s -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,ZERO +// RUN: %clang_cc1 -xc++ %s -fptrauth-function-pointer-type-discrimination -triple arm64e-apple-ios13 -fptrauth-calls -fptrauth-intrinsics -disable-llvm-passes -emit-llvm -o- | FileCheck %s --check-prefixes=CHECK,CHECKCXX,TYPE,TYPECXX + +#ifdef __cplusplus +extern "C" { +#endif + +void f(void); +void f2(int); +void (*fptr)(void); +void *opaque; +unsigned long uintptr; + +#ifdef __cplusplus +struct ptr_member { + void (*fptr_)(int) = 0; +}; +ptr_member pm; +void (*test_member)() = (void (*)())pm.fptr_; + +// CHECKCXX-LABEL: define internal void @__cxx_global_var_init +// TYPECXX: call i64 @llvm.ptrauth.resign(i64 {{.*}}, i32 0, i64 2712, i32 0, i64 18983) +#endif + + +// CHECK-LABEL: define void @test_cast_to_opaque +void test_cast_to_opaque() { + opaque = (void *)f; + + // TYPE: [[RESIGN_VAL:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @f, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 0, i64 0) + // TYPE: [[RESIGN_PTR:%.*]] = inttoptr i64 [[RESIGN_VAL]] to ptr + // ZERO-NOT: @llvm.ptrauth.resign +} + +// CHECK-LABEL: define void @test_cast_from_opaque +void test_cast_from_opaque() { + fptr = (void (*)(void))opaque; + + // TYPE: [[LOAD:%.*]] = load ptr, ptr @opaque + // TYPE: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null + // TYPE: br i1 [[CMP]], label %[[RESIGN_LAB:.*]], label + + // TYPE: [[RESIGN_LAB]]: + // TYPE: [[INT:%.*]] = ptrtoint ptr [[LOAD]] to i64 + // TYPE: [[RESIGN_INT:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[INT]], i32 0, i64 0, i32 0, i64 18983) + + // ZERO-NOT: @llvm.ptrauth.resign +} + +// CHECK-LABEL: define void @test_cast_to_intptr +void test_cast_to_intptr() { + uintptr = (unsigned long)fptr; + + // TYPE: [[ENTRY:.*]]: + // TYPE: [[LOAD:%.*]] = load ptr, ptr @fptr + // TYPE: [[CMP:%.*]] = icmp ne ptr [[LOAD]], null + // TYPE: br i1 [[CMP]], label %[[RESIGN_LAB:.*]], label %[[RESIGN_CONT:.*]] + + // TYPE: [[RESIGN_LAB]]: + // TYPE: [[INT:%.*]] = ptrtoint ptr [[LOAD]] to i64 + // TYPE: [[RESIGN_INT:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[INT]], i32 0, i64 18983, i32 0, i64 0) + // TYPE: [[RESIGN:%.*]] = inttoptr i64 [[RESIGN_INT]] to ptr + // TYPE: br label %[[RESIGN_CONT]] + + // TYPE: [[RESIGN_CONT]]: + // TYPE: phi ptr [ null, %[[ENTRY]] ], [ [[RESIGN]], %[[RESIGN_LAB]] ] + + // ZERO-NOT: @llvm.ptrauth.resign +} + +// CHECK-LABEL: define void @test_function_to_function_cast +void test_function_to_function_cast() { + void (*fptr2)(int) = (void (*)(int))fptr; + // TYPE: call i64 @llvm.ptrauth.resign(i64 {{.*}}, i32 0, i64 18983, i32 0, i64 2712) + // ZERO-NOT: @llvm.ptrauth.resign +} + +// CHECK-LABEL: define void @test_call_lvalue_cast +void test_call_lvalue_cast() { + (*(void (*)(int))f)(42); + + // TYPE: entry: + // TYPE-NEXT: [[RESIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 ptrtoint (ptr ptrauth (ptr @f, i32 0, i64 18983) to i64), i32 0, i64 18983, i32 0, i64 2712) + // TYPE-NEXT: [[RESIGN_INT:%.*]] = inttoptr i64 [[RESIGN]] to ptr + // TYPE-NEXT: call void [[RESIGN_INT]](i32 noundef 42) [ "ptrauth"(i32 0, i64 2712) ] + // ZERO-NOT: @llvm.ptrauth.resign + // ZERO: call void ptrauth (ptr @f, i32 0)(i32 noundef 42) [ "ptrauth"(i32 0, i64 0) ] +} + + +#ifdef __cplusplus +} +#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits