diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index dd023efc7d776..c714fecdf2a02 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -109,6 +109,9 @@ struct PointerAuthOptions : clang::PointerAuthOptions { /// Swift value witness functions. PointerAuthSchema ValueWitnesses; + /// Pointers to Swift value witness tables stored in type metadata. + PointerAuthSchema ValueWitnessTable; + /// Swift protocol witness functions. PointerAuthSchema ProtocolWitnesses; diff --git a/include/swift/Remote/MetadataReader.h b/include/swift/Remote/MetadataReader.h index 4ea21610e5818..65573ad290622 100644 --- a/include/swift/Remote/MetadataReader.h +++ b/include/swift/Remote/MetadataReader.h @@ -699,10 +699,11 @@ class MetadataReader { // pointer's referenced address. TargetValueWitnessTable VWT; auto ValueWitnessTableAddrAddr = MetadataAddress - sizeof(StoredPointer); - StoredPointer ValueWitnessTableAddr; + StoredSignedPointer SignedValueWitnessTableAddr; if (!Reader->readInteger(RemoteAddress(ValueWitnessTableAddrAddr), - &ValueWitnessTableAddr)) + &SignedValueWitnessTableAddr)) return std::nullopt; + auto ValueWitnessTableAddr = stripSignedPointer(SignedValueWitnessTableAddr); if (!Reader->readBytes(RemoteAddress(ValueWitnessTableAddr), (uint8_t *)&VWT, sizeof(VWT))) return std::nullopt; diff --git a/lib/IRGen/GenMeta.cpp b/lib/IRGen/GenMeta.cpp index 6dc3d0aba3d19..a73f1cfa3943e 100644 --- a/lib/IRGen/GenMeta.cpp +++ b/lib/IRGen/GenMeta.cpp @@ -37,6 +37,7 @@ #include "swift/Strings.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/Basic/TargetInfo.h" #include "llvm/ADT/SmallString.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/IR/Function.h" @@ -4036,7 +4037,14 @@ namespace { void addValueWitnessTable() { assert(!isPureObjC()); - B.add(asImpl().getValueWitnessTable(false).getValue()); + + auto wtable = asImpl().getValueWitnessTable(false).getValue(); + if (!isa(wtable)) { + auto schema = IGM.getOptions().PointerAuth.ValueWitnessTable; + B.addSignedPointer(wtable, schema, PointerAuthEntity()); + } else { + B.add(wtable); + } } llvm::Constant *getAddrOfMetaclassObject(ForDefinition_t forDefinition) { @@ -5411,9 +5419,26 @@ emitInvariantLoadFromMetadataAtIndex(IRGenFunction &IGF, /// Given a type metadata pointer, load its value witness table. llvm::Value * IRGenFunction::emitValueWitnessTableRefForMetadata(llvm::Value *metadata) { - auto witness = emitInvariantLoadFromMetadataAtIndex(*this, metadata, nullptr, - -1, IGM.WitnessTablePtrTy, - ".valueWitnesses"); + llvm::Value *addrOfWitnessTablePtr = nullptr; + llvm::LoadInst *loadOfWitnessTablePtr = emitInvariantLoadFromMetadataAtIndex( + *this, metadata, &addrOfWitnessTablePtr, -1, IGM.WitnessTablePtrTy, + ".valueWitnesses"); + + const auto &ptrAuthOpts = IGM.getOptions().PointerAuth; + if (auto schema = IGM.getOptions().PointerAuth.ValueWitnessTable) { + llvm::Value *signedWitnessTablePtr = loadOfWitnessTablePtr; + llvm::Value *witnessTablePtr = emitPointerAuthAuth( + *this, signedWitnessTablePtr, + PointerAuthInfo::emit(*this, schema, addrOfWitnessTablePtr, + PointerAuthEntity())); + + // TODO: We might be able to flag witnessTablePtr as dereferencable (see + // below) by adding an attribute (not setting the metadata). However, it + // is unclear if there are any benefits to be had at the cost of + // changing the APIs in multiple places. + return witnessTablePtr; + } + // A value witness table is dereferenceable to the number of value witness // pointers. @@ -5421,9 +5446,9 @@ IRGenFunction::emitValueWitnessTableRefForMetadata(llvm::Value *metadata) { // there are more witnesses. auto numValueWitnesses = unsigned(ValueWitness::Last_RequiredValueWitness) + 1; - setDereferenceableLoad(witness, + setDereferenceableLoad(loadOfWitnessTablePtr, IGM.getPointerSize().getValue() * numValueWitnesses); - return witness; + return loadOfWitnessTablePtr; } /// Given a lowered SIL type, load a value witness table that represents its @@ -5570,7 +5595,10 @@ namespace { } void addValueWitnessTable() { - B.add(asImpl().getValueWitnessTable(false).getValue()); + auto vwtPointer = asImpl().getValueWitnessTable(false).getValue(); + B.addSignedPointer(vwtPointer, + IGM.getOptions().PointerAuth.ValueWitnessTable, + PointerAuthEntity()); } llvm::Constant *emitLayoutString() { @@ -6051,7 +6079,11 @@ namespace { } void addValueWitnessTable() { - B.add(asImpl().getValueWitnessTable(false).getValue()); + auto vwtPointer = + asImpl().getValueWitnessTable(/*relative*/ false).getValue(); + B.addSignedPointer(vwtPointer, + IGM.getOptions().PointerAuth.ValueWitnessTable, + PointerAuthEntity()); } llvm::Constant *emitNominalTypeDescriptor() { @@ -6533,7 +6565,9 @@ namespace { ? IGM.Context.getAnyObjectType() : IGM.Context.TheNativeObjectType); auto wtable = IGM.getAddrOfValueWitnessTable(type); - B.add(wtable); + B.addSignedPointer(wtable, + IGM.getOptions().PointerAuth.ValueWitnessTable, + PointerAuthEntity()); } void addMetadataFlags() { @@ -6604,7 +6638,11 @@ namespace { void addValueWitnessTable() { auto type = getTargetType()->getCanonicalType(); - B.add(irgen::emitValueWitnessTable(IGM, type, false, false).getValue()); + auto vwtPointer = + irgen::emitValueWitnessTable(IGM, type, false, false).getValue(); + B.addSignedPointer(vwtPointer, + IGM.getOptions().PointerAuth.ValueWitnessTable, + PointerAuthEntity()); } void addMetadataFlags() { @@ -6643,7 +6681,10 @@ namespace { } void addValueWitnessTable() { - B.add(emitValueWitnessTable(/*relative*/ false).getValue()); + auto vwtPointer = emitValueWitnessTable(/*relative*/ false).getValue(); + B.addSignedPointer(vwtPointer, + IGM.getOptions().PointerAuth.ValueWitnessTable, + PointerAuthEntity()); } void flagUnfilledFieldOffset() { @@ -6670,7 +6711,10 @@ namespace { } void addValueWitnessTable() { - B.add(emitValueWitnessTable(/*relative*/ false).getValue()); + auto vwtPointer = emitValueWitnessTable(/*relative*/ false).getValue(); + B.addSignedPointer(vwtPointer, + IGM.getOptions().PointerAuth.ValueWitnessTable, + PointerAuthEntity()); } void addPayloadSize() const { diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index 118a634d01509..2d4954cfd3b33 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -727,6 +727,9 @@ static void setPointerAuthOptions(PointerAuthOptions &opts, PointerAuthSchema(codeKey, /*address*/ true, Discrimination::Decl); opts.ValueWitnesses = PointerAuthSchema(codeKey, /*address*/ true, Discrimination::Decl); + opts.ValueWitnessTable = + PointerAuthSchema(dataKey, /*address*/ true, Discrimination::Constant, + SpecialPointerAuthDiscriminators::ValueWitnessTable); opts.ProtocolWitnesses = PointerAuthSchema(codeKey, /*address*/ true, Discrimination::Decl); opts.ProtocolAssociatedTypeAccessFunctions = diff --git a/test/IRGen/ptrauth-value-witnesses.sil b/test/IRGen/ptrauth-value-witnesses.sil index ad42999e3f34f..bf77f1996a342 100644 --- a/test/IRGen/ptrauth-value-witnesses.sil +++ b/test/IRGen/ptrauth-value-witnesses.sil @@ -7,6 +7,9 @@ import Builtin struct S { var a, b, c: Builtin.NativeObject } + +// Check the constant discriminators for all value witnesses. + // CHECK: @"$s4test1SVwCP.ptrauth" = private constant {{.*}} i64 55882 // CHECK: @"$s4test1SVwxx.ptrauth" = private constant {{.*}} i64 1272 // CHECK: @"$s4test1SVwcp.ptrauth" = private constant {{.*}} i64 58298 @@ -16,6 +19,11 @@ struct S { var a, b, c: Builtin.NativeObject } // CHECK: @"$s4test1SVwet.ptrauth" = private constant {{.*}} i64 24816 // CHECK: @"$s4test1SVwst.ptrauth" = private constant {{.*}} i64 41169 +// The pointer to the value witness table is signed too. + +// 0x2e3f == 11839 is the constant discriminator for value witness tables. +// CHECK: @"$s4test1SVWV.ptrauth" = private constant {{.*}} i64 11839 + sil @test_destroy : $@convention(thin) (@in T) -> () { bb0(%0 : $*T): destroy_addr %0 : $*T @@ -23,8 +31,14 @@ bb0(%0 : $*T): return %result : $() } // CHECK-LABEL: define swiftcc void @test_destroy( -// CHECK: [[VWT:%.*]] = load ptr, -// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 +// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1 +// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839) +// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]] +// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]]) +// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]] +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align // CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64 // CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 1272) @@ -38,8 +52,14 @@ bb0(%0 : $*T, %1 : $*T): return %result : $() } // CHECK-LABEL: define swiftcc void @test_copy_init( -// CHECK: [[VWT:%.*]] = load ptr, -// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 +// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1 +// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839) +// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]] +// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]]) +// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]] +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align // CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64 // CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 58298) @@ -53,8 +73,14 @@ bb0(%0 : $*T, %1 : $*T): return %result : $() } // CHECK-LABEL: define swiftcc void @test_take_init( -// CHECK: [[VWT:%.*]] = load ptr, -// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 +// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1 +// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839) +// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]] +// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]]) +// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]] +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align // CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64 // CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 18648) @@ -68,8 +94,14 @@ bb0(%0 : $*T, %1 : $*T): return %result : $() } // CHECK-LABEL: define swiftcc void @test_copy_assign( -// CHECK: [[VWT:%.*]] = load ptr, -// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 +// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1 +// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839) +// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]] +// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]]) +// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]] +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align // CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64 // CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 34641) @@ -83,8 +115,14 @@ bb0(%0 : $*T, %1 : $*T): return %result : $() } // CHECK-LABEL: define swiftcc void @test_take_assign( -// CHECK: [[VWT:%.*]] = load ptr, -// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 +// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1 +// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839) +// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]] +// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]]) +// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]] +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align // CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64 // CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 61402) @@ -100,8 +138,14 @@ bb0(%0 : $*T, %1 : $*T): return %result : $() } // CHECK-LABEL: define swiftcc void @test_destroy_twice( -// CHECK: [[VWT:%.*]] = load ptr, -// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[VWT]], i32 +// CHECK: [[SIGNED_VWT_ADDR:%.*]] = getelementptr inbounds ptr, ptr {{%.*}}, i64 -1 +// CHECK: [[SIGNED_VWT:%.*]] = load ptr, ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[SIGNED_VWT_ADDR_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT_ADDR]] +// CHECK: [[BLENDED_ADDR:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[SIGNED_VWT_ADDR_INT]], i64 11839) +// CHECK: [[SIGNED_VWT_INT:%.*]] = ptrtoint ptr [[SIGNED_VWT]] +// CHECK: [[AUTHENTICATED_VWT_INT:%.*]] = call i64 @llvm.ptrauth.auth(i64 [[SIGNED_VWT_INT]], i32 2, i64 [[BLENDED_ADDR]]) +// CHECK: [[AUTHENTICATED_VWT:%.*]] = inttoptr i64 [[AUTHENTICATED_VWT_INT]] +// CHECK-NEXT: [[SLOT:%.*]] = getelementptr inbounds ptr, ptr [[AUTHENTICATED_VWT]], i32 // CHECK-NEXT: [[T0:%.*]] = load ptr, ptr [[SLOT]], align // CHECK-NEXT: [[T1:%.*]] = ptrtoint ptr [[SLOT]] to i64 // CHECK-NEXT: [[DISC:%.*]] = call i64 @llvm.ptrauth.blend(i64 [[T1]], i64 1272)