From 2701a0809b919e84e5b5d1a10ed61934465bf95c Mon Sep 17 00:00:00 2001 From: Nate Chandler Date: Thu, 9 Jul 2020 09:50:00 -0700 Subject: [PATCH] [metadata prespecialization] Ptrauth for compared protocol conformances. Two protocol conformance descriptors are passed to swift_compareProtocolConformanceDecriptors from generic metadata accessors when there is a canonical prespecialization and one of the generic arguments has a protocol requirement. Previously, the descriptors were incorrectly being passed without ptrauth processing: one from the witness table in the arguments that are passed in to the accessor and one known statically. Here, the descriptor in the witness table is authed using the ProtocolConformanceDescriptor schema. Then, both descriptors are signed using the ProtocolConformanceDescriptorsAsArguments schema. Finally, in the runtime function, the descriptors are authed. --- include/swift/ABI/MetadataValues.h | 3 +++ include/swift/AST/IRGenOptions.h | 6 ++++++ lib/IRGen/GenPointerAuth.cpp | 3 +++ lib/IRGen/GenPointerAuth.h | 2 ++ lib/IRGen/IRGen.cpp | 5 +++++ lib/IRGen/MetadataRequest.cpp | 28 +++++++++++++++++++++++++++- stdlib/public/runtime/Metadata.cpp | 5 +++++ 7 files changed, 51 insertions(+), 1 deletion(-) diff --git a/include/swift/ABI/MetadataValues.h b/include/swift/ABI/MetadataValues.h index 31b60023e1938..6ab98e9e37e56 100644 --- a/include/swift/ABI/MetadataValues.h +++ b/include/swift/ABI/MetadataValues.h @@ -1118,6 +1118,9 @@ namespace SpecialPointerAuthDiscriminators { /// Runtime function variables exported by the runtime. const uint16_t RuntimeFunctionEntry = 0x625b; + /// Protocol conformance descriptors. + const uint16_t ProtocolConformanceDescriptor = 0xc6eb; + /// Value witness functions. const uint16_t InitializeBufferWithCopyOfBuffer = 0xda4a; const uint16_t Destroy = 0x04f8; diff --git a/include/swift/AST/IRGenOptions.h b/include/swift/AST/IRGenOptions.h index 9b55d54d28d6a..9f70678ca6e05 100644 --- a/include/swift/AST/IRGenOptions.h +++ b/include/swift/AST/IRGenOptions.h @@ -117,6 +117,12 @@ struct PointerAuthOptions : clang::PointerAuthOptions { /// Type descriptor data pointers when passed as arguments. PointerAuthSchema TypeDescriptorsAsArguments; + /// Protocol conformance descriptors. + PointerAuthSchema ProtocolConformanceDescriptors; + + /// Protocol conformance descriptors when passed as arguments. + PointerAuthSchema ProtocolConformanceDescriptorsAsArguments; + /// Resumption functions from yield-once coroutines. PointerAuthSchema YieldOnceResumeFunctions; diff --git a/lib/IRGen/GenPointerAuth.cpp b/lib/IRGen/GenPointerAuth.cpp index 10edd40a0dea2..fa6821b267900 100644 --- a/lib/IRGen/GenPointerAuth.cpp +++ b/lib/IRGen/GenPointerAuth.cpp @@ -309,6 +309,9 @@ PointerAuthEntity::getDeclDiscriminator(IRGenModule &IGM) const { case Special::TypeDescriptor: case Special::TypeDescriptorAsArgument: return SpecialPointerAuthDiscriminators::TypeDescriptor; + case Special::ProtocolConformanceDescriptor: + case Special::ProtocolConformanceDescriptorAsArgument: + return SpecialPointerAuthDiscriminators::ProtocolConformanceDescriptor; case Special::PartialApplyCapture: return PointerAuthDiscriminator_PartialApplyCapture; case Special::KeyPathDestroy: diff --git a/lib/IRGen/GenPointerAuth.h b/lib/IRGen/GenPointerAuth.h index c30e4daf50668..8640f68cbf30f 100644 --- a/lib/IRGen/GenPointerAuth.h +++ b/lib/IRGen/GenPointerAuth.h @@ -62,6 +62,8 @@ class PointerAuthEntity { KeyPathInitializer, KeyPathMetadataAccessor, DynamicReplacementKey, + ProtocolConformanceDescriptor, + ProtocolConformanceDescriptorAsArgument, }; private: diff --git a/lib/IRGen/IRGen.cpp b/lib/IRGen/IRGen.cpp index ca88f2efaccff..a0c233979069f 100644 --- a/lib/IRGen/IRGen.cpp +++ b/lib/IRGen/IRGen.cpp @@ -651,6 +651,11 @@ static void setPointerAuthOptions(PointerAuthOptions &opts, opts.SwiftDynamicReplacementKeys = PointerAuthSchema(dataKey, /*address*/ true, Discrimination::Decl); + opts.ProtocolConformanceDescriptors = + PointerAuthSchema(dataKey, /*address*/ true, Discrimination::Decl); + opts.ProtocolConformanceDescriptorsAsArguments = + PointerAuthSchema(dataKey, /*address*/ false, Discrimination::Decl); + // Coroutine resumption functions are never stored globally in the ABI, // so we can do some things that aren't normally okay to do. However, // we can't use ASIB because that would break ARM64 interoperation. diff --git a/lib/IRGen/MetadataRequest.cpp b/lib/IRGen/MetadataRequest.cpp index e69c72d0914ac..ebb2f45913961 100644 --- a/lib/IRGen/MetadataRequest.cpp +++ b/lib/IRGen/MetadataRequest.cpp @@ -1970,7 +1970,7 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( } else { RootProtocolConformance *rootConformance = concreteConformance->getRootConformance(); - auto *expectedDescriptor = + llvm::Value *expectedDescriptor = IGF.IGM.getAddrOfProtocolConformanceDescriptor(rootConformance); auto *witnessTable = valueAtIndex(requirementIndex); auto *witnessBuffer = @@ -1981,6 +1981,32 @@ static void emitCanonicalSpecializationsForGenericTypeMetadataAccessFunction( uncastProvidedDescriptor, IGM.ProtocolConformanceDescriptorPtrTy); + // Auth the stored descriptor. + auto storedScheme = + IGF.IGM.getOptions().PointerAuth.ProtocolConformanceDescriptors; + if (storedScheme) { + auto authInfo = PointerAuthInfo::emit( + IGF, storedScheme, witnessTable, + PointerAuthEntity::Special::ProtocolConformanceDescriptor); + providedDescriptor = + emitPointerAuthAuth(IGF, providedDescriptor, authInfo); + } + + // Sign the descriptors. + auto argScheme = + IGF.IGM.getOptions() + .PointerAuth.ProtocolConformanceDescriptorsAsArguments; + if (argScheme) { + auto authInfo = PointerAuthInfo::emit( + IGF, argScheme, nullptr, + PointerAuthEntity::Special:: + ProtocolConformanceDescriptorAsArgument); + expectedDescriptor = + emitPointerAuthSign(IGF, expectedDescriptor, authInfo); + providedDescriptor = + emitPointerAuthSign(IGF, providedDescriptor, authInfo); + } + auto *call = IGF.Builder.CreateCall( IGF.IGM.getCompareProtocolConformanceDescriptorsFn(), {providedDescriptor, expectedDescriptor}); diff --git a/stdlib/public/runtime/Metadata.cpp b/stdlib/public/runtime/Metadata.cpp index 5703748dfc182..18dc96a828c6e 100644 --- a/stdlib/public/runtime/Metadata.cpp +++ b/stdlib/public/runtime/Metadata.cpp @@ -4996,6 +4996,11 @@ const WitnessTable *swift::swift_getAssociatedConformanceWitness( bool swift::swift_compareProtocolConformanceDescriptors( const ProtocolConformanceDescriptor *lhs, const ProtocolConformanceDescriptor *rhs) { + lhs = swift_auth_data_non_address( + lhs, SpecialPointerAuthDiscriminators::ProtocolConformanceDescriptor); + rhs = swift_auth_data_non_address( + rhs, SpecialPointerAuthDiscriminators::ProtocolConformanceDescriptor); + return MetadataCacheKey::compareProtocolConformanceDescriptors(lhs, rhs) == 0; }