From b6a30059db8319348ebb454cc303633dfabd6a29 Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Mon, 8 Aug 2016 18:30:44 +0200 Subject: [PATCH] [bcl] Update Reference Source to .NET Framework 4.6.2 --- .../ReferenceSources/PoolBlockingPeriod.cs | 9 + mcs/class/System.Data/ReferenceSources/Res.cs | 7 + .../mobile_System.Data.dll.sources | 1 + .../net_4_x_System.Data.dll.sources | 1 + .../ReferenceSources/SRef.cs | 31 - .../System.Runtime.Caching.dll.sources | 2 +- .../LocalAppContextSwitches.cs | 7 + .../System.Runtime.Serialization.dll.sources | 1 + mcs/class/System.Web/System.Web.dll.sources | 1 + .../LocalAppContextSwitches.cs | 9 +- .../XmlSerializationWriterTests.cs | 18 +- .../LocalAppContextSwitches.cs | 7 + .../ReferenceSources/SSPISafeHandles.cs | 1 + .../System/System.Net/ServicePointManager.cs | 4 + mcs/class/System/System.dll.sources | 1 + mcs/class/System/mobile_System.dll.sources | 1 + .../ReferenceSources/AppContextSwitches.cs | 3 +- .../corlib/ReferenceSources/PathInternal.cs | 10 + .../CryptoConfig.cs | 1 + .../RSACryptoServiceProvider.cs | 48 +- .../SignatureDescriptionTest.cs | 8 +- .../corlib/Test/System/BitConverterTest.cs | 2 +- mcs/class/corlib/corlib.dll.sources | 2 + .../FlowchartConnectionPointsAdorner.cs | 6 +- .../Presentation/Xaml/ViewStateXamlHelper.cs | 120 ++- .../Activities/Hosting/WorkflowInstance.cs | 14 + .../System/Activities/WorkflowApplication.cs | 2 +- .../LocalAppContextSwitches.cs | 2 + .../RegularExpressionAttribute.cs | 20 +- .../Clr/inc/AppContextDefaultValues.cs | 11 + .../InternalApis/Clr/inc/LocalAppContext.cs | 10 + .../System/Configuration/ClientConfigPaths.cs | 15 +- .../Win32/SafeHandles/CapiSafeHandles.cs | 32 +- .../Security/Cryptography/BCryptNative.cs | 33 + .../Security/Cryptography/CapiNative.cs | 10 + .../Cryptography/CapiSymmetricAlgorithm.cs | 3 + .../Security/Cryptography/ECDiffieHellman.cs | 97 ++- .../Cryptography/ECDiffieHellmanCng.cs | 111 ++- .../Cryptography/ECDiffieHellmanPublicKey.cs | 6 +- .../System/Security/Cryptography/ECDsaCng.cs | 57 +- .../Security/Cryptography/NCryptNative.cs | 57 +- .../System/Security/Cryptography/RsaCng.cs | 42 +- .../RSACertificateExtensions.cs | 8 +- .../Data/Common/Utils/MetadataHelper.cs | 2 + .../EntityModel/SchemaObjectModel/Schema.cs | 1 + .../Xml/Xsl/IlGen/XmlILOptimizerVisitor.cs | 4 +- .../Data/Common/DbConnectionStringCommon.cs | 139 ++++ .../System.Data/System/Data/DataSet.cs | 32 +- .../System.Data/System/Data/DataTable.cs | 21 +- .../Data/ProviderBase/DbConnectionPool.cs | 84 ++- .../Data/SqlClient/SqlClientSymmetricKey.cs | 34 +- .../System/Data/SqlClient/SqlCommand.cs | 683 +++++++++++++----- .../System/Data/SqlClient/SqlConnection.cs | 56 +- .../Data/SqlClient/SqlConnectionString.cs | 30 + .../SqlClient/SqlConnectionStringBuilder.cs | 38 + .../SqlConnectionTimeoutErrorInternal.cs | 16 +- .../SqlClient/SqlInternalConnectionTds.cs | 1 + .../System/Data/SqlClient/SqlParameter.cs | 3 - .../Data/SqlClient/SqlSymmetricKeyCache.cs | 21 +- .../System/Data/SqlClient/SqlUtil.cs | 2 +- .../System/Data/SqlClient/TdsEnums.cs | 3 + .../System/NewXml/XPathNodePointer.cs | 1 - .../Clr/inc/AppContextDefaultValues.cs | 11 + .../InternalApis/Clr/inc/LocalAppContext.cs | 10 + .../Claims/X509CertificateClaimSet.cs | 192 +++-- .../IdentityModel/LocalAppContextSwitches.cs | 15 + .../Tokens/X509AsymmetricSecurityKey.cs | 64 +- .../System/Caching/CacheMemoryMonitor.cs | 10 +- .../System/Caching/MemoryCache.cs | 48 +- .../System/Caching/MemoryCacheStatistics.cs | 21 +- .../System/Caching/SRef.cs | 85 +++ .../Runtime/Serialization/DataContract.cs | 90 ++- .../Serialization/Json/JsonWriterDelegator.cs | 20 +- .../Runtime/Serialization/SchemaExporter.cs | 2 +- .../Runtime/Serialization/SchemaImporter.cs | 2 +- .../Activation/HostedAspNetEnvironment.cs | 13 +- .../Runtime/Diagnostics/EtwDiagnosticTrace.cs | 1 + .../Clr/inc/AppContextDefaultValues.cs | 11 + .../InternalApis/Clr/inc/LocalAppContext.cs | 10 + .../AppContextDefaultValues.Default.cs | 5 + .../Channels/HttpChannelListener.cs | 8 +- .../ServiceModel/Channels/PipeConnection.cs | 35 +- .../Channels/TransportDefaults.cs | 4 +- .../Channels/UnsafeNativeMethods.cs | 81 ++- .../ServiceModel/Channels/WebSocketHelper.cs | 2 + .../ServiceModel/Configuration/Properties.cs | 4 +- .../Description/MessageContractExporter.cs | 19 +- .../ServiceModel/Description/WsdlHelper.cs | 5 +- .../ServiceModel/Dispatcher/QueryMatcher.cs | 2 + .../Dispatcher/TaskMethodInvoker.cs | 313 ++++---- .../XmlSerializerOperationFormatter.cs | 2 +- .../System/ServiceModel/EndpointAddress10.cs | 2 +- .../ServiceModel/EndpointAddressAugust2004.cs | 2 +- .../ServiceModel/LocalAppContextSwitches.cs | 21 + .../System/ServiceModel/OperationContext.cs | 39 +- .../ServiceModel/OperationContextScope.cs | 15 +- .../ServiceModel/Security/CryptoHelper.cs | 3 + .../ServiceModel/Security/SecurityUtils.cs | 87 ++- .../Security/TlsSspiNegotiation.cs | 9 +- .../Tokens/IssuedSecurityTokenProvider.cs | 2 +- .../ServiceModel/Security/WSSecurityPolicy.cs | 2 +- .../System/ServiceModel/Security/WSTrust.cs | 2 +- .../Security/WSTrustServiceContract.cs | 3 +- .../System/ServiceModel/ServiceHost.cs | 5 +- .../ServiceModel/ServiceModelAppSettings.cs | 18 + .../System.ServiceModel/System/UriTemplate.cs | 24 +- .../DynamicData/DynamicValidator.cs | 3 +- .../DynamicData/FieldTemplateUserControl.cs | 6 +- .../DynamicData/MetaColumn.cs | 11 +- .../WCFModel/DataSvcMapFileLoader.cs | 2 + .../Compilation/WCFModel/MetadataFile.cs | 3 + .../Compilation/WCFModel/SvcMapFileLoader.cs | 2 + .../Adapters/ChtmlCalendarAdapter.cs | 2 +- .../Adapters/WmlCalendarAdapter.cs | 2 +- .../System.Web/AspNetEventSource.cs | 8 + .../System.Web/Cache/CacheDependency.cs | 20 +- .../referencesource/System.Web/Cache/SRef.cs | 3 +- .../referencesource/System.Web/Cache/cache.cs | 84 ++- .../System.Web/Compilation/BuildManager.cs | 1 + .../Compilation/PreservationFileReader.cs | 1 + .../Compilation/XsdBuildProvider.cs | 1 + .../BrowserCapabilitiesCodeGenerator.cs | 3 + .../HttpCapabilitiesSectionHandler.cs | 3 +- .../RemoteWebConfigurationHostServer.cs | 2 + .../Handlers/TransferRequestHandler.cs | 36 +- .../System.Web/Hosting/ApplicationManager.cs | 24 +- .../System.Web/Hosting/HostingEnvironment.cs | 5 + .../System.Web/HttpApplication.cs | 32 +- .../System.Web/HttpCacheParams.cs | 25 +- .../System.Web/HttpCachePolicy.cs | 208 +++++- .../System.Web/HttpCacheVary.cs | 32 +- .../HttpCacheVaryByContentEncodings.cs | 25 +- .../referencesource/System.Web/HttpContext.cs | 19 +- .../System.Web/HttpResponse.cs | 13 +- .../DataAnnotationsModelMetadataProvider.cs | 14 +- .../DataAnnotationsModelValidator.cs | 53 +- .../DataAnnotationsModelValidatorProvider.cs | 15 +- .../ModelBinding/RangeAttributeAdapter.cs | 5 + .../RegularExpressionAttributeAdapter.cs | 4 + .../StringLengthAttributeAdapter.cs | 4 + .../Security/Cryptography/CryptoAlgorithms.cs | 1 + .../System.Web/Security/FormsIdentity.cs | 3 +- .../System.Web/State/SessionStateModule.cs | 15 +- .../System.Web/State/SessionStateUtil.cs | 18 + .../System.Web/TaskAsyncHelper.cs | 7 + .../System.Web/UI/PartialCachingControl.cs | 48 +- .../System.Web/UI/WebControls/Calendar.cs | 2 +- .../UI/WebControls/QueryExtensions.cs | 12 +- .../System.Web/UI/WebControls/xml.cs | 4 + .../referencesource/System.Web/Util/GCUtil.cs | 29 + .../System.Web/Util/StringUtil.cs | 2 + .../System.Web/Util/SynchronizationHelper.cs | 2 +- .../System.Web/Util/XmlUtils.cs | 13 + .../System.Web/XmlSiteMapProvider.cs | 1 + .../AuthoringOM/Compiler/CompileXomlTask.cs | 3 +- .../Design/ComponentSerializationService.cs | 4 +- .../System.Workflow.Runtime/Tracking.cs | 13 +- .../Tracking/TrackingProfileSerializer.cs | 3 +- .../WorkflowRuntime.cs | 11 + .../Clr/inc/AppContextDefaultValues.cs | 11 + .../InternalApis/Clr/inc/LocalAppContext.cs | 10 + .../Core/AppContextDefaultValues.Defaults.cs | 5 + .../Xml/Core/LocalAppContextSwitches.cs | 10 + .../Xml/Serialization/Xmlcustomformatter.cs | 18 +- .../Clr/inc/AppContextDefaultValues.cs | 11 + .../InternalApis/Clr/inc/LocalAppContext.cs | 10 + .../NDP_Common/inc/PinnableBufferCache.cs | 12 +- .../microsoft/win32/UnsafeNativeMethods.cs | 31 +- .../system/componentmodel/MemberDescriptor.cs | 16 +- .../net/System/Net/HttpListenerRequest.cs | 22 +- .../System/net/System/Net/Internal.cs | 1 + .../System/Net/SecureProtocols/_SslState.cs | 10 +- .../net/System/Net/ServicePointManager.cs | 154 ++-- .../net/System/Net/UnsafeNativeMethods.cs | 21 +- .../System/net/System/Net/_SecureChannel.cs | 19 +- .../io/system/io/FileSystemWatcher.cs | 3 - .../sys/AppContextDefaultValues.Defaults.cs | 7 +- .../System/sys/LocalAppContextSwitches.cs | 31 +- .../Tasks/Xaml/PartialClassGenerationTask.cs | 7 +- .../Build/Tasks/Xaml/XamlBuildTaskServices.cs | 6 + .../NDP_Common/inc/PinnableBufferCache.cs | 12 +- .../mscorlib/microsoft/win32/win32native.cs | 16 + .../mscorlib/system/AppContext/AppContext.cs | 10 +- .../AppContextDefaultValues.Defaults.cs | 17 +- .../AppContext/AppContextDefaultValues.cs | 11 + .../system/AppContext/AppContextSwitches.cs | 42 ++ .../mscorlib/system/AppDomainSetup.cs | 60 +- .../mscorlib/system/appdomain.cs | 55 +- .../mscorlib/system/bitconverter.cs | 2 +- .../mscorlib/system/deployment/cmsutils.cs | 14 +- .../eventing/TraceLogging/SimpleTypeInfos.cs | 9 + .../TraceLogging/TraceLoggingEventSource.cs | 9 +- .../TraceLoggingMetadataCollector.cs | 2 +- .../diagnostics/eventing/activitytracker.cs | 237 ++++-- .../diagnostics/eventing/eventprovider.cs | 2 +- .../diagnostics/eventing/eventsource.cs | 492 ++++++++++--- .../mscorlib/system/environment.cs | 2 +- .../system/globalization/taiwancalendar.cs | 2 +- .../mscorlib/system/io/__error.cs | 20 +- .../mscorlib/system/io/binaryreader.cs | 21 +- .../mscorlib/system/io/binarywriter.cs | 21 +- .../mscorlib/system/io/directory.cs | 121 +++- .../mscorlib/system/io/directoryinfo.cs | 16 +- .../mscorlib/system/io/file.cs | 21 +- .../mscorlib/system/io/fileinfo.cs | 8 +- .../mscorlib/system/io/filestream.cs | 46 +- .../system/io/filesystemenumerable.cs | 19 +- .../mscorlib/system/io/filesysteminfo.cs | 8 +- .../mscorlib/system/io/longpath.cs | 57 +- .../mscorlib/system/io/path.cs | 318 +++++--- .../system/resources/resourcereader.cs | 17 +- .../windowsruntime/nativemethods.cs | 7 + .../security/accesscontrol/filesecurity.cs | 47 +- .../system/security/claims/ClaimsIdentity.cs | 23 +- .../security/cryptography/cryptoconfig.cs | 55 +- .../system/security/cryptography/dsa.cs | 79 ++ .../cryptography/dsacryptoserviceprovider.cs | 30 + .../cryptography/rsacryptoserviceprovider.cs | 21 +- .../rsaoaepkeyexchangedeformatter.cs | 15 +- .../rsaoaepkeyexchangeformatter.cs | 15 +- .../rsapkcs1keyexchangedeformatter.cs | 15 +- .../rsapkcs1keyexchangeformatter.cs | 15 +- .../rsapkcs1signaturedeformatter.cs | 19 + .../rsapkcs1signatureformatter.cs | 19 + .../cryptography/signaturedescription.cs | 48 +- .../system/security/cryptography/utils.cs | 68 ++ .../x509certificates/x509utils.cs | 2 +- .../security/permissions/fileiopermission.cs | 576 +++++++++------ .../security/principal/windowsidentity.cs | 4 + .../security/util/stringexpressionset.cs | 52 +- .../system/security/util/urlstring.cs | 32 +- .../mscorlib/system/text/stringbuilder.cs | 5 +- .../mscorlib/system/threading/Tasks/Task.cs | 43 +- 233 files changed, 5656 insertions(+), 1819 deletions(-) create mode 100644 mcs/class/System.Data/ReferenceSources/PoolBlockingPeriod.cs delete mode 100644 mcs/class/System.Runtime.Caching/ReferenceSources/SRef.cs create mode 100644 mcs/class/System.Runtime.Serialization/ReferenceSources/LocalAppContextSwitches.cs create mode 100644 mcs/class/System/ReferenceSources/LocalAppContextSwitches.cs create mode 100644 mcs/class/corlib/ReferenceSources/PathInternal.cs diff --git a/mcs/class/System.Data/ReferenceSources/PoolBlockingPeriod.cs b/mcs/class/System.Data/ReferenceSources/PoolBlockingPeriod.cs new file mode 100644 index 00000000000..82231f413b5 --- /dev/null +++ b/mcs/class/System.Data/ReferenceSources/PoolBlockingPeriod.cs @@ -0,0 +1,9 @@ +namespace System.Data.SqlClient +{ + public enum PoolBlockingPeriod + { + Auto, + AlwaysBlock, + NeverBlock + } +} \ No newline at end of file diff --git a/mcs/class/System.Data/ReferenceSources/Res.cs b/mcs/class/System.Data/ReferenceSources/Res.cs index 1fce5dcce82..c103d0d1e3b 100644 --- a/mcs/class/System.Data/ReferenceSources/Res.cs +++ b/mcs/class/System.Data/ReferenceSources/Res.cs @@ -1265,6 +1265,13 @@ namespace System.Data { public const string SQLCR_UnrecoverableServer = "The connection is broken and recovery is not possible. The connection is marked by the server as unrecoverable. No attempt was made to restore the connection."; public const string SQLCR_UnrecoverableClient = "The connection is broken and recovery is not possible. The connection is marked by the client driver as unrecoverable. No attempt was made to restore the connection."; public const string SQLCR_NoCRAckAtReconnection = "The server did not acknowledge a recovery attempt, connection recovery is not possible."; + + public const string AZURESQL_GenericEndpoint = ".database.windows.net"; + public const string AZURESQL_GermanEndpoint = ".database.cloudapi.de"; + public const string AZURESQL_UsGovEndpoint = ".database.usgovcloudapi.net"; + public const string AZURESQL_ChinaEndpoint = ".database.chinacloudapi.cn"; + public const string DbConnectionString_PoolBlockingPeriod = "Defines the blocking period behavior for a connection pool."; + public const string SQL_Timeout_Execution = "Execution Timeout Expired. The timeout period elapsed prior to completion of the operation or the server is not responding."; } diff --git a/mcs/class/System.Data/mobile_System.Data.dll.sources b/mcs/class/System.Data/mobile_System.Data.dll.sources index a5b2a2f1492..eb7e02eb03c 100644 --- a/mcs/class/System.Data/mobile_System.Data.dll.sources +++ b/mcs/class/System.Data/mobile_System.Data.dll.sources @@ -6,6 +6,7 @@ Assembly/AssemblyInfo.cs ../../build/common/AssemblyRef.cs ReferenceSources/NativeOledbWrapper.cs +ReferenceSources/PoolBlockingPeriod.cs ReferenceSources/Res.cs ReferenceSources/Res.missing.cs ReferenceSources/ResCategoryAttribute.cs diff --git a/mcs/class/System.Data/net_4_x_System.Data.dll.sources b/mcs/class/System.Data/net_4_x_System.Data.dll.sources index 76b642b8849..c075e87489d 100644 --- a/mcs/class/System.Data/net_4_x_System.Data.dll.sources +++ b/mcs/class/System.Data/net_4_x_System.Data.dll.sources @@ -6,6 +6,7 @@ Assembly/AssemblyInfo.cs ../../build/common/AssemblyRef.cs ReferenceSources/NativeOledbWrapper.cs +ReferenceSources/PoolBlockingPeriod.cs ReferenceSources/Res.cs ReferenceSources/Res.missing.cs ReferenceSources/ResCategoryAttribute.cs diff --git a/mcs/class/System.Runtime.Caching/ReferenceSources/SRef.cs b/mcs/class/System.Runtime.Caching/ReferenceSources/SRef.cs deleted file mode 100644 index 644a2fc0b22..00000000000 --- a/mcs/class/System.Runtime.Caching/ReferenceSources/SRef.cs +++ /dev/null @@ -1,31 +0,0 @@ -using System; -using System.Runtime.InteropServices; - -namespace System.Runtime.Caching { - /* - * This class is used to retrieve the size of an object graph. - * Although Mono has not a way of computing this. - * Known problems: - * - CacheMemoryMonitor does not trim the cache when it reaches its memory size limit. - * - IMemoryCacheManager.UpdateCacheSize is called with incorrect size. - */ - internal class SRef { - -// private Object _sizedRef; - - internal SRef (Object target) { -// _sizedRef = target; - } - - internal long ApproximateSize { - get { - // TODO: .net uses System.SizedReference which contains approximate size after Gen 2 collection - return 16; - } - } - - internal void Dispose() { - - } - } -} \ No newline at end of file diff --git a/mcs/class/System.Runtime.Caching/System.Runtime.Caching.dll.sources b/mcs/class/System.Runtime.Caching/System.Runtime.Caching.dll.sources index c10ee4fb406..46aa74c47c0 100644 --- a/mcs/class/System.Runtime.Caching/System.Runtime.Caching.dll.sources +++ b/mcs/class/System.Runtime.Caching/System.Runtime.Caching.dll.sources @@ -8,7 +8,6 @@ ReferenceSources/CacheEntryCollection.cs ReferenceSources/CacheExpires.cs ReferenceSources/CacheUsage.cs ReferenceSources/R.Designer.cs -ReferenceSources/SRef.cs ../referencesource/System.Runtime.Caching/Resources/RH.cs ../referencesource/System.Runtime.Caching/System/Caching/CacheEntryChangeMonitor.cs ../referencesource/System.Runtime.Caching/System/Caching/CacheEntryRemovedArguments.cs @@ -51,3 +50,4 @@ ReferenceSources/SRef.cs ../referencesource/System.Runtime.Caching/System/Caching/SafeBitVector32.cs ../referencesource/System.Runtime.Caching/System/Caching/SafeRegistryHandle.cs ../referencesource/System.Runtime.Caching/System/Caching/SqlChangeMonitor.cs +../referencesource/System.Runtime.Caching/System/Caching/SRef.cs diff --git a/mcs/class/System.Runtime.Serialization/ReferenceSources/LocalAppContextSwitches.cs b/mcs/class/System.Runtime.Serialization/ReferenceSources/LocalAppContextSwitches.cs new file mode 100644 index 00000000000..ad8837615e7 --- /dev/null +++ b/mcs/class/System.Runtime.Serialization/ReferenceSources/LocalAppContextSwitches.cs @@ -0,0 +1,7 @@ +namespace System +{ + static class LocalAppContextSwitches + { + public static readonly bool DoNotUseTimeZoneInfo = false; + } +} \ No newline at end of file diff --git a/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization.dll.sources b/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization.dll.sources index 9e790d522b7..e889387651a 100644 --- a/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization.dll.sources +++ b/mcs/class/System.Runtime.Serialization/System.Runtime.Serialization.dll.sources @@ -4,6 +4,7 @@ Assembly/AssemblyInfo.cs ReferenceSources/DiagnosticUtility.cs ReferenceSources/FxTrace.cs +ReferenceSources/LocalAppContextSwitches.cs ReferenceSources/SR.cs ReferenceSources/SR.missing.cs ReferenceSources/XmlExceptionHelper.cs diff --git a/mcs/class/System.Web/System.Web.dll.sources b/mcs/class/System.Web/System.Web.dll.sources index 5f47d1326e0..248b80f3537 100644 --- a/mcs/class/System.Web/System.Web.dll.sources +++ b/mcs/class/System.Web/System.Web.dll.sources @@ -1400,6 +1400,7 @@ ReferenceSources/SR.cs ../referencesource/System.Web/Hosting/IProcessHostSupportFunctions.cs ../referencesource/System.Web/Hosting/HTTP_COOKED_URL.cs ../referencesource/System.Web/Hosting/HostingEnvironmentException.cs +../referencesource/System.Web/Util/Debug.cs ../referencesource/System.Web/Util/SynchronizationContextMode.cs ../referencesource/System.Web/Util/ISyncContextLock.cs ../referencesource/System.Web/Util/DoNotResetAttribute.cs diff --git a/mcs/class/System.XML/ReferenceSources/LocalAppContextSwitches.cs b/mcs/class/System.XML/ReferenceSources/LocalAppContextSwitches.cs index 9c961021fd6..bc03e96bbd8 100644 --- a/mcs/class/System.XML/ReferenceSources/LocalAppContextSwitches.cs +++ b/mcs/class/System.XML/ReferenceSources/LocalAppContextSwitches.cs @@ -1,7 +1,8 @@ namespace System { - static class LocalAppContextSwitches { - public const bool IgnoreEmptyKeySequences = false; - public const bool DontThrowOnInvalidSurrogatePairs = false; - } + static class LocalAppContextSwitches { + public static readonly bool IgnoreEmptyKeySequences = false; + public static readonly bool DontThrowOnInvalidSurrogatePairs = false; + public static readonly bool IgnoreKindInUtcTimeSerialization = false; + } } \ No newline at end of file diff --git a/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializationWriterTests.cs b/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializationWriterTests.cs index afa18715f26..4b81d7366ff 100644 --- a/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializationWriterTests.cs +++ b/mcs/class/System.XML/Test/System.Xml.Serialization/XmlSerializationWriterTests.cs @@ -1575,30 +1575,16 @@ namespace MonoTests.System.XmlSerialization ser.Serialize (sw, d); string str = sw.ToString (); - str = RemoveTZ (str, "MyTime"); - str = RemoveTZ (str, "MyTimeNullable"); - var expected = "" + Environment.NewLine + "" + Environment.NewLine + -" 10:00:00.0000000$TZ$" + Environment.NewLine + -" 10:00:00.0000000$TZ$" + Environment.NewLine + +" 10:00:00.0000000Z" + Environment.NewLine + +" 10:00:00.0000000Z" + Environment.NewLine + " 2012-01-03" + Environment.NewLine + " 2012-01-03" + Environment.NewLine + ""; Assert.AreEqual (expected, str); } - - static string RemoveTZ (string str, string tag) - { - var st = str.IndexOf ("<" + tag + ">"); - var et = str.IndexOf (""); - if (st < 0 || et < 0) - return str; - - var start = str.IndexOfAny (new [] { '+', '-' }, st, et - st); - return str.Substring (0, start) + "$TZ$" + str.Substring (et, str.Length - et); - } } } diff --git a/mcs/class/System/ReferenceSources/LocalAppContextSwitches.cs b/mcs/class/System/ReferenceSources/LocalAppContextSwitches.cs new file mode 100644 index 00000000000..5df7130bebb --- /dev/null +++ b/mcs/class/System/ReferenceSources/LocalAppContextSwitches.cs @@ -0,0 +1,7 @@ +namespace System +{ + static class LocalAppContextSwitches + { + public static readonly bool MemberDescriptorEqualsReturnsFalseIfEquivalent = false; + } +} \ No newline at end of file diff --git a/mcs/class/System/ReferenceSources/SSPISafeHandles.cs b/mcs/class/System/ReferenceSources/SSPISafeHandles.cs index b7c1da79538..a12e395cf6f 100644 --- a/mcs/class/System/ReferenceSources/SSPISafeHandles.cs +++ b/mcs/class/System/ReferenceSources/SSPISafeHandles.cs @@ -133,6 +133,7 @@ namespace System.Net.Security ValidateManual = 0x08, NoDefaultCred = 0x10, ValidateAuto = 0x20, + SendAuxRecord = 0x00200000, UseStrongCrypto = 0x00400000 } diff --git a/mcs/class/System/System.Net/ServicePointManager.cs b/mcs/class/System/System.Net/ServicePointManager.cs index 723125b1e75..32a0148b8ea 100644 --- a/mcs/class/System/System.Net/ServicePointManager.cs +++ b/mcs/class/System/System.Net/ServicePointManager.cs @@ -294,6 +294,10 @@ namespace System.Net get { return false; } } + internal static bool DisableSendAuxRecord { + get { return false; } + } + // Methods public static void SetTcpKeepAlive (bool enabled, int keepAliveTime, int keepAliveInterval) { diff --git a/mcs/class/System/System.dll.sources b/mcs/class/System/System.dll.sources index 4d802b3108d..542fa6411e0 100644 --- a/mcs/class/System/System.dll.sources +++ b/mcs/class/System/System.dll.sources @@ -562,6 +562,7 @@ ReferenceSources/EnvironmentHelpers.cs ReferenceSources/Internal.cs ReferenceSources/HttpApi.cs ReferenceSources/HttpSysSettings.cs +ReferenceSources/LocalAppContextSwitches.cs ReferenceSources/Logging.cs ReferenceSources/NativeMethods.cs ReferenceSources/RequestCacheProtocol.cs diff --git a/mcs/class/System/mobile_System.dll.sources b/mcs/class/System/mobile_System.dll.sources index 4bba90982fe..d0a70bbb58b 100644 --- a/mcs/class/System/mobile_System.dll.sources +++ b/mcs/class/System/mobile_System.dll.sources @@ -305,6 +305,7 @@ ReferenceSources/CAPI.cs ReferenceSources/EnvironmentHelpers.cs ReferenceSources/HttpApi.cs ReferenceSources/Internal.cs +ReferenceSources/LocalAppContextSwitches.cs ReferenceSources/HttpSysSettings.cs ReferenceSources/Logging.cs ReferenceSources/NativeMethods.cs diff --git a/mcs/class/corlib/ReferenceSources/AppContextSwitches.cs b/mcs/class/corlib/ReferenceSources/AppContextSwitches.cs index bf8c82427e5..55d45d833e3 100644 --- a/mcs/class/corlib/ReferenceSources/AppContextSwitches.cs +++ b/mcs/class/corlib/ReferenceSources/AppContextSwitches.cs @@ -1,5 +1,6 @@ namespace System { static class AppContextSwitches { - public const bool ThrowExceptionIfDisposedCancellationTokenSource = true; + public static readonly bool ThrowExceptionIfDisposedCancellationTokenSource = true; + public static readonly bool SetActorAsReferenceWhenCopyingClaimsIdentity = false; } } \ No newline at end of file diff --git a/mcs/class/corlib/ReferenceSources/PathInternal.cs b/mcs/class/corlib/ReferenceSources/PathInternal.cs new file mode 100644 index 00000000000..828a080bb4d --- /dev/null +++ b/mcs/class/corlib/ReferenceSources/PathInternal.cs @@ -0,0 +1,10 @@ +namespace System.IO +{ + static class PathInternal + { + public static bool IsPartiallyQualified (string path) + { + return false; + } + } +} \ No newline at end of file diff --git a/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs b/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs index 35a574660c9..369455581da 100644 --- a/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs +++ b/mcs/class/corlib/System.Security.Cryptography/CryptoConfig.cs @@ -421,6 +421,7 @@ public partial class CryptoConfig { oid.Add (managedSHA1, oidSHA1); oid.Add (nameSHA1b, oidSHA1); oid.Add (nameSHA1c, oidSHA1); + oid.Add (nameSHA1Cng, oidSHA1); oid.Add (nameMD5, oidMD5); oid.Add (nameMD5a, oidMD5); diff --git a/mcs/class/corlib/System.Security.Cryptography/RSACryptoServiceProvider.cs b/mcs/class/corlib/System.Security.Cryptography/RSACryptoServiceProvider.cs index 53667fb87df..a8ebc812da3 100644 --- a/mcs/class/corlib/System.Security.Cryptography/RSACryptoServiceProvider.cs +++ b/mcs/class/corlib/System.Security.Cryptography/RSACryptoServiceProvider.cs @@ -36,8 +36,7 @@ using Mono.Security.Cryptography; namespace System.Security.Cryptography { - [ComVisible (true)] - public sealed class RSACryptoServiceProvider : RSA, ICspAsymmetricAlgorithm { + public partial class RSACryptoServiceProvider { private const int PROV_RSA_FULL = 1; // from WinCrypt.h private const int AT_KEYEXCHANGE = 1; private const int AT_SIGNATURE = 2; @@ -102,7 +101,7 @@ namespace System.Security.Cryptography { // no need to load - it cannot exists var p = new CspParameters (PROV_RSA_FULL); - if (useMachineKeyStore) + if (UseMachineKeyStore) p.Flags |= CspProviderFlags.UseMachineKeyStore; store = new KeyPairPersistence (p); } @@ -121,13 +120,6 @@ namespace System.Security.Cryptography { FromXmlString (store.KeyValue); } } - - private static bool useMachineKeyStore; - - public static bool UseMachineKeyStore { - get { return useMachineKeyStore; } - set { useMachineKeyStore = value; } - } ~RSACryptoServiceProvider () { @@ -161,11 +153,7 @@ namespace System.Security.Cryptography { public bool PublicOnly { get { return rsa.PublicOnly; } } - - public override string SignatureAlgorithm { - get { return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; } - } - + public byte[] Decrypt (byte[] rgb, bool fOAEP) { if (rgb == null) @@ -339,6 +327,29 @@ namespace System.Security.Cryptography { return PKCS1.Sign_v15 (this, hash, rgbHash); } + byte[] SignHash(byte[] rgbHash, int calgHash) + { + return PKCS1.Sign_v15 (this, InternalHashToHashAlgorithm (calgHash), rgbHash); + } + + static HashAlgorithm InternalHashToHashAlgorithm (int calgHash) + { + switch (calgHash) { + case Constants.CALG_MD5: + return MD5.Create (); + case Constants.CALG_SHA1: + return SHA1.Create (); + case Constants.CALG_SHA_256: + return SHA256.Create (); + case Constants.CALG_SHA_384: + return SHA384.Create (); + case Constants.CALG_SHA_512: + return SHA512.Create (); + } + + throw new NotImplementedException (calgHash.ToString ()); + } + // NOTE: this method can work with ANY configured (OID in machine.config) // HashAlgorithm descendant public bool VerifyData (byte[] buffer, object halg, byte[] signature) @@ -364,6 +375,11 @@ namespace System.Security.Cryptography { HashAlgorithm hash = HashAlgorithm.Create (hashName); return PKCS1.Verify_v15 (this, hash, rgbHash, rgbSignature); } + + bool VerifyHash(byte[] rgbHash, int calgHash, byte[] rgbSignature) + { + return PKCS1.Verify_v15 (this, InternalHashToHashAlgorithm (calgHash), rgbHash, rgbSignature); + } protected override void Dispose (bool disposing) { @@ -444,7 +460,7 @@ namespace System.Security.Cryptography { var p = new CspParameters (PROV_RSA_FULL); p.KeyNumber = keyBlob [5] == 0x24 ? AT_SIGNATURE : AT_KEYEXCHANGE; - if (useMachineKeyStore) + if (UseMachineKeyStore) p.Flags |= CspProviderFlags.UseMachineKeyStore; store = new KeyPairPersistence (p); } diff --git a/mcs/class/corlib/Test/System.Security.Cryptography/SignatureDescriptionTest.cs b/mcs/class/corlib/Test/System.Security.Cryptography/SignatureDescriptionTest.cs index 38a4aa7fafc..c27a58f99cf 100644 --- a/mcs/class/corlib/Test/System.Security.Cryptography/SignatureDescriptionTest.cs +++ b/mcs/class/corlib/Test/System.Security.Cryptography/SignatureDescriptionTest.cs @@ -311,15 +311,15 @@ public class SignatureDescriptionTest { { // internal class - we cannot create one without CryptoConfig SignatureDescription sd = (SignatureDescription) CryptoConfig.CreateFromName ("http://www.w3.org/2000/09/xmldsig#rsa-sha1"); - Assert.AreEqual ("System.Security.Cryptography.SHA1CryptoServiceProvider", sd.DigestAlgorithm); + Assert.AreEqual ("System.Security.Cryptography.SHA1Cng", sd.DigestAlgorithm); Assert.AreEqual ("System.Security.Cryptography.RSAPKCS1SignatureDeformatter", sd.DeformatterAlgorithm); Assert.AreEqual ("System.Security.Cryptography.RSAPKCS1SignatureFormatter", sd.FormatterAlgorithm); - Assert.AreEqual ("System.Security.Cryptography.RSACryptoServiceProvider", sd.KeyAlgorithm); + Assert.AreEqual ("System.Security.Cryptography.RSA", sd.KeyAlgorithm); HashAlgorithm hash = sd.CreateDigest(); - Assert.AreEqual ("System.Security.Cryptography.SHA1CryptoServiceProvider", hash.ToString ()); + Assert.AreEqual ("System.Security.Cryptography.SHA1Cng", hash.ToString ()); - Assert.AreEqual (rsa.ToString (), sd.KeyAlgorithm); + Assert.AreEqual ("System.Security.Cryptography.RSA", sd.KeyAlgorithm); AsymmetricSignatureDeformatter asd = sd.CreateDeformatter (rsa); Assert.AreEqual ("System.Security.Cryptography.RSAPKCS1SignatureDeformatter", asd.ToString ()); diff --git a/mcs/class/corlib/Test/System/BitConverterTest.cs b/mcs/class/corlib/Test/System/BitConverterTest.cs index 75775d3aa76..b69d81d5358 100644 --- a/mcs/class/corlib/Test/System/BitConverterTest.cs +++ b/mcs/class/corlib/Test/System/BitConverterTest.cs @@ -790,7 +790,7 @@ namespace MonoTests.System Assert.IsNull (ex.InnerException, "#C3"); Assert.IsNotNull (ex.Message, "#C4"); Assert.IsNotNull (ex.ParamName, "#C5"); - Assert.AreEqual ("byteArray", ex.ParamName, "#C6"); + Assert.AreEqual ("value", ex.ParamName, "#C6"); } } diff --git a/mcs/class/corlib/corlib.dll.sources b/mcs/class/corlib/corlib.dll.sources index 6406b39c7da..9ef22797a96 100644 --- a/mcs/class/corlib/corlib.dll.sources +++ b/mcs/class/corlib/corlib.dll.sources @@ -900,6 +900,7 @@ ReferenceSources/TextInfo.cs ReferenceSources/win32native.cs ReferenceSources/SharedStatics.cs ReferenceSources/SecurityContext.cs +ReferenceSources/PathInternal.cs ../referencesource/mscorlib/system/__filters.cs ../referencesource/mscorlib/system/__hresults.cs @@ -1448,6 +1449,7 @@ ReferenceSources/SecurityContext.cs ../referencesource/mscorlib/system/security/cryptography/ripemd160.cs ../referencesource/mscorlib/system/security/cryptography/ripemd160managed.cs ../referencesource/mscorlib/system/security/cryptography/rsa.cs +../referencesource/mscorlib/system/security/cryptography/rsacryptoserviceprovider.cs ../referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangedeformatter.cs ../referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangeformatter.cs ../referencesource/mscorlib/system/security/cryptography/rsapkcs1keyexchangedeformatter.cs diff --git a/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/FlowchartConnectionPointsAdorner.cs b/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/FlowchartConnectionPointsAdorner.cs index d1b3abc1dae..2debe1f3578 100644 --- a/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/FlowchartConnectionPointsAdorner.cs +++ b/mcs/class/referencesource/System.Activities.Core.Presentation/System/Activities/Core/Presentation/FlowchartConnectionPointsAdorner.cs @@ -63,10 +63,11 @@ namespace System.Activities.Core.Presentation trueLabelText = (string)virtualizingContainer.ModelItem.Properties["TrueLabel"].ComputedValue; } + double pixelsPerDip = VisualTreeHelper.GetDpi(trueConnectionPoint).PixelsPerDip; actualPoint = new Point(trueConnectionPoint.Location.X - origin.X, trueConnectionPoint.Location.Y - origin.Y); FormattedText trueMarkerFormattedText = new FormattedText(trueLabelText, new System.Globalization.CultureInfo(textCulture), this.FlowDirection, FlowchartDesigner.FlowElementCaptionTypeface, FlowchartDesigner.FlowNodeCaptionFontSize, - new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor)); + new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor), pixelsPerDip); actualPoint.Y += ConnectionPoint.DrawingLargeSide / 2; actualPoint.X -= trueMarkerFormattedText.WidthIncludingTrailingWhitespace; @@ -94,9 +95,10 @@ namespace System.Activities.Core.Presentation actualPoint = new Point(falseConnectionPoint.Location.X - origin.X, falseConnectionPoint.Location.Y - origin.Y); actualPoint.Y += ConnectionPoint.DrawingLargeSide / 2; + double pixelsPerDip = VisualTreeHelper.GetDpi(falseConnectionPoint).PixelsPerDip; FormattedText falseMarkerFormattedText = new FormattedText(falseLabelText, new System.Globalization.CultureInfo(textCulture), this.FlowDirection, FlowchartDesigner.FlowElementCaptionTypeface, FlowchartDesigner.FlowNodeCaptionFontSize, - new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor)); + new SolidColorBrush(WorkflowDesignerColors.WorkflowViewElementCaptionColor), pixelsPerDip); DrawtWithTransform( drawingContext, diff --git a/mcs/class/referencesource/System.Activities.Presentation/Microsoft.Tools.Common/Microsoft/Activities/Presentation/Xaml/ViewStateXamlHelper.cs b/mcs/class/referencesource/System.Activities.Presentation/Microsoft.Tools.Common/Microsoft/Activities/Presentation/Xaml/ViewStateXamlHelper.cs index 08bf6c294fa..fb5266eb131 100644 --- a/mcs/class/referencesource/System.Activities.Presentation/Microsoft.Tools.Common/Microsoft/Activities/Presentation/Xaml/ViewStateXamlHelper.cs +++ b/mcs/class/referencesource/System.Activities.Presentation/Microsoft.Tools.Common/Microsoft/Activities/Presentation/Xaml/ViewStateXamlHelper.cs @@ -7,6 +7,7 @@ namespace Microsoft.Activities.Presentation.Xaml using System; using System.Activities; using System.Activities.Debugger; + using System.Activities.DynamicUpdate; using System.Activities.Presentation.View; using System.Activities.Presentation.ViewState; using System.Collections.Generic; @@ -30,6 +31,18 @@ namespace Microsoft.Activities.Presentation.Xaml XamlDebuggerXmlReader.EndColumnName.MemberName }; + // These are used to discover that we have found a DynamicUpdateInfo.OriginalDefintion or OriginalActivityBuilder + // attached property member. We have "hardcoded" the *MemberName" here because DynamicUpdateInfo has the + // AttachableMemberIdentifier properties marked as private. But the DynamicUpdateInfo class itself is public, + // as are the Get and Set methods. + static readonly string DynamicUpdateOriginalDefinitionMemberName = "OriginalDefinition"; + static readonly MethodInfo GetOriginalDefinition = typeof(DynamicUpdateInfo).GetMethod("GetOriginalDefinition"); + static readonly MethodInfo SetOriginalDefinition = typeof(DynamicUpdateInfo).GetMethod("SetOriginalDefinition"); + + static readonly string DynamicUpdateOriginalActivityBuilderMemberName = "OriginalActivityBuilder"; + static readonly MethodInfo GetOriginalActivityBuilder = typeof(DynamicUpdateInfo).GetMethod("GetOriginalActivityBuilder"); + static readonly MethodInfo SetOriginalActivityBuilder = typeof(DynamicUpdateInfo).GetMethod("SetOriginalActivityBuilder"); + // This method collects view state attached properties and generates a Xaml node stream // with all view state information appearing within the ViewStateManager node. // It is called when workflow definition is being serialized to string. @@ -279,6 +292,22 @@ namespace Microsoft.Activities.Presentation.Xaml // Xaml member definition for IdRef. Used to identify existing IdRef properties in the input nodestream. XamlMember idRefMember = new XamlMember(IdRef, GetIdRef, SetIdRef, inputReader.SchemaContext); + // These are used to ignore the IdRef members that are inside a DynamicUpdateInfo.OriginalDefinition/OriginalActivityBuilder attached property. + // We need to ignore these because if we don't, the IdRef values for the objects in the actual workflow defintion will be ignored because of the + // duplicate IdRef value. This causes problems with activity designers that depend on the ViewStateManager data to correctly display the workflow + // on the WorkflowDesigner canvas. + XamlMember originalDefinitionMember = new XamlMember(DynamicUpdateOriginalDefinitionMemberName, GetOriginalDefinition, SetOriginalDefinition, inputReader.SchemaContext); + XamlMember originalActivityBuilderMember = new XamlMember(DynamicUpdateOriginalActivityBuilderMemberName, GetOriginalActivityBuilder, SetOriginalActivityBuilder, inputReader.SchemaContext); + + // insideOriginalDefintion gets set to true when we find a "StartMember" node for either of the above two attached properties. + // originalDefintionMemberCount gets incremented if we find any "StartMember" and insideOriginalDefinition is true. + // originalDefintionMemberCount gets decremented if we find any "EndMember" and insideOriginalDefintion is true. + // insideOriginalDefintion gets set to false when we find an "EndMember" and originalDefinitionMemberCount gets decremented to 0. + // If insideOriginalDefintion is true when we find an "IdRef" member, we do NOT add that IdRef to the idRefsSeen HashSet to avoid + // duplicates being defined by the IdRefs inside of the OriginalDefinition attached properties. + bool insideOriginalDefinition = false; + int originalDefinitionMemberCount = 0; + // Dictionary containing Ids and corresponding viewstate related // attached property nodes. Populated by StripViewStateElement method. Dictionary viewStateInfo = null; @@ -323,9 +352,21 @@ namespace Microsoft.Activities.Presentation.Xaml break; case XamlNodeType.StartMember: + // If we find a StartMember for DynamicUpdateInfo.OriginalDefinition or OriginalActivityBuilder, remember that we are + // inside one of those. We don't want to "remember" IdRef values in the idRefsSeen HashSet while inside these attached properties. + if (workflowDefinition.Member.Equals(originalDefinitionMember) || workflowDefinition.Member.Equals(originalActivityBuilderMember)) + { + insideOriginalDefinition = true; + } + + if (insideOriginalDefinition) + { + originalDefinitionMemberCount++; + } + // Track when the reader enters IdRef. Skip writing the start // node to the output nodelist until we check for duplicates. - if (workflowDefinition.Member.Equals(idRefMember)) + else if (workflowDefinition.Member.Equals(idRefMember)) { inIdRefMember = true; skipWritingWorkflowDefinition = true; @@ -341,38 +382,43 @@ namespace Microsoft.Activities.Presentation.Xaml case XamlNodeType.Value: if (inIdRefMember) { - string idRef = workflowDefinition.Value as string; - if (!string.IsNullOrWhiteSpace(idRef)) + // We don't want to deal with the IdRef if we are inside a DynamicUpdateInfo.OriginalDefinition/OriginalActivityBuilder + // attached property. + if (!insideOriginalDefinition) { - // If IdRef value is a duplicate then do not associate it with - // the stack frame (top of stack == activity node with IdRef member on it). - if (idRefsSeen.Contains(idRef)) - { - stack.Peek().IdRef = null; - } - // If the IdRef value is unique then associate it with the - // stack frame and also write its value into the output nodestream. - else + string idRef = workflowDefinition.Value as string; + if (!string.IsNullOrWhiteSpace(idRef)) { - stack.Peek().IdRef = idRef; - idManager.UpdateMap(idRef); - idRefsSeen.Add(idRef); - - if (shouldPassLineInfo) + // If IdRef value is a duplicate then do not associate it with + // the stack frame (top of stack == activity node with IdRef member on it). + if (idRefsSeen.Contains(idRef)) { - lineInfoComsumer.SetLineInfo(idRefLineNumber, idRefLinePosition); + stack.Peek().IdRef = null; } + // If the IdRef value is unique then associate it with the + // stack frame and also write its value into the output nodestream. + else + { + stack.Peek().IdRef = idRef; + idManager.UpdateMap(idRef); + idRefsSeen.Add(idRef); - mergedNodeWriter.WriteStartMember(idRefMember); + if (shouldPassLineInfo) + { + lineInfoComsumer.SetLineInfo(idRefLineNumber, idRefLinePosition); + } - if (shouldPassLineInfo) - { - lineInfoComsumer.SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition); - } + mergedNodeWriter.WriteStartMember(idRefMember); - mergedNodeWriter.WriteValue(idRef); + if (shouldPassLineInfo) + { + lineInfoComsumer.SetLineInfo(lineInfo.LineNumber, lineInfo.LinePosition); + } - shouldWriteIdRefEndMember = true; + mergedNodeWriter.WriteValue(idRef); + + shouldWriteIdRefEndMember = true; + } } } // Don't need to write IdRef value into the output @@ -382,9 +428,21 @@ namespace Microsoft.Activities.Presentation.Xaml break; case XamlNodeType.EndMember: + // If we are inside an OriginalDefinition/OriginalActivityBuilder attached property, + // decrement the count and if it goes to zero, set insideOriginalDefintion to false + // because we just encountered the EndMember for it. + if (insideOriginalDefinition) + { + originalDefinitionMemberCount--; + if (originalDefinitionMemberCount == 0) + { + insideOriginalDefinition = false; + } + } + // Exit IdRef node. Skip writing the EndMember node, we would have done // it as part of reading the IdRef value. - if (inIdRefMember) + if (inIdRefMember && !insideOriginalDefinition) { inIdRefMember = false; skipWritingWorkflowDefinition = true; @@ -401,6 +459,7 @@ namespace Microsoft.Activities.Presentation.Xaml mergedNodeWriter.WriteEndMember(); } } + break; case XamlNodeType.EndObject: @@ -592,6 +651,7 @@ namespace Microsoft.Activities.Presentation.Xaml viewStateSourceLocationMap = null; XamlNodeList strippedNodeList = new XamlNodeList(inputReader.SchemaContext); XamlMember viewStateManager = new XamlMember(ViewStateManager, GetViewStateManager, SetViewStateManager, inputReader.SchemaContext); + using (XamlWriter strippedWriter = strippedNodeList.Writer) { IXamlLineInfo lineInfo = inputReader as IXamlLineInfo; @@ -618,7 +678,7 @@ namespace Microsoft.Activities.Presentation.Xaml return strippedNodeList.GetReader(); } - + // This method reads ViewStateManager nodes from the xaml nodestream and outputs that in the // viewStateInfo dictionary. The input reader is positioned on the ViewStateManagerNode in the nodestream. static void ReadViewStateInfo(XamlReader inputReader, out Dictionary viewStateInfo, out Dictionary viewStateSourceLocationMap) @@ -700,7 +760,11 @@ namespace Microsoft.Activities.Presentation.Xaml } } } - else if (globalMemberLevel == 1 && !IsAttachablePropertyForConvert(xamlReader)) + // The xamlReader.ReadSubtree and subsequent while loop to get the Id member + // has moved the xamlReader forward to the next member. We need to check to see + // if it is an Attached Property that we care about. If it isn't then we need to + // skip it and not put it in the resulting XamlNodeList. + if (globalMemberLevel == 1 && !IsAttachablePropertyForConvert(xamlReader)) { skippingUnexpectedAttachedProperty = true; } diff --git a/mcs/class/referencesource/System.Activities/System/Activities/Hosting/WorkflowInstance.cs b/mcs/class/referencesource/System.Activities/System/Activities/Hosting/WorkflowInstance.cs index 6b24f0ea522..c4cd899b81f 100644 --- a/mcs/class/referencesource/System.Activities/System/Activities/Hosting/WorkflowInstance.cs +++ b/mcs/class/referencesource/System.Activities/System/Activities/Hosting/WorkflowInstance.cs @@ -48,6 +48,20 @@ namespace System.Activities.Hosting StackTrace abortStack; #endif + static WorkflowInstance() + { + try + { + using (TelemetryEventSource eventSource = new TelemetryEventSource()) + { + eventSource.V2Runtime(); + } + } + catch + { + } + } + protected WorkflowInstance(Activity workflowDefinition) : this(workflowDefinition, null) { diff --git a/mcs/class/referencesource/System.Activities/System/Activities/WorkflowApplication.cs b/mcs/class/referencesource/System.Activities/System/Activities/WorkflowApplication.cs index 20900632507..ff9b74d7295 100644 --- a/mcs/class/referencesource/System.Activities/System/Activities/WorkflowApplication.cs +++ b/mcs/class/referencesource/System.Activities/System/Activities/WorkflowApplication.cs @@ -104,7 +104,7 @@ namespace System.Activities IList rootExecutionProperties; IDictionary instanceMetadata; - + public WorkflowApplication(Activity workflowDefinition) : this(workflowDefinition, (WorkflowIdentity)null) { diff --git a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/LocalAppContextSwitches.cs b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/LocalAppContextSwitches.cs index 20b80cfdeff..799f49541bb 100644 --- a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/LocalAppContextSwitches.cs +++ b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/LocalAppContextSwitches.cs @@ -21,8 +21,10 @@ namespace System.ComponentModel.DataAnnotations { } public static void SetDefaultsLessOrEqual_46() { +#pragma warning disable BCL0012 //disable warning about AppContextDefaults not following the recommended pattern // Define the switches that should be true for 4.6 or less, false for 4.6.1+. LocalAppContext.DefineSwitchDefault(UseLegacyRegExTimeoutString, true); +#pragma warning restore BCL0012 } } } diff --git a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/RegularExpressionAttribute.cs b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/RegularExpressionAttribute.cs index cd4ac2683ec..0b0f4b3047b 100644 --- a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/RegularExpressionAttribute.cs +++ b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/DataAnnotations/RegularExpressionAttribute.cs @@ -1,4 +1,4 @@ -using System.ComponentModel.DataAnnotations.Resources; +using System.ComponentModel.DataAnnotations.Resources; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text.RegularExpressions; @@ -19,7 +19,18 @@ namespace System.ComponentModel.DataAnnotations { /// Gets or sets the timeout to use when matching the regular expression pattern (in milliseconds) /// (-1 means never timeout). /// - public int MatchTimeoutInMilliseconds { get; set; } = GetDefaultTimeout(); + public int MatchTimeoutInMilliseconds { + get { + return _matchTimeoutInMilliseconds; + } + set { + _matchTimeoutInMilliseconds = value; + _matchTimeoutSet = true; + } + } + + private int _matchTimeoutInMilliseconds; + private bool _matchTimeoutSet; private Regex Regex { get; set; } @@ -90,6 +101,11 @@ namespace System.ComponentModel.DataAnnotations { if (string.IsNullOrEmpty(this.Pattern)) { throw new InvalidOperationException(DataAnnotationsResources.RegularExpressionAttribute_Empty_Pattern); } + + if (!_matchTimeoutSet) { + MatchTimeoutInMilliseconds = GetDefaultTimeout(); + } + Regex = MatchTimeoutInMilliseconds == -1 ? new Regex(Pattern) : Regex = new Regex(Pattern, default(RegexOptions), TimeSpan.FromMilliseconds((double)MatchTimeoutInMilliseconds)); diff --git a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/InternalApis/Clr/inc/AppContextDefaultValues.cs b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/InternalApis/Clr/inc/AppContextDefaultValues.cs index 8a130a0f342..9224bf8b8fb 100644 --- a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/InternalApis/Clr/inc/AppContextDefaultValues.cs +++ b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/InternalApis/Clr/inc/AppContextDefaultValues.cs @@ -3,6 +3,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== + +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + using System; using System.Collections.Generic; @@ -167,3 +176,5 @@ namespace System static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version); } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/InternalApis/Clr/inc/LocalAppContext.cs b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/InternalApis/Clr/inc/LocalAppContext.cs index f05b599ed3d..33662b54280 100644 --- a/mcs/class/referencesource/System.ComponentModel.DataAnnotations/InternalApis/Clr/inc/LocalAppContext.cs +++ b/mcs/class/referencesource/System.ComponentModel.DataAnnotations/InternalApis/Clr/inc/LocalAppContext.cs @@ -4,6 +4,14 @@ // // ==--== +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + // NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches using System; using System.Collections.Generic; @@ -126,3 +134,5 @@ namespace System } } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/System.Configuration/System/Configuration/ClientConfigPaths.cs b/mcs/class/referencesource/System.Configuration/System/Configuration/ClientConfigPaths.cs index 4e46c61716b..5ee50f1adcc 100644 --- a/mcs/class/referencesource/System.Configuration/System/Configuration/ClientConfigPaths.cs +++ b/mcs/class/referencesource/System.Configuration/System/Configuration/ClientConfigPaths.cs @@ -26,6 +26,8 @@ namespace System.Configuration { const string ClickOnceDataDirectory = "DataDirectory"; const string ConfigExtension = ".config"; const int MAX_PATH = 260; + const int MAX_UNICODESTRING_LEN = short.MaxValue; + const int ERROR_INSUFFICIENT_BUFFER = 122; //https://msdn.microsoft.com/en-us/library/windows/desktop/ms681382(v=vs.85).aspx const int MAX_LENGTH_TO_USE = 25; const string FILE_URI_LOCAL = "file:///"; const string FILE_URI_UNC = "file://"; @@ -108,7 +110,18 @@ namespace System.Configuration { } else { StringBuilder sb = new StringBuilder(MAX_PATH); - UnsafeNativeMethods.GetModuleFileName(new HandleRef(null, IntPtr.Zero), sb, sb.Capacity); + int noOfTimes = 1; + int length = 0; + // Iterating by allocating chunk of memory each time we find the length is not sufficient. + // Performance should not be an issue for current MAX_PATH length due to this change. + while (((length = UnsafeNativeMethods.GetModuleFileName(new HandleRef(null, IntPtr.Zero), sb, sb.Capacity)) == sb.Capacity) + && Marshal.GetLastWin32Error() == ERROR_INSUFFICIENT_BUFFER + && sb.Capacity < MAX_UNICODESTRING_LEN) { + noOfTimes += 2; // increasing buffer size by 520 in each iteration - perf. + int capacity = noOfTimes * MAX_PATH < MAX_UNICODESTRING_LEN ? noOfTimes * MAX_PATH : MAX_UNICODESTRING_LEN; + sb.EnsureCapacity(capacity); + } + sb.Length = length; applicationUri = Path.GetFullPath(sb.ToString()); applicationFilename = applicationUri; } diff --git a/mcs/class/referencesource/System.Core/Microsoft/Win32/SafeHandles/CapiSafeHandles.cs b/mcs/class/referencesource/System.Core/Microsoft/Win32/SafeHandles/CapiSafeHandles.cs index 16669900dca..acda796288c 100644 --- a/mcs/class/referencesource/System.Core/Microsoft/Win32/SafeHandles/CapiSafeHandles.cs +++ b/mcs/class/referencesource/System.Core/Microsoft/Win32/SafeHandles/CapiSafeHandles.cs @@ -186,6 +186,8 @@ namespace Microsoft.Win32.SafeHandles { #pragma warning restore 618 #endif internal sealed class SafeCapiHashHandle : SafeCapiHandleBase { + private static volatile SafeCapiHashHandle s_invalidHandle; + #if FEATURE_CORESYSTEM [System.Security.SecurityCritical] #endif @@ -197,9 +199,17 @@ namespace Microsoft.Win32.SafeHandles { /// public static SafeCapiHashHandle InvalidHandle { get { - SafeCapiHashHandle handle = new SafeCapiHashHandle(); - handle.SetHandle(IntPtr.Zero); - return handle; + if (s_invalidHandle == null) { + // More than one of these might get created in parallel, but that's okay. + // Saving one to the field saves on GC tracking, but by SuppressingFinalize on + // any instance returned there's already less finalization pressure. + SafeCapiHashHandle handle = new SafeCapiHashHandle(); + handle.SetHandle(IntPtr.Zero); + GC.SuppressFinalize(handle); + s_invalidHandle = handle; + } + + return s_invalidHandle; } } @@ -233,6 +243,8 @@ namespace Microsoft.Win32.SafeHandles { #pragma warning restore 618 #endif internal sealed class SafeCapiKeyHandle : SafeCapiHandleBase { + private static volatile SafeCapiKeyHandle s_invalidHandle; + #if FEATURE_CORESYSTEM [System.Security.SecurityCritical] #endif @@ -245,9 +257,17 @@ namespace Microsoft.Win32.SafeHandles { internal static SafeCapiKeyHandle InvalidHandle { [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")] get { - SafeCapiKeyHandle handle = new SafeCapiKeyHandle(); - handle.SetHandle(IntPtr.Zero); - return handle; + if (s_invalidHandle == null) { + // More than one of these might get created in parallel, but that's okay. + // Saving one to the field saves on GC tracking, but by SuppressingFinalize on + // any instance returned there's already less finalization pressure. + SafeCapiKeyHandle handle = new SafeCapiKeyHandle(); + handle.SetHandle(IntPtr.Zero); + GC.SuppressFinalize(handle); + s_invalidHandle = handle; + } + + return s_invalidHandle; } } diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/BCryptNative.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/BCryptNative.cs index b0586886a1b..f4d5ebecbcf 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/BCryptNative.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/BCryptNative.cs @@ -38,6 +38,35 @@ namespace System.Security.Cryptography { /// Pss = 8 // BCRYPT_PAD_PSS } +#if !MONO + [StructLayout(LayoutKind.Sequential)] + internal struct BCRYPT_DSA_KEY_BLOB_V2 + { + public BCryptNative.KeyBlobMagicNumber dwMagic; // BCRYPT_DSA_PUBLIC_MAGIC_V2 or BCRYPT_DSA_PRIVATE_MAGIC_V2 + public int cbKey; // key lengths in BYTES (e.g. for a 3072-bit key, cbKey = 3072/8 = 384) + public HASHALGORITHM_ENUM hashAlgorithm; + public DSAFIPSVERSION_ENUM standardVersion; + public int cbSeedLength; // size (in bytes) of the seed value + public int cbGroupSize; // size (in bytes) of the Q value + public byte Count3; // # of iterations used to generate Q. In big-endian format. + public byte Count2; + public byte Count1; + public byte Count0; + } +#endif + internal enum HASHALGORITHM_ENUM : int + { + DSA_HASH_ALGORITHM_SHA1 = 0, + DSA_HASH_ALGORITHM_SHA256 = 1, + DSA_HASH_ALGORITHM_SHA512 = 2, + } + + internal enum DSAFIPSVERSION_ENUM : int + { + DSA_FIPS186_2 = 0, + DSA_FIPS186_3 = 1, + } + /// /// Native interop with CNG's BCrypt layer. Native definitions can be found in bcrypt.h /// @@ -102,6 +131,10 @@ namespace System.Security.Cryptography { /// Magic numbers identifying blob types /// internal enum KeyBlobMagicNumber { + DsaPublic = 0x42505344, // BCRYPT_DSA_PUBLIC_MAGIC for key lengths <= 1024 bits + DsaPublicV2 = 0x32425044, // BCRYPT_DSA_PUBLIC_MAGIC_V2 for key lengths > 1024 bits + DsaPrivate = 0x56505344, // BCRYPT_DSA_PRIVATE_MAGIC for key lengths <= 1024 bits + DsaPrivateV2 = 0x32565044, // BCRYPT_DSA_PRIVATE_MAGIC_V2 for key lengths > 1024 bits ECDHPublicP256 = 0x314B4345, // BCRYPT_ECDH_PUBLIC_P256_MAGIC ECDHPublicP384 = 0x334B4345, // BCRYPT_ECDH_PUBLIC_P384_MAGIC ECDHPublicP521 = 0x354B4345, // BCRYPT_ECDH_PUBLIC_P521_MAGIC diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiNative.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiNative.cs index b9f7080affc..cbf1971793d 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiNative.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiNative.cs @@ -168,6 +168,14 @@ namespace System.Security.Cryptography { public IntPtr pbData; } + [StructLayout(LayoutKind.Sequential)] + internal struct CERT_DSS_PARAMETERS + { + public CRYPTOAPI_BLOB p; + public CRYPTOAPI_BLOB q; + public CRYPTOAPI_BLOB g; + } + [StructLayout(LayoutKind.Sequential)] internal unsafe struct PROV_ENUMALGS { public AlgorithmId aiAlgId; @@ -187,6 +195,8 @@ namespace System.Security.Cryptography { internal const uint CALG_DSS_SIGN = (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY); internal const uint CALG_RSA_KEYX = (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RSA | ALG_SID_RSA_ANY); internal const uint CNG_RSA_PUBLIC_KEY_BLOB = 72; + internal const uint X509_DSS_PUBLICKEY = 38; + internal const uint X509_DSS_PARAMETERS = 39; internal const uint X509_ASN_ENCODING = 0x00000001; internal const uint PKCS_7_ASN_ENCODING = 0x00010000; diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiSymmetricAlgorithm.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiSymmetricAlgorithm.cs index 490e61651f2..c1c5bdc3d7d 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiSymmetricAlgorithm.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/CapiSymmetricAlgorithm.cs @@ -447,6 +447,9 @@ namespace System.Security.Cryptography { buffer.Length); } else { + if (!LocalAppContextSwitches.AesCryptoServiceProviderDontCorrectlyResetDecryptor) { + resetSize = buffer.Length; + } CapiNative.UnsafeNativeMethods.CryptDecrypt(m_key, SafeCapiHashHandle.InvalidHandle, true, diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellman.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellman.cs index efb002c5814..39a279372b4 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellman.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellman.cs @@ -46,6 +46,101 @@ namespace System.Security.Cryptography { // public abstract ECDiffieHellmanPublicKey PublicKey { get; } - public abstract byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey); + + // This method must be implemented by derived classes. In order to conform to the contract, it cannot be abstract. + public virtual byte[] DeriveKeyMaterial(ECDiffieHellmanPublicKey otherPartyPublicKey) + { + throw DerivedClassMustOverride(); + } + + /// + /// Derive key material using the formula HASH(x) where x is the computed result of the EC Diffie-Hellman algorithm. + /// + /// The public key of the party with which to derive a mutual secret. + /// The identifier for the hash algorithm to use. + /// A hashed output suitable for key material + /// is over a different curve than this key + public byte[] DeriveKeyFromHash(ECDiffieHellmanPublicKey otherPartyPublicKey, HashAlgorithmName hashAlgorithm) + { + return DeriveKeyFromHash(otherPartyPublicKey, hashAlgorithm, null, null); + } + + /// + /// Derive key material using the formula HASH(secretPrepend || x || secretAppend) where x is the computed + /// result of the EC Diffie-Hellman algorithm. + /// + /// The public key of the party with which to derive a mutual secret. + /// The identifier for the hash algorithm to use. + /// A value to prepend to the derived secret before hashing. A null value is treated as an empty array. + /// A value to append to the derived secret before hashing. A null value is treated as an empty array. + /// A hashed output suitable for key material + /// is over a different curve than this key + public virtual byte[] DeriveKeyFromHash( + ECDiffieHellmanPublicKey otherPartyPublicKey, + HashAlgorithmName hashAlgorithm, + byte[] secretPrepend, + byte[] secretAppend) + { + throw DerivedClassMustOverride(); + } + + /// + /// Derive key material using the formula HMAC(hmacKey, x) where x is the computed + /// result of the EC Diffie-Hellman algorithm. + /// + /// The public key of the party with which to derive a mutual secret. + /// The identifier for the hash algorithm to use. + /// The key to use in the HMAC. A null value indicates that the result of the EC Diffie-Hellman algorithm should be used as the HMAC key. + /// A hashed output suitable for key material + /// is over a different curve than this key + public byte[] DeriveKeyFromHmac( + ECDiffieHellmanPublicKey otherPartyPublicKey, + HashAlgorithmName hashAlgorithm, + byte[] hmacKey) + { + return DeriveKeyFromHmac(otherPartyPublicKey, hashAlgorithm, hmacKey, null, null); + } + + /// + /// Derive key material using the formula HMAC(hmacKey, secretPrepend || x || secretAppend) where x is the computed + /// result of the EC Diffie-Hellman algorithm. + /// + /// The public key of the party with which to derive a mutual secret. + /// The identifier for the hash algorithm to use. + /// The key to use in the HMAC. A null value indicates that the result of the EC Diffie-Hellman algorithm should be used as the HMAC key. + /// A value to prepend to the derived secret before hashing. A null value is treated as an empty array. + /// A value to append to the derived secret before hashing. A null value is treated as an empty array. + /// A hashed output suitable for key material + /// is over a different curve than this key + public virtual byte[] DeriveKeyFromHmac( + ECDiffieHellmanPublicKey otherPartyPublicKey, + HashAlgorithmName hashAlgorithm, + byte[] hmacKey, + byte[] secretPrepend, + byte[] secretAppend) + { + throw DerivedClassMustOverride(); + } + + /// + /// Derive key material using the TLS pseudo-random function (PRF) derivation algorithm. + /// + /// The public key of the party with which to derive a mutual secret. + /// The ASCII encoded PRF label. + /// The 64-byte PRF seed. + /// A 48-byte output of the TLS pseudo-random function. + /// is over a different curve than this key + /// is null + /// is null + /// is not exactly 64 bytes in length + public virtual byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) + { + throw DerivedClassMustOverride(); + } + + private static Exception DerivedClassMustOverride() + { + return new NotImplementedException(SR.GetString(SR.NotSupported_SubclassOverride)); + } } } diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellmanCng.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellmanCng.cs index ada0c1ac58a..4a555dae543 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellmanCng.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellmanCng.cs @@ -93,7 +93,21 @@ namespace System.Security.Cryptography { } CodeAccessPermission.RevertAssert(); - KeySize = m_key.KeySize; + // Our LegalKeySizes value stores the values that we encoded as being the correct + // legal key size limitations for this algorithm, as documented on MSDN. + // + // But on a new OS version we might not question if our limit is accurate, or MSDN + // could have been innacurate to start with. + // + // Since the key is already loaded, we know that Windows thought it to be valid; + // therefore we should set KeySizeValue directly to bypass the LegalKeySizes conformance + // check. + // + // For RSA there are known cases where this change matters. RSACryptoServiceProvider can + // create a 384-bit RSA key, which we consider too small to be legal. It can also create + // a 1032-bit RSA key, which we consider illegal because it doesn't match our 64-bit + // alignment requirement. (In both cases Windows loads it just fine) + KeySizeValue = m_key.KeySize; } /// @@ -247,7 +261,22 @@ namespace System.Security.Cryptography { // m_key = value; - KeySize = m_key.KeySize; + + // Our LegalKeySizes value stores the values that we encoded as being the correct + // legal key size limitations for this algorithm, as documented on MSDN. + // + // But on a new OS version we might not question if our limit is accurate, or MSDN + // could have been innacurate to start with. + // + // Since the key is already loaded, we know that Windows thought it to be valid; + // therefore we should set KeySizeValue directly to bypass the LegalKeySizes conformance + // check. + // + // For RSA there are known cases where this change matters. RSACryptoServiceProvider can + // create a 384-bit RSA key, which we consider too small to be legal. It can also create + // a 1032-bit RSA key, which we consider illegal because it doesn't match our 64-bit + // alignment requirement. (In both cases Windows loads it just fine) + KeySizeValue = m_key.KeySize; } } @@ -369,6 +398,84 @@ namespace System.Security.Cryptography { } } + [SecuritySafeCritical] + public override byte[] DeriveKeyFromHash( + ECDiffieHellmanPublicKey otherPartyPublicKey, + HashAlgorithmName hashAlgorithm, + byte[] secretPrepend, + byte[] secretAppend) + { + Contract.Ensures(Contract.Result() != null); + + if (otherPartyPublicKey == null) + throw new ArgumentNullException("otherPartyPublicKey"); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw new ArgumentException(SR.GetString(SR.Cryptography_HashAlgorithmNameNullOrEmpty), "hashAlgorithm"); + + using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey)) + { + return NCryptNative.DeriveKeyMaterialHash( + secretAgreement, + hashAlgorithm.Name, + secretPrepend, + secretAppend, + NCryptNative.SecretAgreementFlags.None); + } + } + + [SecuritySafeCritical] + public override byte[] DeriveKeyFromHmac( + ECDiffieHellmanPublicKey otherPartyPublicKey, + HashAlgorithmName hashAlgorithm, + byte[] hmacKey, + byte[] secretPrepend, + byte[] secretAppend) + { + Contract.Ensures(Contract.Result() != null); + + if (otherPartyPublicKey == null) + throw new ArgumentNullException("otherPartyPublicKey"); + if (string.IsNullOrEmpty(hashAlgorithm.Name)) + throw new ArgumentException(SR.GetString(SR.Cryptography_HashAlgorithmNameNullOrEmpty), "hashAlgorithm"); + + using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey)) + { + NCryptNative.SecretAgreementFlags flags = hmacKey == null ? + NCryptNative.SecretAgreementFlags.UseSecretAsHmacKey : + NCryptNative.SecretAgreementFlags.None; + + return NCryptNative.DeriveKeyMaterialHmac( + secretAgreement, + hashAlgorithm.Name, + hmacKey, + secretPrepend, + secretAppend, + flags); + } + } + + [SecuritySafeCritical] + public override byte[] DeriveKeyTls(ECDiffieHellmanPublicKey otherPartyPublicKey, byte[] prfLabel, byte[] prfSeed) + { + Contract.Ensures(Contract.Result() != null); + + if (otherPartyPublicKey == null) + throw new ArgumentNullException("otherPartyPublicKey"); + if (prfLabel == null) + throw new ArgumentNullException("prfLabel"); + if (prfSeed == null) + throw new ArgumentNullException("prfSeed"); + + using (SafeNCryptSecretHandle secretAgreement = DeriveSecretAgreementHandle(otherPartyPublicKey)) + { + return NCryptNative.DeriveKeyMaterialTls( + secretAgreement, + prfLabel, + prfSeed, + NCryptNative.SecretAgreementFlags.None); + } + } + /// /// Get a handle to the secret agreement generated between two parties /// diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellmanPublicKey.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellmanPublicKey.cs index 3099a3a77e3..91e89d8be9c 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellmanPublicKey.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDiffieHellmanPublicKey.cs @@ -40,6 +40,10 @@ namespace System.Security.Cryptography { return m_keyBlob.Clone() as byte[]; } - public abstract string ToXmlString(); + // This method must be implemented by derived classes. In order to conform to the contract, it cannot be abstract. + public virtual string ToXmlString() + { + throw new NotImplementedException(SR.GetString(SR.NotSupported_SubclassOverride)); + } } } diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDsaCng.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDsaCng.cs index c1f169ead6a..1dcebb46d34 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDsaCng.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/ECDsaCng.cs @@ -54,12 +54,12 @@ namespace System.Security.Cryptography { [SecuritySafeCritical] public ECDsaCng(CngKey key) { Contract.Ensures(LegalKeySizesValue != null); - Contract.Ensures(m_key != null && m_key.AlgorithmGroup == CngAlgorithmGroup.ECDsa); + Contract.Ensures(m_key != null && IsEccAlgorithmGroup(m_key.AlgorithmGroup)); if (key == null) { throw new ArgumentNullException("key"); } - if (key.AlgorithmGroup != CngAlgorithmGroup.ECDsa) { + if (!IsEccAlgorithmGroup(key.AlgorithmGroup)) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDsaRequiresECDsaKey), "key"); } @@ -83,7 +83,21 @@ namespace System.Security.Cryptography { } CodeAccessPermission.RevertAssert(); - KeySize = m_key.KeySize; + // Our LegalKeySizes value stores the values that we encoded as being the correct + // legal key size limitations for this algorithm, as documented on MSDN. + // + // But on a new OS version we might not question if our limit is accurate, or MSDN + // could have been innacurate to start with. + // + // Since the key is already loaded, we know that Windows thought it to be valid; + // therefore we should set KeySizeValue directly to bypass the LegalKeySizes conformance + // check. + // + // For RSA there are known cases where this change matters. RSACryptoServiceProvider can + // create a 384-bit RSA key, which we consider too small to be legal. It can also create + // a 1032-bit RSA key, which we consider illegal because it doesn't match our 64-bit + // alignment requirement. (In both cases Windows loads it just fine) + KeySizeValue = m_key.KeySize; } /// @@ -112,8 +126,8 @@ namespace System.Security.Cryptography { public CngKey Key { get { Contract.Ensures(Contract.Result() != null); - Contract.Ensures(Contract.Result().AlgorithmGroup == CngAlgorithmGroup.ECDsa); - Contract.Ensures(m_key != null && m_key.AlgorithmGroup == CngAlgorithmGroup.ECDsa); + Contract.Ensures(IsEccAlgorithmGroup(Contract.Result().AlgorithmGroup)); + Contract.Ensures(m_key != null && IsEccAlgorithmGroup(m_key.AlgorithmGroup)); // If the size of the key no longer matches our stored value, then we need to replace it with // a new key of the correct size. @@ -151,9 +165,9 @@ namespace System.Security.Cryptography { private set { Contract.Requires(value != null); - Contract.Ensures(m_key != null && m_key.AlgorithmGroup == CngAlgorithmGroup.ECDsa); + Contract.Ensures(m_key != null && IsEccAlgorithmGroup(m_key.AlgorithmGroup)); - if (value.AlgorithmGroup != CngAlgorithmGroup.ECDsa) { + if (!IsEccAlgorithmGroup(value.AlgorithmGroup)) { throw new ArgumentException(SR.GetString(SR.Cryptography_ArgECDsaRequiresECDsaKey)); } @@ -168,7 +182,22 @@ namespace System.Security.Cryptography { // m_key = value; - KeySize = m_key.KeySize; + + // Our LegalKeySizes value stores the values that we encoded as being the correct + // legal key size limitations for this algorithm, as documented on MSDN. + // + // But on a new OS version we might not question if our limit is accurate, or MSDN + // could have been innacurate to start with. + // + // Since the key is already loaded, we know that Windows thought it to be valid; + // therefore we should set KeySizeValue directly to bypass the LegalKeySizes conformance + // check. + // + // For RSA there are known cases where this change matters. RSACryptoServiceProvider can + // create a 384-bit RSA key, which we consider too small to be legal. It can also create + // a 1032-bit RSA key, which we consider illegal because it doesn't match our 64-bit + // alignment requirement. (In both cases Windows loads it just fine) + KeySizeValue = m_key.KeySize; } } @@ -416,6 +445,16 @@ namespace System.Security.Cryptography { return hasher.HashFinal(); } } - #endif + + private static bool IsEccAlgorithmGroup(CngAlgorithmGroup algorithmGroup) + { + // Sometimes, when reading from certificates, ECDSA keys get identified as ECDH. + // Windows allows the ECDH keys to perform both key exchange (ECDH) and signing (ECDSA), + // so either value is acceptable for the ECDSA wrapper object. + // + // It is worth noting, however, that ECDSA-identified keys cannot be used for key exchange (ECDH) in CNG. + return algorithmGroup == CngAlgorithmGroup.ECDsa || algorithmGroup == CngAlgorithmGroup.ECDiffieHellman; + } +#endif } } diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/NCryptNative.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/NCryptNative.cs index 8807a434240..9faf5ee01b1 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/NCryptNative.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/NCryptNative.cs @@ -796,10 +796,6 @@ namespace System.Security.Cryptography { signature, signature.Length, paddingMode); - if (error != ErrorCode.Success && error != ErrorCode.BadSignature) { - throw new CryptographicException((int)error); - } - return error == ErrorCode.Success; } @@ -1694,6 +1690,55 @@ namespace System.Security.Cryptography { return signature; } + /// + /// Sign a hash using no padding + /// + [System.Security.SecurityCritical] + internal static byte[] SignHash(SafeNCryptKeyHandle key, byte[] hash, int expectedSize) + { + Contract.Requires(key != null); + Contract.Requires(hash != null); + Contract.Ensures(Contract.Result() != null); + +#if DEBUG + expectedSize = 1; +#endif + + // Figure out how big the signature is + byte[] signature = new byte[expectedSize]; + int signatureSize = 0; + ErrorCode error = UnsafeNativeMethods.NCryptSignHash(key, + IntPtr.Zero, + hash, + hash.Length, + signature, + signature.Length, + out signatureSize, + 0); + + if (error == ErrorCode.BufferTooSmall) + { + signature = new byte[signatureSize]; + + error = UnsafeNativeMethods.NCryptSignHash(key, + IntPtr.Zero, + hash, + hash.Length, + signature, + signature.Length, + out signatureSize, + 0); + } + + if (error != ErrorCode.Success) + { + throw new CryptographicException((int)error); + } + + Array.Resize(ref signature, signatureSize); + return signature; + } + /// /// Unpack a key blob in ECC public blob format into its X and Y parameters /// @@ -1736,10 +1781,6 @@ namespace System.Security.Cryptography { signature.Length, 0); - if (error != ErrorCode.Success && error != ErrorCode.BadSignature) { - throw new CryptographicException((int)error); - } - return error == ErrorCode.Success; } } diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/RsaCng.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/RsaCng.cs index 842c40428e9..dda03fe7f37 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/RsaCng.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/RsaCng.cs @@ -101,7 +101,11 @@ namespace System.Security.Cryptography // If we don't have a key yet, we need to generate a random one now if (_key == null) { - CngKeyCreationParameters creationParameters = new CngKeyCreationParameters(); + CngKeyCreationParameters creationParameters = new CngKeyCreationParameters() + { + ExportPolicy = CngExportPolicies.AllowPlaintextExport, + }; + CngProperty keySizeProperty = new CngProperty(NCryptNative.KeyPropertyName.Length, BitConverter.GetBytes(KeySize), CngPropertyOptions.None); @@ -126,7 +130,22 @@ namespace System.Security.Cryptography } _key = value; - KeySize = _key.KeySize; + + // Our LegalKeySizes value stores the values that we encoded as being the correct + // legal key size limitations for this algorithm, as documented on MSDN. + // + // But on a new OS version we might not question if our limit is accurate, or MSDN + // could have been innacurate to start with. + // + // Since the key is already loaded, we know that Windows thought it to be valid; + // therefore we should set KeySizeValue directly to bypass the LegalKeySizes conformance + // check. + // + // For RSA there are known cases where this change matters. RSACryptoServiceProvider can + // create a 384-bit RSA key, which we consider too small to be legal. It can also create + // a 1032-bit RSA key, which we consider illegal because it doesn't match our 64-bit + // alignment requirement. (In both cases Windows loads it just fine) + KeySizeValue = _key.KeySize; } } @@ -516,6 +535,25 @@ namespace System.Security.Cryptography throw new CryptographicException(SR.GetString(SR.Cryptography_UnsupportedPaddingMode)); } } + + /* + * The members + * DecryptValue + * EncryptValue + * get_KeyExchangeAlgorithm + * get_SignatureAlgorithm + * are all implemented on RSA as of net46. + * + * But in servicing situations, System.Core.dll can get patched onto a machine which has mscorlib < net46, meaning + * these abstract members have no implementation. + * + * To keep servicing simple, we'll redefine the overrides here. Since this type is sealed it only affects reflection, + * as there are no derived types to mis-target base.-invocations. + */ + public override byte[] DecryptValue(byte[] rgb) { throw new NotSupportedException(SR.NotSupported_Method); } + public override byte[] EncryptValue(byte[] rgb) { throw new NotSupportedException(SR.NotSupported_Method); } + public override string KeyExchangeAlgorithm { get { return "RSA"; } } + public override string SignatureAlgorithm { get { return "RSA"; } } #endif } } diff --git a/mcs/class/referencesource/System.Core/System/Security/Cryptography/X509Certificates/RSACertificateExtensions.cs b/mcs/class/referencesource/System.Core/System/Security/Cryptography/X509Certificates/RSACertificateExtensions.cs index e4ef01d3e64..a69b7ed8aab 100644 --- a/mcs/class/referencesource/System.Core/System/Security/Cryptography/X509Certificates/RSACertificateExtensions.cs +++ b/mcs/class/referencesource/System.Core/System/Security/Cryptography/X509Certificates/RSACertificateExtensions.cs @@ -71,8 +71,14 @@ namespace System.Security.Cryptography.X509Certificates { if (privateKeyHandle == null) { + if (LocalAppContextSwitches.DontReliablyClonePrivateKey) + return (RSA)certificate.PrivateKey; + // fall back to CAPI if we cannot acquire the key using CNG. - return (RSA)certificate.PrivateKey; + RSACryptoServiceProvider rsaCsp = (RSACryptoServiceProvider)certificate.PrivateKey; + CspParameters cspParameters = DSACertificateExtensions.CopyCspParameters(rsaCsp); + RSACryptoServiceProvider clone = new RSACryptoServiceProvider(cspParameters); + return clone; } CngKey key = CngKey.Open(privateKeyHandle, CngKeyHandleOpenOptions.None); diff --git a/mcs/class/referencesource/System.Data.Entity/System/Data/Common/Utils/MetadataHelper.cs b/mcs/class/referencesource/System.Data.Entity/System/Data/Common/Utils/MetadataHelper.cs index 1ab0fb9122e..8d7a31911c0 100644 --- a/mcs/class/referencesource/System.Data.Entity/System/Data/Common/Utils/MetadataHelper.cs +++ b/mcs/class/referencesource/System.Data.Entity/System/Data/Common/Utils/MetadataHelper.cs @@ -833,6 +833,8 @@ namespace System.Data.Common.Utils [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Cryptographic.Standard", "CA5350:Microsoft.Cryptographic.Standard", Justification = "MD5CryptoServiceProvider is not used for cryptography/security purposes and we do it only for v1 and v1.1 for compatibility reasons.")] + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security.Cryptography", "CA5350:Microsoft.Cryptographic.Standard", + Justification = "MD5CryptoServiceProvider is not used for cryptography/security purposes and we do it only for v1 and v1.1 for compatibility reasons.")] internal static HashAlgorithm CreateMetadataHashAlgorithm(double schemaVersion) { HashAlgorithm hashAlgorithm; diff --git a/mcs/class/referencesource/System.Data.Entity/System/Data/EntityModel/SchemaObjectModel/Schema.cs b/mcs/class/referencesource/System.Data.Entity/System/Data/EntityModel/SchemaObjectModel/Schema.cs index a0388683aac..adb7b34c74d 100644 --- a/mcs/class/referencesource/System.Data.Entity/System/Data/EntityModel/SchemaObjectModel/Schema.cs +++ b/mcs/class/referencesource/System.Data.Entity/System/Data/EntityModel/SchemaObjectModel/Schema.cs @@ -1253,6 +1253,7 @@ namespace System.Data.EntityModel.SchemaObjectModel return schemaSet; } + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security.Xml", "CA3060:UseXmlReaderForSchemaRead", Justification = "The schema files are embedded in the product assembly as resources")] private static void AddXmlSchemaToSet(XmlSchemaSet schemaSet, XmlSchemaResource schemaResource, HashSet schemasAlreadyAdded) { // loop through the children to do a depth first load diff --git a/mcs/class/referencesource/System.Data.SqlXml/System/Xml/Xsl/IlGen/XmlILOptimizerVisitor.cs b/mcs/class/referencesource/System.Data.SqlXml/System/Xml/Xsl/IlGen/XmlILOptimizerVisitor.cs index e1c869221fa..f671178fc0c 100644 --- a/mcs/class/referencesource/System.Data.SqlXml/System/Xml/Xsl/IlGen/XmlILOptimizerVisitor.cs +++ b/mcs/class/referencesource/System.Data.SqlXml/System/Xml/Xsl/IlGen/XmlILOptimizerVisitor.cs @@ -2289,8 +2289,8 @@ namespace System.Xml.Xsl.IlGen { if (local3.NodeType == QilNodeType.Loop) { QilNode local4 = local3[0]; QilNode local5 = local3[1]; - if ( NonPositional(local2, local1) ) { - // PATTERN: [CommuteFilterLoop] (Filter $iter:(For (Loop $iter2:* $ret2:*)) $cond:* ^ (NonPositional? $cond $iter)) => (Loop $iter2 (Filter $iter3:(For $ret2) (Subs $cond $iter $iter3))) + if (( NonPositional(local2, local1) ) && (!( IsDocOrderDistinct(local3) ))) { + // PATTERN: [CommuteFilterLoop] (Filter $iter:(For $loop:(Loop $iter2:* $ret2:*)) $cond:* ^ (NonPositional? $cond $iter) ^ ~((DocOrderDistinct? $loop))) => (Loop $iter2 (Filter $iter3:(For $ret2) (Subs $cond $iter $iter3))) if (AllowReplace(XmlILOptimization.CommuteFilterLoop, local0)) { QilNode local6 = VisitFor(f.For(local5)); return Replace(XmlILOptimization.CommuteFilterLoop, local0, VisitLoop(f.Loop(local4, VisitFilter(f.Filter(local6, Subs(local2, local1, local6) ))))); diff --git a/mcs/class/referencesource/System.Data/System/Data/Common/DbConnectionStringCommon.cs b/mcs/class/referencesource/System.Data/System/Data/Common/DbConnectionStringCommon.cs index e1981b6b9de..24be05dfc29 100644 --- a/mcs/class/referencesource/System.Data/System/Data/Common/DbConnectionStringCommon.cs +++ b/mcs/class/referencesource/System.Data/System/Data/Common/DbConnectionStringCommon.cs @@ -323,6 +323,143 @@ namespace System.Data.Common { } } + #region <> + const string PoolBlockingPeriodAutoString = "Auto"; + const string PoolBlockingPeriodAlwaysBlockString = "AlwaysBlock"; + const string PoolBlockingPeriodNeverBlockString = "NeverBlock"; + + internal static bool TryConvertToPoolBlockingPeriod(string value, out PoolBlockingPeriod result) + { + Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); + Debug.Assert(null != value, "TryConvertToPoolBlockingPeriod(null,...)"); + + if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodAutoString)) + { + result = PoolBlockingPeriod.Auto; + return true; + } + else if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodAlwaysBlockString)) + { + result = PoolBlockingPeriod.AlwaysBlock; + return true; + } + else if (StringComparer.OrdinalIgnoreCase.Equals(value, PoolBlockingPeriodNeverBlockString)) + { + result = PoolBlockingPeriod.NeverBlock; + return true; + } + else + { + result = DbConnectionStringDefaults.PoolBlockingPeriod; + return false; + } + } + + internal static bool IsValidPoolBlockingPeriodValue(PoolBlockingPeriod value) + { + Debug.Assert(Enum.GetNames(typeof(PoolBlockingPeriod)).Length == 3, "PoolBlockingPeriod enum has changed, update needed"); + return value == PoolBlockingPeriod.Auto || value == PoolBlockingPeriod.AlwaysBlock || value == PoolBlockingPeriod.NeverBlock; + } + + internal static string PoolBlockingPeriodToString(PoolBlockingPeriod value) + { + Debug.Assert(IsValidPoolBlockingPeriodValue(value)); + + if (value == PoolBlockingPeriod.AlwaysBlock) + { + return PoolBlockingPeriodAlwaysBlockString; + } + if (value == PoolBlockingPeriod.NeverBlock) + { + return PoolBlockingPeriodNeverBlockString; + } + else + { + return PoolBlockingPeriodAutoString; + } + } + + /// + /// This method attempts to convert the given value to a PoolBlockingPeriod enum. The algorithm is: + /// * if the value is from type string, it will be matched against PoolBlockingPeriod enum names only, using ordinal, case-insensitive comparer + /// * if the value is from type PoolBlockingPeriod, it will be used as is + /// * if the value is from integral type (SByte, Int16, Int32, Int64, Byte, UInt16, UInt32, or UInt64), it will be converted to enum + /// * if the value is another enum or any other type, it will be blocked with an appropriate ArgumentException + /// + /// in any case above, if the conerted value is out of valid range, the method raises ArgumentOutOfRangeException. + /// + /// PoolBlockingPeriod value in the valid range + internal static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value) + { + Debug.Assert(null != value, "ConvertToPoolBlockingPeriod(null)"); + string sValue = (value as string); + PoolBlockingPeriod result; + if (null != sValue) + { + // We could use Enum.TryParse here, but it accepts value combinations like + // "ReadOnly, ReadWrite" which are unwelcome here + // Also, Enum.TryParse is 100x slower than plain StringComparer.OrdinalIgnoreCase.Equals method. + + if (TryConvertToPoolBlockingPeriod(sValue, out result)) + { + return result; + } + + // try again after remove leading & trailing whitespaces. + sValue = sValue.Trim(); + if (TryConvertToPoolBlockingPeriod(sValue, out result)) + { + return result; + } + + // string values must be valid + throw ADP.InvalidConnectionOptionValue(keyword); + } + else + { + // the value is not string, try other options + PoolBlockingPeriod eValue; + + if (value is PoolBlockingPeriod) + { + // quick path for the most common case + eValue = (PoolBlockingPeriod)value; + } + else if (value.GetType().IsEnum) + { + // explicitly block scenarios in which user tries to use wrong enum types, like: + // builder["PoolBlockingPeriod"] = EnvironmentVariableTarget.Process; + // workaround: explicitly cast non-PoolBlockingPeriod enums to int + throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), null); + } + else + { + try + { + // Enum.ToObject allows only integral and enum values (enums are blocked above), rasing ArgumentException for the rest + eValue = (PoolBlockingPeriod)Enum.ToObject(typeof(PoolBlockingPeriod), value); + } + catch (ArgumentException e) + { + // to be consistent with the messages we send in case of wrong type usage, replace + // the error with our exception, and keep the original one as inner one for troubleshooting + throw ADP.ConvertFailed(value.GetType(), typeof(PoolBlockingPeriod), e); + } + } + + // ensure value is in valid range + if (IsValidPoolBlockingPeriodValue(eValue)) + { + return eValue; + } + else + { + throw ADP.InvalidEnumerationValue(typeof(ApplicationIntent), (int)eValue); + } + } + } + #endregion + const string ApplicationIntentReadWriteString = "ReadWrite"; const string ApplicationIntentReadOnlyString = "ReadOnly"; @@ -752,6 +889,7 @@ namespace System.Data.Common { internal const int ConnectRetryInterval = 10; internal static readonly SqlAuthenticationMethod Authentication = SqlAuthenticationMethod.NotSpecified; internal static readonly SqlConnectionColumnEncryptionSetting ColumnEncryptionSetting = SqlConnectionColumnEncryptionSetting.Disabled; + internal const PoolBlockingPeriod PoolBlockingPeriod = SqlClient.PoolBlockingPeriod.Auto; } internal static class DbConnectionOptionKeywords { @@ -819,6 +957,7 @@ namespace System.Data.Common { internal const string Authentication = "Authentication"; internal const string Certificate = "Certificate"; internal const string ColumnEncryptionSetting = "Column Encryption Setting"; + internal const string PoolBlockingPeriod = "PoolBlockingPeriod"; // common keywords (OleDb, OracleClient, SqlClient) internal const string DataSource = "Data Source"; diff --git a/mcs/class/referencesource/System.Data/System/Data/DataSet.cs b/mcs/class/referencesource/System.Data/System/Data/DataSet.cs index cb0c072a659..44d81f07e1e 100644 --- a/mcs/class/referencesource/System.Data/System/Data/DataSet.cs +++ b/mcs/class/referencesource/System.Data/System/Data/DataSet.cs @@ -2122,7 +2122,12 @@ namespace System.Data { if (stream == null) return XmlReadMode.Auto; - return ReadXml(new XmlTextReader(stream), false); + XmlTextReader xr = new XmlTextReader(stream); + + // Prevent Dtd entity in dataset + xr.XmlResolver = null; + + return ReadXml(xr, false); } /// @@ -2132,7 +2137,12 @@ namespace System.Data { if (reader == null) return XmlReadMode.Auto; - return ReadXml(new XmlTextReader(reader), false); + XmlTextReader xr = new XmlTextReader(reader); + + // Prevent Dtd entity in dataset + xr.XmlResolver = null; + + return ReadXml(xr, false); } /// @@ -2142,7 +2152,12 @@ namespace System.Data { public XmlReadMode ReadXml(string fileName) { XmlTextReader xr = new XmlTextReader(fileName); - try { + + // Prevent Dtd entity in dataset + xr.XmlResolver = null; + + try + { return ReadXml(xr, false); } finally { @@ -2520,6 +2535,8 @@ namespace System.Data { return XmlReadMode.Auto; XmlTextReader reader = (mode == XmlReadMode.Fragment) ? new XmlTextReader(stream, XmlNodeType.Element, null) : new XmlTextReader(stream); + // Prevent Dtd entity in dataset + reader.XmlResolver = null; return ReadXml(reader, mode, false); } @@ -2531,6 +2548,8 @@ namespace System.Data { return XmlReadMode.Auto; XmlTextReader xmlreader = (mode == XmlReadMode.Fragment) ? new XmlTextReader(reader.ReadToEnd(), XmlNodeType.Element, null) : new XmlTextReader(reader); + // Prevent Dtd entity in dataset + xmlreader.XmlResolver = null; return ReadXml(xmlreader, mode, false); } @@ -2547,7 +2566,12 @@ namespace System.Data { } else xr = new XmlTextReader(fileName); - try { + + // Prevent Dtd entity in dataset + xr.XmlResolver = null; + + try + { return ReadXml(xr, mode, false); } finally { diff --git a/mcs/class/referencesource/System.Data/System/Data/DataTable.cs b/mcs/class/referencesource/System.Data/System/Data/DataTable.cs index 637816ef0c3..24673fa5c51 100644 --- a/mcs/class/referencesource/System.Data/System/Data/DataTable.cs +++ b/mcs/class/referencesource/System.Data/System/Data/DataTable.cs @@ -5044,7 +5044,12 @@ namespace System.Data { if (stream == null) return XmlReadMode.Auto; - return ReadXml( new XmlTextReader(stream), false); + XmlTextReader xr = new XmlTextReader(stream); + + // Prevent Dtd entity in DataTable + xr.XmlResolver = null; + + return ReadXml(xr, false); } public XmlReadMode ReadXml(TextReader reader) @@ -5052,7 +5057,12 @@ namespace System.Data { if (reader == null) return XmlReadMode.Auto; - return ReadXml( new XmlTextReader(reader), false); + XmlTextReader xr = new XmlTextReader(reader); + + // Prevent Dtd entity in DataTable + xr.XmlResolver = null; + + return ReadXml(xr, false); } [ResourceExposure(ResourceScope.Machine)] @@ -5060,7 +5070,12 @@ namespace System.Data { public XmlReadMode ReadXml(string fileName) { XmlTextReader xr = new XmlTextReader(fileName); - try { + + // Prevent Dtd entity in DataTable + xr.XmlResolver = null; + + try + { return ReadXml( xr , false); } finally { diff --git a/mcs/class/referencesource/System.Data/System/Data/ProviderBase/DbConnectionPool.cs b/mcs/class/referencesource/System.Data/System/Data/ProviderBase/DbConnectionPool.cs index 5b5743725f9..dd0b6ad4bb3 100644 --- a/mcs/class/referencesource/System.Data/System/Data/ProviderBase/DbConnectionPool.cs +++ b/mcs/class/referencesource/System.Data/System/Data/ProviderBase/DbConnectionPool.cs @@ -12,6 +12,7 @@ namespace System.Data.ProviderBase { using System.Collections; using System.Collections.Generic; using System.Data.Common; + using System.Data.SqlClient; using System.Diagnostics; using System.Globalization; using System.Runtime.CompilerServices; @@ -756,7 +757,81 @@ namespace System.Data.ProviderBase { private Timer CreateCleanupTimer() { return (new Timer(new TimerCallback(this.CleanupCallback), null, _cleanupWait, _cleanupWait)); } - + + private static readonly string[] AzureSqlServerEndpoints = {Res.GetString(Res.AZURESQL_GenericEndpoint), + Res.GetString(Res.AZURESQL_GermanEndpoint), + Res.GetString(Res.AZURESQL_UsGovEndpoint), + Res.GetString(Res.AZURESQL_ChinaEndpoint) }; + private static bool IsAzureSqlServerEndpoint(string dataSource) + { + // remove server port + var i = dataSource.LastIndexOf(','); + if (i >= 0) + { + dataSource = dataSource.Substring(0, i); + } + + // check for the instance name + i = dataSource.LastIndexOf('\\'); + if (i >= 0) + { + dataSource = dataSource.Substring(0, i); + } + + // trim redundant whitespaces + dataSource = dataSource.Trim(); + + // check if servername end with any azure endpoints + for (i = 0; i < AzureSqlServerEndpoints.Length; i++) + { + if (dataSource.EndsWith(AzureSqlServerEndpoints[i], StringComparison.OrdinalIgnoreCase)) + { + return true; + } + } + return false; + } + + private bool IsBlockingPeriodEnabled() + { + var poolGroupConnectionOptions = _connectionPoolGroup.ConnectionOptions as SqlConnectionString; + if (poolGroupConnectionOptions == null) + { + return true; + } + + var policy = poolGroupConnectionOptions.PoolBlockingPeriod; + + switch (policy) + { + case PoolBlockingPeriod.Auto: + { + if (IsAzureSqlServerEndpoint(poolGroupConnectionOptions.DataSource)) + { + return false; // in Azure it will be Disabled + } + else + { + return true; // in Non Azure, it will be Enabled + } + } + case PoolBlockingPeriod.AlwaysBlock: + { + return true; //Enabled + } + case PoolBlockingPeriod.NeverBlock: + { + return false; //Disabled + } + default: + { + //we should never get into this path. + Debug.Fail("Unknown PoolBlockingPeriod. Please specify explicit results in above switch case statement."); + return true; + } + } + } + private DbConnectionInternal CreateObject(DbConnection owningObject, DbConnectionOptions userOptions, DbConnectionInternal oldConnection) { DbConnectionInternal newObj = null; @@ -797,7 +872,7 @@ namespace System.Data.ProviderBase { // Reset the error wait: _errorWait = ERROR_WAIT_DEFAULT; } - catch(Exception e) { + catch(Exception e) { // if (!ADP.IsCatchableExceptionType(e)) { throw; @@ -805,6 +880,11 @@ namespace System.Data.ProviderBase { ADP.TraceExceptionForCapture(e); + if (!IsBlockingPeriodEnabled()) + { + throw; + } + newObj = null; // set to null, so we do not return bad new object // Failed to create instance _resError = e; diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlClientSymmetricKey.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlClientSymmetricKey.cs index 112108ae14b..501ed7c9150 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlClientSymmetricKey.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlClientSymmetricKey.cs @@ -15,10 +15,9 @@ namespace System.Data.SqlClient /// Base class containing raw key bytes for symmetric key algorithms. Some encryption algorithms can use the key directly while others derive sub keys from this. /// If an algorithm needs to derive more keys, have a derived class from this and use it in the corresponding encryption algorithm. /// - internal class SqlClientSymmetricKey - { + internal class SqlClientSymmetricKey { /// - /// DPAPI protected key + /// The underlying key material /// protected readonly byte[] _rootKey; @@ -26,8 +25,7 @@ namespace System.Data.SqlClient /// Constructor that initializes the root key. /// /// root key - internal SqlClientSymmetricKey(byte[] rootKey) - { + internal SqlClientSymmetricKey(byte[] rootKey) { // Key validation if (rootKey == null || rootKey.Length == 0) { throw SQL.NullColumnEncryptionKeySysErr(); @@ -36,14 +34,24 @@ namespace System.Data.SqlClient _rootKey = rootKey; } + /// + /// Destructor that cleans up the key material. + /// This is a best effort approach since there are no guarantees around GC. + /// + ~SqlClientSymmetricKey() { + if (_rootKey != null) { + for (int i = 0; i < _rootKey.Length; i++) { + _rootKey[i] = 0; + } + } + } + /// /// Returns a copy of the plain text key /// This is needed for actual encryption/decryption. /// - internal virtual byte[] RootKey - { - get - { + internal virtual byte[] RootKey { + get { return _rootKey; } } @@ -52,8 +60,7 @@ namespace System.Data.SqlClient /// Computes SHA256 value of the plain text key bytes /// /// A string containing SHA256 hash of the root key - internal virtual string GetKeyHash() - { + internal virtual string GetKeyHash() { return SqlSecurityUtility.GetSHA256Hash(RootKey); } @@ -63,10 +70,7 @@ namespace System.Data.SqlClient /// /// Returns the length of the root key /// - internal virtual int Length() - { - // Note: DPAPI preserves the original byte length - // so for now, this is as same as returning the length of the raw key. + internal virtual int Length() { return _rootKey.Length; } } diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlCommand.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlCommand.cs index 2e560dbf344..46a53537089 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlCommand.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlCommand.cs @@ -81,7 +81,12 @@ namespace System.Data.SqlClient { /// Force the client to sleep during sp_describe_parameter_encryption after ReadDescribeEncryptionParameterResults. /// private static bool _sleepAfterReadDescribeEncryptionParameterResults = false; -#endif + + /// + /// Internal flag for testing purposes that forces all queries to internally end async calls. + /// + private static bool _forceInternalEndQuery = false; +#endif // devnote: Prepare // Against 7.0 Server (Sphinx) a prepare/unprepare requires an extra roundtrip to the server. @@ -287,6 +292,16 @@ namespace System.Data.SqlClient { } } + /// + /// A flag to indicate if EndExecute was already initiated by the Begin call. + /// + private volatile bool _internalEndExecuteInitiated; + + /// + /// A flag to indicate whether we postponed caching the query metadata for this command. + /// + internal bool CachingQueryMetadataPostponed { get; set; } + // // Smi execution-specific stuff // @@ -1170,7 +1185,8 @@ namespace System.Data.SqlClient { try { statistics = SqlStatistics.StartTimer(Statistics); WriteBeginExecuteEvent(); - InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, false, CommandTimeout); + bool usedCache; + InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, false, CommandTimeout, out usedCache); success = true; return _rowsAffected; } @@ -1199,7 +1215,8 @@ namespace System.Data.SqlClient { Bid.ScopeEnter(out hscp, " %d#", ObjectID); try { statistics = SqlStatistics.StartTimer(Statistics); - InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, true, CommandTimeout); + bool usedCache; + InternalExecuteNonQuery(null, ADP.ExecuteNonQuery, true, CommandTimeout, out usedCache); } finally { SqlStatistics.StopTimer(statistics); @@ -1217,34 +1234,41 @@ namespace System.Data.SqlClient { public IAsyncResult BeginExecuteNonQuery(AsyncCallback callback, object stateObject) { Bid.CorrelationTrace(" ObjectID%d#, ActivityID %ls\n", ObjectID); SqlConnection.ExecutePermission.Demand(); - return BeginExecuteNonQueryInternal(callback, stateObject, 0); + return BeginExecuteNonQueryInternal(0, callback, stateObject, 0, inRetry: false); } private IAsyncResult BeginExecuteNonQueryAsync(AsyncCallback callback, object stateObject) { - return BeginExecuteNonQueryInternal(callback, stateObject, CommandTimeout, asyncWrite:true); + return BeginExecuteNonQueryInternal(0, callback, stateObject, CommandTimeout, inRetry: false, asyncWrite:true); } - private IAsyncResult BeginExecuteNonQueryInternal(AsyncCallback callback, object stateObject, int timeout, bool asyncWrite = false) { - // Reset _pendingCancel upon entry into any Execute - used to synchronize state - // between entry into Execute* API and the thread obtaining the stateObject. - _pendingCancel = false; + private IAsyncResult BeginExecuteNonQueryInternal(CommandBehavior behavior, AsyncCallback callback, object stateObject, int timeout, bool inRetry, bool asyncWrite = false) { + TaskCompletionSource globalCompletion = new TaskCompletionSource(stateObject); + TaskCompletionSource localCompletion = new TaskCompletionSource(stateObject); + + if (!inRetry) { + // Reset _pendingCancel upon entry into any Execute - used to synchronize state + // between entry into Execute* API and the thread obtaining the stateObject. + _pendingCancel = false; + + ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj + // back into pool when we should not. + } - ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj - // back into pool when we should not. - SqlStatistics statistics = null; try { - statistics = SqlStatistics.StartTimer(Statistics); - WriteBeginExecuteEvent(); - TaskCompletionSource completion = new TaskCompletionSource(stateObject); + if (!inRetry) { + statistics = SqlStatistics.StartTimer(Statistics); + WriteBeginExecuteEvent(); + } + bool usedCache; try { // InternalExecuteNonQuery already has reliability block, but if failure will not put stateObj back into pool. - Task execNQ = InternalExecuteNonQuery(completion, ADP.BeginExecuteNonQuery, false, timeout, asyncWrite); + Task execNQ = InternalExecuteNonQuery(localCompletion, ADP.BeginExecuteNonQuery, false, timeout, out usedCache, asyncWrite, inRetry: inRetry); if (execNQ != null) { - AsyncHelper.ContinueTask(execNQ, completion, () => BeginExecuteNonQueryInternalReadStage(completion)); + AsyncHelper.ContinueTask(execNQ, localCompletion, () => BeginExecuteNonQueryInternalReadStage(localCompletion)); } else { - BeginExecuteNonQueryInternalReadStage(completion); + BeginExecuteNonQueryInternalReadStage(localCompletion); } } catch (Exception e) { @@ -1258,12 +1282,18 @@ namespace System.Data.SqlClient { throw; } + // When we use query caching for parameter encryption we need to retry on specific errors. + // In these cases finalize the call internally and trigger a retry when needed. + if (!TriggerInternalEndAndRetryIfNecessary(behavior, stateObject, timeout, ADP.EndExecuteNonQuery, usedCache, inRetry, asyncWrite, globalCompletion, localCompletion, InternalEndExecuteNonQuery, BeginExecuteNonQueryInternal)) { + globalCompletion = localCompletion; + } + // Add callback after work is done to avoid overlapping Begin\End methods if (callback != null) { - completion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default); + globalCompletion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default); } - return completion.Task; + return globalCompletion.Task; } finally { SqlStatistics.StopTimer(statistics); @@ -1319,7 +1349,7 @@ namespace System.Data.SqlClient { } } - private void VerifyEndExecuteState(Task completionTask, String endMethod) { + private void VerifyEndExecuteState(Task completionTask, String endMethod, bool fullCheckForColumnEncryption = false) { if (null == completionTask) { throw ADP.ArgumentNull("asyncResult"); } @@ -1340,7 +1370,7 @@ namespace System.Data.SqlClient { // If transparent parameter encryption was attempted, then we need to skip other checks like those on EndMethodName // since we want to wait for async results before checking those fields. - if (IsColumnEncryptionEnabled) { + if (IsColumnEncryptionEnabled && !fullCheckForColumnEncryption) { if (_activeConnection.State != ConnectionState.Open) { // If the connection is not 'valid' then it was closed while we were executing throw ADP.ClosedConnectionError(); @@ -1361,13 +1391,24 @@ namespace System.Data.SqlClient { } } - private void WaitForAsyncResults(IAsyncResult asyncResult) { + private void WaitForAsyncResults(IAsyncResult asyncResult, bool isInternal) { Task completionTask = (Task) asyncResult; if (!asyncResult.IsCompleted) { asyncResult.AsyncWaitHandle.WaitOne(); } - _stateObj._networkPacketTaskSource = null; - _activeConnection.GetOpenTdsConnection().DecrementAsyncCount(); + + if (_stateObj != null) { + _stateObj._networkPacketTaskSource = null; + } + + // If this is an internal command we will decrement the count when the End method is actually called by the user. + // If we are using Column Encryption and the previous task failed, the async count should have already been fixed up. + // There is a generic issue in how we handle the async count because: + // a) BeginExecute might or might not clean it up on failure. + // b) In EndExecute, we check the task state before waiting and throw if it's failed, whereas if we wait we will always adjust the count. + if (!isInternal && (!IsColumnEncryptionEnabled || !completionTask.IsFaulted)) { + _activeConnection.GetOpenTdsConnection().DecrementAsyncCount(); + } } public int EndExecuteNonQuery(IAsyncResult asyncResult) { @@ -1390,6 +1431,7 @@ namespace System.Data.SqlClient { private int EndExecuteNonQueryAsync(IAsyncResult asyncResult) { Bid.CorrelationTrace(" ObjectID%d#, ActivityID %ls\n", ObjectID); + Debug.Assert(!_internalEndExecuteInitiated || _stateObj == null); Exception asyncException = ((Task)asyncResult).Exception; if (asyncException != null) { @@ -1400,7 +1442,13 @@ namespace System.Data.SqlClient { else { ThrowIfReconnectionHasBeenCanceled(); // lock on _stateObj prevents ----s with close/cancel. - lock (_stateObj) { + // If we have already initiate the End call internally, we have already done that, so no point doing it again. + if (!_internalEndExecuteInitiated) { + lock (_stateObj) { + return EndExecuteNonQueryInternal(asyncResult); + } + } + else { return EndExecuteNonQueryInternal(asyncResult); } } @@ -1408,11 +1456,43 @@ namespace System.Data.SqlClient { private int EndExecuteNonQueryInternal(IAsyncResult asyncResult) { SqlStatistics statistics = null; + bool success = false; + int? sqlExceptionNumber = null; + try { + statistics = SqlStatistics.StartTimer(Statistics); + int result = (int)InternalEndExecuteNonQuery(asyncResult, ADP.EndExecuteNonQuery, isInternal: false); + success = true; + return result; + } + catch (SqlException e) { + sqlExceptionNumber = e.Number; + if (cachedAsyncState != null) { + cachedAsyncState.ResetAsyncState(); + }; + // SqlException is always catchable + ReliablePutStateObject(); + throw; + } + catch (Exception e) { + if (cachedAsyncState != null) { + cachedAsyncState.ResetAsyncState(); + }; + if (ADP.IsCatchableExceptionType(e)) { + ReliablePutStateObject(); + }; + throw; + } + finally { + SqlStatistics.StopTimer(statistics); + WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: false); + } + } + + private object InternalEndExecuteNonQuery(IAsyncResult asyncResult, string endMethod, bool isInternal) { TdsParser bestEffortCleanupTarget = null; RuntimeHelpers.PrepareConstrainedRegions(); - bool success = false; - int? sqlExceptionNumber = null; + try { #if DEBUG TdsParser.ReliabilitySection tdsReliabilitySection = new TdsParser.ReliabilitySection(); @@ -1424,30 +1504,32 @@ namespace System.Data.SqlClient { { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - statistics = SqlStatistics.StartTimer(Statistics); - VerifyEndExecuteState((Task)asyncResult, ADP.EndExecuteNonQuery); - WaitForAsyncResults(asyncResult); + VerifyEndExecuteState((Task)asyncResult, endMethod); + WaitForAsyncResults(asyncResult, isInternal); - // If Transparent parameter encryption was attempted, then we would have skipped the below - // checks in VerifyEndExecuteState since we wanted to wait for WaitForAsyncResults to complete. + // If column encryption is enabled, also check the state after waiting for the task. + // It would be better to do this for all cases, but avoiding for compatibility reasons. if (IsColumnEncryptionEnabled) { - if (cachedAsyncState.EndMethodName == null) { - throw ADP.MethodCalledTwice(ADP.EndExecuteNonQuery); - } - - if (ADP.EndExecuteNonQuery != cachedAsyncState.EndMethodName) { - throw ADP.MismatchedAsyncResult(cachedAsyncState.EndMethodName, ADP.EndExecuteNonQuery); - } - - if (!cachedAsyncState.IsActiveConnectionValid(_activeConnection)) { - // If the connection is not 'valid' then it was closed while we were executing - throw ADP.ClosedConnectionError(); - } + VerifyEndExecuteState((Task)asyncResult, endMethod, fullCheckForColumnEncryption: true); } bool processFinallyBlock = true; try { - NotifyDependency(); + // If this is not for internal usage, notify the dependency. + // If we have already initiated the end internally, the reader should be ready, so just return the rows affected. + if (!isInternal) { + NotifyDependency(); + + if (_internalEndExecuteInitiated) { + Debug.Assert(_stateObj == null); + + // Reset the state since we exit early. + cachedAsyncState.ResetAsyncState(); + + return _rowsAffected; + } + } + CheckThrowSNIException(); // only send over SQL Batch command if we are not a stored proc and have no parameters @@ -1459,20 +1541,19 @@ namespace System.Data.SqlClient { if (!result) { throw SQL.SynchronousCallMayNotPend(); } } finally { - cachedAsyncState.ResetAsyncState(); + // Don't reset the state for internal End. The user End will do that eventually. + if (!isInternal) { + cachedAsyncState.ResetAsyncState(); + } } } else { // otherwise, use a full-fledged execute that can handle params and stored procs - SqlDataReader reader = CompleteAsyncExecuteReader(); + SqlDataReader reader = CompleteAsyncExecuteReader(isInternal); if (null != reader) { reader.Close(); } } } - catch (SqlException e) { - sqlExceptionNumber = e.Number; - throw; - } catch (Exception e) { processFinallyBlock = ADP.IsCatchableExceptionType(e); throw; @@ -1484,7 +1565,6 @@ namespace System.Data.SqlClient { } Debug.Assert(null == _stateObj, "non-null state object in EndExecuteNonQuery"); - success = true; return _rowsAffected; } #if DEBUG @@ -1506,23 +1586,11 @@ namespace System.Data.SqlClient { SqlInternalConnection.BestEffortCleanup(bestEffortCleanupTarget); throw; } - catch (Exception e) { - if (cachedAsyncState != null) { - cachedAsyncState.ResetAsyncState(); - }; - if (ADP.IsCatchableExceptionType(e)) { - ReliablePutStateObject(); - }; - throw; - } - finally { - SqlStatistics.StopTimer(statistics); - WriteEndExecuteEvent(success, sqlExceptionNumber, synchronous: false); - } } - private Task InternalExecuteNonQuery(TaskCompletionSource completion, string methodName, bool sendToPipe, int timeout, bool asyncWrite = false) { + private Task InternalExecuteNonQuery(TaskCompletionSource completion, string methodName, bool sendToPipe, int timeout, out bool usedCache, bool asyncWrite = false, bool inRetry = false) { bool async = (null != completion); + usedCache = false; SqlStatistics statistics = Statistics; _rowsAffected = -1; @@ -1542,7 +1610,9 @@ namespace System.Data.SqlClient { bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); // @devnote: this function may throw for an invalid connection // @devnote: returns false for empty command text - ValidateCommand(methodName, async); + if (!inRetry) { + ValidateCommand(methodName, async); + } CheckNotificationStateAndAutoEnlist(); // Only call after validate - requires non null connection! Task task = null; @@ -1566,12 +1636,15 @@ namespace System.Data.SqlClient { } } + // We should never get here for a retry since we only have retries for parameters. + Debug.Assert(!inRetry); + task = RunExecuteNonQueryTds(methodName, async, timeout, asyncWrite); } else { // otherwise, use a full-fledged execute that can handle params and stored procs Debug.Assert( !sendToPipe, "trying to send non-context command to pipe" ); Bid.Trace(" %d#, Command executed as RPC.\n", ObjectID); - SqlDataReader reader = RunExecuteReader(0, RunBehavior.UntilDone, false, methodName, completion, timeout, out task, asyncWrite); + SqlDataReader reader = RunExecuteReader(0, RunBehavior.UntilDone, false, methodName, completion, timeout, out task, out usedCache, asyncWrite, inRetry); if (null!=reader) { if (task != null) { task = AsyncHelper.CreateContinuationTask(task, () => reader.Close()); @@ -1649,31 +1722,38 @@ namespace System.Data.SqlClient { [System.Security.Permissions.HostProtectionAttribute(ExternalThreading=true)] public IAsyncResult BeginExecuteXmlReader(AsyncCallback callback, object stateObject) { Bid.CorrelationTrace(" ObjectID%d#, ActivityID %ls\n", ObjectID); - SqlConnection.ExecutePermission.Demand(); - return BeginExecuteXmlReaderInternal(callback, stateObject, 0); + SqlConnection.ExecutePermission.Demand(); + return BeginExecuteXmlReaderInternal(CommandBehavior.SequentialAccess, callback, stateObject, 0, inRetry: false); } private IAsyncResult BeginExecuteXmlReaderAsync(AsyncCallback callback, object stateObject) { - return BeginExecuteXmlReaderInternal(callback, stateObject, CommandTimeout, asyncWrite:true); + return BeginExecuteXmlReaderInternal(CommandBehavior.SequentialAccess, callback, stateObject, CommandTimeout, inRetry: false, asyncWrite: true); } - private IAsyncResult BeginExecuteXmlReaderInternal(AsyncCallback callback, object stateObject, int timeout, bool asyncWrite = false) { - // Reset _pendingCancel upon entry into any Execute - used to synchronize state - // between entry into Execute* API and the thread obtaining the stateObject. - _pendingCancel = false; + private IAsyncResult BeginExecuteXmlReaderInternal(CommandBehavior behavior, AsyncCallback callback, object stateObject, int timeout, bool inRetry, bool asyncWrite = false) { + TaskCompletionSource globalCompletion = new TaskCompletionSource(stateObject); + TaskCompletionSource localCompletion = new TaskCompletionSource(stateObject); - ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj - // back into pool when we should not. + if (!inRetry) { + // Reset _pendingCancel upon entry into any Execute - used to synchronize state + // between entry into Execute* API and the thread obtaining the stateObject. + _pendingCancel = false; + + ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj + // back into pool when we should not. + } SqlStatistics statistics = null; try { - statistics = SqlStatistics.StartTimer(Statistics); - WriteBeginExecuteEvent(); - TaskCompletionSource completion = new TaskCompletionSource(stateObject); + if (!inRetry) { + statistics = SqlStatistics.StartTimer(Statistics); + WriteBeginExecuteEvent(); + } + bool usedCache; Task writeTask; try { // InternalExecuteNonQuery already has reliability block, but if failure will not put stateObj back into pool. - RunExecuteReader(CommandBehavior.SequentialAccess, RunBehavior.ReturnImmediately, true, ADP.BeginExecuteXmlReader, completion, timeout, out writeTask, asyncWrite); + RunExecuteReader(behavior, RunBehavior.ReturnImmediately, true, ADP.BeginExecuteXmlReader, localCompletion, timeout, out writeTask, out usedCache, asyncWrite, inRetry); } catch (Exception e) { if (!ADP.IsCatchableOrSecurityExceptionType(e)) { @@ -1687,17 +1767,23 @@ namespace System.Data.SqlClient { } if (writeTask != null) { - AsyncHelper.ContinueTask(writeTask, completion, () => BeginExecuteXmlReaderInternalReadStage(completion)); + AsyncHelper.ContinueTask(writeTask, localCompletion, () => BeginExecuteXmlReaderInternalReadStage(localCompletion)); } else { - BeginExecuteXmlReaderInternalReadStage(completion); + BeginExecuteXmlReaderInternalReadStage(localCompletion); + } + + // When we use query caching for parameter encryption we need to retry on specific errors. + // In these cases finalize the call internally and trigger a retry when needed. + if (!TriggerInternalEndAndRetryIfNecessary(behavior, stateObject, timeout, ADP.EndExecuteXmlReader, usedCache, inRetry, asyncWrite, globalCompletion, localCompletion, InternalEndExecuteReader, BeginExecuteXmlReaderInternal)) { + globalCompletion = localCompletion; } // Add callback after work is done to avoid overlapping Begin\End methods if (callback != null) { - completion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default); + globalCompletion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default); } - return completion.Task; + return globalCompletion.Task; } finally { SqlStatistics.StopTimer(statistics); @@ -1768,6 +1854,7 @@ namespace System.Data.SqlClient { private XmlReader EndExecuteXmlReaderAsync(IAsyncResult asyncResult) { Bid.CorrelationTrace(" ObjectID%d#, ActivityID %ls\n", ObjectID); + Debug.Assert(!_internalEndExecuteInitiated || _stateObj == null); Exception asyncException = ((Task)asyncResult).Exception; if (asyncException != null) { @@ -1778,7 +1865,13 @@ namespace System.Data.SqlClient { else { ThrowIfReconnectionHasBeenCanceled(); // lock on _stateObj prevents ----s with close/cancel. - lock (_stateObj) { + // If we have already initiate the End call internally, we have already done that, so no point doing it again. + if (!_internalEndExecuteInitiated) { + lock (_stateObj) { + return EndExecuteXmlReaderInternal(asyncResult); + } + } + else { return EndExecuteXmlReaderInternal(asyncResult); } } @@ -1788,7 +1881,7 @@ namespace System.Data.SqlClient { bool success = false; int? sqlExceptionNumber = null; try { - XmlReader result = CompleteXmlReader(InternalEndExecuteReader(asyncResult, ADP.EndExecuteXmlReader)); + XmlReader result = CompleteXmlReader(InternalEndExecuteReader(asyncResult, ADP.EndExecuteXmlReader, isInternal: false)); success = true; return result; } @@ -1894,7 +1987,7 @@ namespace System.Data.SqlClient { public IAsyncResult BeginExecuteReader(AsyncCallback callback, object stateObject, CommandBehavior behavior) { Bid.CorrelationTrace(" ObjectID%d#, behavior=%d{ds.CommandBehavior}, ActivityID %ls\n", ObjectID, (int)behavior); SqlConnection.ExecutePermission.Demand(); - return BeginExecuteReaderInternal(behavior, callback, stateObject, 0); + return BeginExecuteReaderInternal(behavior, callback, stateObject, 0, inRetry: false); } internal SqlDataReader ExecuteReader(CommandBehavior behavior, string method) { @@ -1967,6 +2060,7 @@ namespace System.Data.SqlClient { private SqlDataReader EndExecuteReaderAsync(IAsyncResult asyncResult) { Bid.CorrelationTrace(" ObjectID%d#, ActivityID %ls\n", ObjectID); + Debug.Assert(!_internalEndExecuteInitiated || _stateObj == null); Exception asyncException = ((Task)asyncResult).Exception; if (asyncException != null) { @@ -1977,8 +2071,14 @@ namespace System.Data.SqlClient { else { ThrowIfReconnectionHasBeenCanceled(); // lock on _stateObj prevents ----s with close/cancel. - lock (_stateObj) { + // If we have already initiate the End call internally, we have already done that, so no point doing it again. + if (!_internalEndExecuteInitiated) { + lock (_stateObj) { return EndExecuteReaderInternal(asyncResult); + } + } + else { + return EndExecuteReaderInternal(asyncResult); } } } @@ -1989,7 +2089,7 @@ namespace System.Data.SqlClient { int? sqlExceptionNumber = null; try { statistics = SqlStatistics.StartTimer(Statistics); - SqlDataReader result = InternalEndExecuteReader(asyncResult, ADP.EndExecuteReader); + SqlDataReader result = InternalEndExecuteReader(asyncResult, ADP.EndExecuteReader, isInternal: false); success = true; return result; } @@ -2020,26 +2120,33 @@ namespace System.Data.SqlClient { } private IAsyncResult BeginExecuteReaderAsync(CommandBehavior behavior, AsyncCallback callback, object stateObject) { - return BeginExecuteReaderInternal(behavior, callback, stateObject, CommandTimeout, asyncWrite:true); + return BeginExecuteReaderInternal(behavior, callback, stateObject, CommandTimeout, inRetry: false, asyncWrite:true); } - private IAsyncResult BeginExecuteReaderInternal(CommandBehavior behavior, AsyncCallback callback, object stateObject, int timeout, bool asyncWrite = false) { - // Reset _pendingCancel upon entry into any Execute - used to synchronize state - // between entry into Execute* API and the thread obtaining the stateObject. - _pendingCancel = false; + private IAsyncResult BeginExecuteReaderInternal(CommandBehavior behavior, AsyncCallback callback, object stateObject, int timeout, bool inRetry, bool asyncWrite = false) { + TaskCompletionSource globalCompletion = new TaskCompletionSource(stateObject); + TaskCompletionSource localCompletion = new TaskCompletionSource(stateObject); + + if (!inRetry) { + // Reset _pendingCancel upon entry into any Execute - used to synchronize state + // between entry into Execute* API and the thread obtaining the stateObject. + _pendingCancel = false; + } SqlStatistics statistics = null; try { - statistics = SqlStatistics.StartTimer(Statistics); - WriteBeginExecuteEvent(); - TaskCompletionSource completion = new TaskCompletionSource(stateObject); - - ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj - // back into pool when we should not. + if (!inRetry) { + statistics = SqlStatistics.StartTimer(Statistics); + WriteBeginExecuteEvent(); + ValidateAsyncCommand(); // Special case - done outside of try/catches to prevent putting a stateObj + // back into pool when we should not. + } + + bool usedCache; Task writeTask = null; try { // InternalExecuteNonQuery already has reliability block, but if failure will not put stateObj back into pool. - RunExecuteReader(behavior, RunBehavior.ReturnImmediately, true, ADP.BeginExecuteReader, completion, timeout, out writeTask, asyncWrite); + RunExecuteReader(behavior, RunBehavior.ReturnImmediately, true, ADP.BeginExecuteReader, localCompletion, timeout, out writeTask, out usedCache, asyncWrite, inRetry); } catch (Exception e) { if (!ADP.IsCatchableOrSecurityExceptionType(e)) { @@ -2053,23 +2160,128 @@ namespace System.Data.SqlClient { } if (writeTask != null ) { - AsyncHelper.ContinueTask(writeTask,completion,()=> BeginExecuteReaderInternalReadStage(completion)); + AsyncHelper.ContinueTask(writeTask, localCompletion, () => BeginExecuteReaderInternalReadStage(localCompletion)); } else { - BeginExecuteReaderInternalReadStage(completion); + BeginExecuteReaderInternalReadStage(localCompletion); + } + + // When we use query caching for parameter encryption we need to retry on specific errors. + // In these cases finalize the call internally and trigger a retry when needed. + if (!TriggerInternalEndAndRetryIfNecessary(behavior, stateObject, timeout, ADP.EndExecuteReader, usedCache, inRetry, asyncWrite, globalCompletion, localCompletion, InternalEndExecuteReader, BeginExecuteReaderInternal)) { + globalCompletion = localCompletion; } // Add callback after work is done to avoid overlapping Begin\End methods if (callback != null) { - completion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default); + globalCompletion.Task.ContinueWith((t) => callback(t), TaskScheduler.Default); } - return completion.Task; + + return globalCompletion.Task; } finally { SqlStatistics.StopTimer(statistics); } } + private bool TriggerInternalEndAndRetryIfNecessary(CommandBehavior behavior, object stateObject, int timeout, string endMethod, bool usedCache, bool inRetry, bool asyncWrite, TaskCompletionSource globalCompletion, TaskCompletionSource localCompletion, Func endFunc, Func retryFunc) { + // We shouldn't be using the cache if we are in retry. + Debug.Assert(!usedCache || !inRetry); + + // If column ecnryption is enabled and we used the cache, we want to catch any potential exceptions that were caused by the query cache and retry if the error indicates that we should. + // So, try to read the result of the query before completing the overall task and trigger a retry if appropriate. + if ((IsColumnEncryptionEnabled && !inRetry && usedCache) +#if DEBUG + || _forceInternalEndQuery +#endif + ) { + long firstAttemptStart = ADP.TimerCurrent(); + + localCompletion.Task.ContinueWith(tsk => { + if (tsk.IsFaulted) { + globalCompletion.TrySetException(tsk.Exception.InnerException); + } + else if (tsk.IsCanceled) { + globalCompletion.TrySetCanceled(); + } + else { + try { + // Mark that we initiated the internal EndExecute. This should always be false until we set it here. + Debug.Assert(!_internalEndExecuteInitiated); + _internalEndExecuteInitiated = true; + + // lock on _stateObj prevents ----s with close/cancel. + lock (_stateObj) { + endFunc(tsk, endMethod, true/*inInternal*/); + } + globalCompletion.TrySetResult(tsk.Result); + } + catch (Exception e) { + // Put the state object back to the cache. + // Do not reset the async state, since this is managed by the user Begin/End and not internally. + if (ADP.IsCatchableExceptionType(e)) { + ReliablePutStateObject(); + } + + bool shouldRetry = false; + + // Check if we have an error indicating that we can retry. + if (e is SqlException) { + SqlException sqlEx = e as SqlException; + + for (int i = 0; i < sqlEx.Errors.Count; i++) { + if (sqlEx.Errors[i].Number == TdsEnums.TCE_CONVERSION_ERROR_CLIENT_RETRY) { + shouldRetry = true; + break; + } + } + } + + if (!shouldRetry) { + // If we cannot retry, Reset the async state to make sure we leave a clean state. + if (null != _cachedAsyncState) { + _cachedAsyncState.ResetAsyncState(); + } + _activeConnection.GetOpenTdsConnection().DecrementAsyncCount(); + + globalCompletion.TrySetException(e); + } + else { + // Remove the enrty from the cache since it was inconsistent. + SqlQueryMetadataCache.GetInstance().InvalidateCacheEntry(this); + + try { + // Kick off the retry. + _internalEndExecuteInitiated = false; + Task retryTask = (Task)retryFunc(behavior, null, stateObject, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), true/*inRetry*/, asyncWrite); + + retryTask.ContinueWith(retryTsk => { + if (retryTsk.IsFaulted) { + globalCompletion.TrySetException(retryTsk.Exception.InnerException); + } + else if (retryTsk.IsCanceled) { + globalCompletion.TrySetCanceled(); + } + else { + globalCompletion.TrySetResult(retryTsk.Result); + } + }, TaskScheduler.Default); + } + catch (Exception e2) { + globalCompletion.TrySetException(e2); + } + } + } + } + }, TaskScheduler.Default); + + return true; + } + else { + return false; + } + } + private void BeginExecuteReaderInternalReadStage(TaskCompletionSource completion) { Debug.Assert(completion != null,"CompletionSource should not be null"); // Read SNI does not have catches for async exceptions, handle here. @@ -2123,26 +2335,15 @@ namespace System.Data.SqlClient { } } - private SqlDataReader InternalEndExecuteReader(IAsyncResult asyncResult, string endMethod) { - - VerifyEndExecuteState((Task) asyncResult, endMethod); - WaitForAsyncResults(asyncResult); + private SqlDataReader InternalEndExecuteReader(IAsyncResult asyncResult, string endMethod, bool isInternal) { + + VerifyEndExecuteState((Task)asyncResult, endMethod); + WaitForAsyncResults(asyncResult, isInternal); - // If Transparent parameter encryption was attempted, then we would have skipped the below - // checks in VerifyEndExecuteState since we wanted to wait for WaitForAsyncResults to complete. + // If column encryption is enabled, also check the state after waiting for the task. + // It would be better to do this for all cases, but avoiding for compatibility reasons. if (IsColumnEncryptionEnabled) { - if (cachedAsyncState.EndMethodName == null) { - throw ADP.MethodCalledTwice(endMethod); - } - - if (endMethod != cachedAsyncState.EndMethodName) { - throw ADP.MismatchedAsyncResult(cachedAsyncState.EndMethodName, endMethod); - } - - if (!cachedAsyncState.IsActiveConnectionValid(_activeConnection)) { - // If the connection is not 'valid' then it was closed while we were executing - throw ADP.ClosedConnectionError(); - } + VerifyEndExecuteState((Task)asyncResult, endMethod, fullCheckForColumnEncryption: true); } CheckThrowSNIException(); @@ -2160,7 +2361,7 @@ namespace System.Data.SqlClient { { #endif //DEBUG bestEffortCleanupTarget = SqlInternalConnection.GetBestEffortCleanupTarget(_activeConnection); - SqlDataReader reader = CompleteAsyncExecuteReader(); + SqlDataReader reader = CompleteAsyncExecuteReader(isInternal); Debug.Assert(null == _stateObj, "non-null state object in InternalEndExecuteReader"); return reader; } @@ -2188,7 +2389,7 @@ namespace System.Data.SqlClient { public override Task ExecuteNonQueryAsync(CancellationToken cancellationToken) { Bid.CorrelationTrace(" ObjectID%d#, ActivityID %ls\n", ObjectID); - SqlConnection.ExecutePermission.Demand(); + SqlConnection.ExecutePermission.Demand(); TaskCompletionSource source = new TaskCompletionSource(); @@ -2220,7 +2421,7 @@ namespace System.Data.SqlClient { } } }, TaskScheduler.Default); - } + } catch (Exception e) { source.SetException(e); } @@ -2252,7 +2453,7 @@ namespace System.Data.SqlClient { new public Task ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken) { Bid.CorrelationTrace(" ObjectID%d#, behavior=%d{ds.CommandBehavior}, ActivityID %ls\n", ObjectID, (int)behavior); - SqlConnection.ExecutePermission.Demand(); + SqlConnection.ExecutePermission.Demand(); TaskCompletionSource source = new TaskCompletionSource(); @@ -2264,12 +2465,12 @@ namespace System.Data.SqlClient { } registration = cancellationToken.Register(CancelIgnoreFailure); } - + Task returnedTask = source.Task; try { RegisterForConnectionCloseNotification(ref returnedTask); - Task.Factory.FromAsync(BeginExecuteReaderAsync, EndExecuteReaderAsync, behavior, null).ContinueWith((t) => { + Task.Factory.FromAsync(BeginExecuteReaderAsync, EndExecuteReaderAsync, behavior, null).ContinueWith((t) => { registration.Dispose(); if (t.IsFaulted) { Exception e = t.Exception.InnerException; @@ -2284,7 +2485,7 @@ namespace System.Data.SqlClient { } } }, TaskScheduler.Default); - } + } catch (Exception e) { source.SetException(e); } @@ -2356,8 +2557,8 @@ namespace System.Data.SqlClient { public Task ExecuteXmlReaderAsync(CancellationToken cancellationToken) { Bid.CorrelationTrace(" ObjectID%d#, ActivityID %ls\n", ObjectID); - SqlConnection.ExecutePermission.Demand(); - + SqlConnection.ExecutePermission.Demand(); + TaskCompletionSource source = new TaskCompletionSource(); CancellationTokenRegistration registration = new CancellationTokenRegistration(); @@ -2368,7 +2569,7 @@ namespace System.Data.SqlClient { } registration = cancellationToken.Register(CancelIgnoreFailure); } - + Task returnedTask = source.Task; try { RegisterForConnectionCloseNotification(ref returnedTask); @@ -2388,7 +2589,7 @@ namespace System.Data.SqlClient { } } }, TaskScheduler.Default); - } + } catch (Exception e) { source.SetException(e); } @@ -2882,6 +3083,9 @@ namespace System.Data.SqlClient { GetStateObject(); + // Reset the encryption state in case it has been set by a previous command. + ResetEncryptionState(); + // we just send over the raw text with no annotation // no parameters are sent over // no data reader is returned @@ -2993,6 +3197,12 @@ namespace System.Data.SqlClient { // First reset the command level state. ClearDescribeParameterEncryptionRequests(); + // Reset the state for internal End execution. + _internalEndExecuteInitiated = false; + + // Reset the state for the cache. + CachingQueryMetadataPostponed = false; + // Reset the state of each of the parameters. if (_parameters != null) { for (int i = 0; i < _parameters.Count; i++) { @@ -3047,13 +3257,13 @@ namespace System.Data.SqlClient { /// /// /// - private void PrepareForTransparentEncryption(CommandBehavior cmdBehavior, bool returnStream, bool async, int timeout, TaskCompletionSource completion, out Task returnTask, bool asyncWrite) - { + private void PrepareForTransparentEncryption(CommandBehavior cmdBehavior, bool returnStream, bool async, int timeout, TaskCompletionSource completion, out Task returnTask, bool asyncWrite, out bool usedCache, bool inRetry) { // Fetch reader with input params Task fetchInputParameterEncryptionInfoTask = null; bool describeParameterEncryptionNeeded = false; SqlDataReader describeParameterEncryptionDataReader = null; returnTask = null; + usedCache = false; Debug.Assert(_activeConnection != null, "_activeConnection should not be null in PrepareForTransparentEncryption."); Debug.Assert(_activeConnection.Parser != null, "_activeConnection.Parser should not be null in PrepareForTransparentEncryption."); @@ -3064,11 +3274,18 @@ namespace System.Data.SqlClient { "ColumnEncryption setting should be enabled for input parameter encryption."); Debug.Assert(async == (completion != null), "completion should can be null if and only if mode is async."); + // If we are not in Batch RPC and not already retrying, attempt to fetch the cipher MD for each parameter from the cache. + // If this succeeds then return immediately, otherwise just fall back to the full crypto MD discovery. + if (!BatchRPCMode && !inRetry && SqlQueryMetadataCache.GetInstance().GetQueryMetadataIfExists(this)) { + usedCache = true; + return; + } + // A flag to indicate if finallyblock needs to execute. bool processFinallyBlock = true; // A flag to indicate if we need to decrement async count on the connection in finally block. - bool decrementAsyncCountInFinallyBlock = async; + bool decrementAsyncCountInFinallyBlock = false; // Flag to indicate if exception is caught during the execution, to govern clean up. bool exceptionCaught = false; @@ -3118,6 +3335,9 @@ namespace System.Data.SqlClient { return; } + // If we are in async execution, we need to decrement our async count on exception. + decrementAsyncCountInFinallyBlock = async; + Debug.Assert(describeParameterEncryptionDataReader != null, "describeParameterEncryptionDataReader should not be null, as it is required to get results of describe parameter encryption."); @@ -3128,6 +3348,7 @@ namespace System.Data.SqlClient { processFinallyBlock = false; returnTask = AsyncHelper.CreateContinuationTask(fetchInputParameterEncryptionInfoTask, () => { bool processFinallyBlockAsync = true; + bool decrementAsyncCountInFinallyBlockAsync = true; RuntimeHelpers.PrepareConstrainedRegions(); try { @@ -3143,14 +3364,13 @@ namespace System.Data.SqlClient { // If it is async, then TryFetchInputParameterEncryptionInfo-> RunExecuteReaderTds would have incremented the async count. // Decrement it when we are about to complete async execute reader. SqlInternalConnectionTds internalConnectionTds = _activeConnection.GetOpenTdsConnection(); - if (internalConnectionTds != null) - { + if (internalConnectionTds != null) { internalConnectionTds.DecrementAsyncCount(); - decrementAsyncCountInFinallyBlock = false; + decrementAsyncCountInFinallyBlockAsync = false; } // Complete executereader. - describeParameterEncryptionDataReader = CompleteAsyncExecuteReader(); + describeParameterEncryptionDataReader = CompleteAsyncExecuteReader(forDescribeParameterEncryption: true); Debug.Assert(null == _stateObj, "non-null state object in PrepareForTransparentEncryption."); // Read the results of describe parameter encryption. @@ -3173,7 +3393,7 @@ namespace System.Data.SqlClient { } finally { PrepareTransparentEncryptionFinallyBlock( closeDataReader: processFinallyBlockAsync, - decrementAsyncCount: decrementAsyncCountInFinallyBlock, + decrementAsyncCount: decrementAsyncCountInFinallyBlockAsync, clearDataStructures: processFinallyBlockAsync, wasDescribeParameterEncryptionNeeded: describeParameterEncryptionNeeded, describeParameterEncryptionRpcOriginalRpcMap: describeParameterEncryptionRpcOriginalRpcMap, @@ -3187,6 +3407,8 @@ namespace System.Data.SqlClient { if (exception != null) { throw exception; }})); + + decrementAsyncCountInFinallyBlock = false; } else { // If it was async, ending the reader is still pending. @@ -3196,6 +3418,7 @@ namespace System.Data.SqlClient { processFinallyBlock = false; returnTask = Task.Run(() => { bool processFinallyBlockAsync = true; + bool decrementAsyncCountInFinallyBlockAsync = true; RuntimeHelpers.PrepareConstrainedRegions(); try { @@ -3214,11 +3437,11 @@ namespace System.Data.SqlClient { SqlInternalConnectionTds internalConnectionTds = _activeConnection.GetOpenTdsConnection(); if (internalConnectionTds != null) { internalConnectionTds.DecrementAsyncCount(); - decrementAsyncCountInFinallyBlock = false; + decrementAsyncCountInFinallyBlockAsync = false; } // Complete executereader. - describeParameterEncryptionDataReader = CompleteAsyncExecuteReader(); + describeParameterEncryptionDataReader = CompleteAsyncExecuteReader(forDescribeParameterEncryption: true); Debug.Assert(null == _stateObj, "non-null state object in PrepareForTransparentEncryption."); // Read the results of describe parameter encryption. @@ -3242,13 +3465,15 @@ namespace System.Data.SqlClient { } finally { PrepareTransparentEncryptionFinallyBlock( closeDataReader: processFinallyBlockAsync, - decrementAsyncCount: decrementAsyncCountInFinallyBlock, + decrementAsyncCount: decrementAsyncCountInFinallyBlockAsync, clearDataStructures: processFinallyBlockAsync, wasDescribeParameterEncryptionNeeded: describeParameterEncryptionNeeded, describeParameterEncryptionRpcOriginalRpcMap: describeParameterEncryptionRpcOriginalRpcMap, describeParameterEncryptionDataReader: describeParameterEncryptionDataReader); } }); + + decrementAsyncCountInFinallyBlock = false; } else { // For synchronous execution, read the results of describe parameter encryption here. @@ -3413,6 +3638,7 @@ namespace System.Data.SqlClient { timeout: timeout, task: out task, asyncWrite: asyncWrite, + inRetry: false, ds: null, describeParameterEncryptionRequest: true); } @@ -3494,6 +3720,13 @@ namespace System.Data.SqlClient { SqlParameter param = originalRpcRequest.parameters[i]; paramCopy = new SqlParameter(param.ParameterName, param.SqlDbType, param.Size, param.Direction, param.Precision, param.Scale, param.SourceColumn, param.SourceVersion, param.SourceColumnNullMapping, param.Value, param.XmlSchemaCollectionDatabase, param.XmlSchemaCollectionOwningSchema, param.XmlSchemaCollectionName); + paramCopy.CompareInfo = param.CompareInfo; + paramCopy.TypeName = param.TypeName; + paramCopy.UdtTypeName = param.UdtTypeName; + paramCopy.IsNullable = param.IsNullable; + paramCopy.LocaleId = param.LocaleId; + paramCopy.Offset = param.Offset; + tempCollection.Add(paramCopy); } @@ -3715,18 +3948,25 @@ namespace System.Data.SqlClient { } } } + + // If we are not in Batch RPC mode, update the query cache with the encryption MD. + if (!BatchRPCMode) { + SqlQueryMetadataCache.GetInstance().AddQueryMetadata(this, ignoreQueriesWithReturnValueParams: true); + } } internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, string method) { Task unused; // sync execution - SqlDataReader reader = RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, completion:null, timeout:CommandTimeout, task:out unused); + bool usedCache; + SqlDataReader reader = RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, completion: null, timeout: CommandTimeout, task: out unused, usedCache: out usedCache); Debug.Assert(unused == null, "returned task during synchronous execution"); return reader; } // task is created in case of pending asynchronous write, returned SqlDataReader should not be utilized until that task is complete - internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, string method, TaskCompletionSource completion, int timeout, out Task task, bool asyncWrite = false) { + internal SqlDataReader RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, string method, TaskCompletionSource completion, int timeout, out Task task, out bool usedCache, bool asyncWrite = false, bool inRetry = false) { bool async = (null != completion); + usedCache = false; task = null; @@ -3740,7 +3980,10 @@ namespace System.Data.SqlClient { // @devnote: this function may throw for an invalid connection // @devnote: returns false for empty command text - ValidateCommand(method, async); + if (!inRetry) { + ValidateCommand(method, async); + } + CheckNotificationStateAndAutoEnlist(); // Only call after validate - requires non null connection! TdsParser bestEffortCleanupTarget = null; @@ -3777,14 +4020,46 @@ namespace System.Data.SqlClient { } else if (IsColumnEncryptionEnabled) { Task returnTask = null; - PrepareForTransparentEncryption(cmdBehavior, returnStream, async, timeout, completion, out returnTask, asyncWrite && async); - Debug.Assert(async == (returnTask != null), @"returnTask should be null if and only if async is false."); + PrepareForTransparentEncryption(cmdBehavior, returnStream, async, timeout, completion, out returnTask, asyncWrite && async, out usedCache, inRetry); + Debug.Assert(usedCache || (async == (returnTask != null)), @"if we didn't use the cache, returnTask should be null if and only if async is false."); + + long firstAttemptStart = ADP.TimerCurrent(); - return RunExecuteReaderTdsWithTransparentParameterEncryption( cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, ds: null, - describeParameterEncryptionRequest: false, describeParameterEncryptionTask: returnTask); + try { + return RunExecuteReaderTdsWithTransparentParameterEncryption(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, inRetry: inRetry, ds: null, + describeParameterEncryptionRequest: false, describeParameterEncryptionTask: returnTask); + } + catch (SqlException ex) { + // We only want to retry once, so don't retry if we are already in retry. + // If we didn't use the cache, we don't want to retry. + // The async retried are handled separately, handle only [....] calls here. + if (inRetry || async || !usedCache) { + throw; + } + + bool shouldRetry = false; + + // Check if we have an error indicating that we can retry. + for (int i = 0; i < ex.Errors.Count; i++) { + if (ex.Errors[i].Number == TdsEnums.TCE_CONVERSION_ERROR_CLIENT_RETRY) { + shouldRetry = true; + break; + } + } + + if (!shouldRetry) { + throw; + } + else { + // Retry if the command failed with appropriate error. + // First invalidate the entry from the cache, so that we refresh our encryption MD. + SqlQueryMetadataCache.GetInstance().InvalidateCacheEntry(this); + return RunExecuteReader(cmdBehavior, runBehavior, returnStream, method, null, TdsParserStaticMethods.GetRemainingTimeout(timeout, firstAttemptStart), out task, out usedCache, async, inRetry: true); + } + } } else { - return RunExecuteReaderTds( cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async); + return RunExecuteReaderTds( cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite && async, inRetry: inRetry); } } @@ -3830,11 +4105,11 @@ namespace System.Data.SqlClient { int timeout, out Task task, bool asyncWrite, + bool inRetry, SqlDataReader ds=null, bool describeParameterEncryptionRequest = false, Task describeParameterEncryptionTask = null) { Debug.Assert(!asyncWrite || async, "AsyncWrite should be always accompanied by Async"); - Debug.Assert((describeParameterEncryptionTask != null) == async, @"async should be true if and only if describeParameterEncryptionTask is not null."); if (ds == null && returnStream) { ds = new SqlDataReader(this, cmdBehavior); @@ -3842,40 +4117,42 @@ namespace System.Data.SqlClient { if (describeParameterEncryptionTask != null) { long parameterEncryptionStart = ADP.TimerCurrent(); - TaskCompletionSource completion = new TaskCompletionSource(); - AsyncHelper.ContinueTask(describeParameterEncryptionTask, completion, - () => { - Task subTask = null; - RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, TdsParserStaticMethods.GetRemainingTimeout(timeout, parameterEncryptionStart), out subTask, asyncWrite, ds); - if (subTask == null) { - completion.SetResult(null); - } - else { - AsyncHelper.ContinueTask(subTask, completion, () => completion.SetResult(null)); - } - }, connectionToDoom: null, - onFailure: ((exception) => { - if (_cachedAsyncState != null) { - _cachedAsyncState.ResetAsyncState(); - } - if (exception != null) { - throw exception; - }}), - onCancellation: (() => { - if (_cachedAsyncState != null) { - _cachedAsyncState.ResetAsyncState(); - }}), - connectionToAbort: _activeConnection); - task = completion.Task; - return ds; + TaskCompletionSource completion = new TaskCompletionSource(); + AsyncHelper.ContinueTask(describeParameterEncryptionTask, completion, + () => { + Task subTask = null; + RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, TdsParserStaticMethods.GetRemainingTimeout(timeout, parameterEncryptionStart), out subTask, asyncWrite, inRetry, ds); + if (subTask == null) { + completion.SetResult(null); + } + else { + AsyncHelper.ContinueTask(subTask, completion, () => completion.SetResult(null)); + } + }, connectionToDoom: null, + onFailure: ((exception) => { + if (_cachedAsyncState != null) { + _cachedAsyncState.ResetAsyncState(); + } + if (exception != null) { + throw exception; + } + }), + onCancellation: (() => { + if (_cachedAsyncState != null) { + _cachedAsyncState.ResetAsyncState(); + } + }), + connectionToAbort: _activeConnection); + task = completion.Task; + return ds; } else { // Synchronous execution. - return RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite, ds); + return RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, timeout, out task, asyncWrite, inRetry, ds); } } - private SqlDataReader RunExecuteReaderTds( CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, bool async, int timeout, out Task task, bool asyncWrite, SqlDataReader ds=null, bool describeParameterEncryptionRequest = false) { + private SqlDataReader RunExecuteReaderTds( CommandBehavior cmdBehavior, RunBehavior runBehavior, bool returnStream, bool async, int timeout, out Task task, bool asyncWrite, bool inRetry, SqlDataReader ds=null, bool describeParameterEncryptionRequest = false) { Debug.Assert(!asyncWrite || async, "AsyncWrite should be always accompanied by Async"); if (ds == null && returnStream) { @@ -3900,7 +4177,7 @@ namespace System.Data.SqlClient { Interlocked.CompareExchange(ref _reconnectionCompletionSource, null, completion); timeoutCTS.Cancel(); Task subTask; - RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, TdsParserStaticMethods.GetRemainingTimeout(timeout, reconnectionStart), out subTask, asyncWrite, ds); + RunExecuteReaderTds(cmdBehavior, runBehavior, returnStream, async, TdsParserStaticMethods.GetRemainingTimeout(timeout, reconnectionStart), out subTask, asyncWrite, inRetry, ds); if (subTask == null) { completion.SetResult(null); } @@ -3933,7 +4210,8 @@ namespace System.Data.SqlClient { bool processFinallyBlock = true; bool decrementAsyncCountOnFailure = false; - if (async) { + // If we are in retry, don't increment the Async count. This should have already been set. + if (async && !inRetry) { _activeConnection.GetOpenTdsConnection().IncrementAsyncCount(); decrementAsyncCountOnFailure = true; } @@ -4077,7 +4355,7 @@ namespace System.Data.SqlClient { } else { // Always execute - even if no reader! - FinishExecuteReader(ds, runBehavior, optionSettings); + FinishExecuteReader(ds, runBehavior, optionSettings, isInternal: false, forDescribeParameterEncryption: false); } } catch (Exception e) { @@ -4177,11 +4455,11 @@ namespace System.Data.SqlClient { return ds; } - private SqlDataReader CompleteAsyncExecuteReader() { + private SqlDataReader CompleteAsyncExecuteReader(bool isInternal = false, bool forDescribeParameterEncryption = false) { SqlDataReader ds = cachedAsyncState.CachedAsyncReader; // should not be null bool processFinallyBlock = true; try { - FinishExecuteReader(ds, cachedAsyncState.CachedRunBehavior, cachedAsyncState.CachedSetOptions); + FinishExecuteReader(ds, cachedAsyncState.CachedRunBehavior, cachedAsyncState.CachedSetOptions, isInternal, forDescribeParameterEncryption); } catch (Exception e) { processFinallyBlock = ADP.IsCatchableExceptionType(e); @@ -4190,7 +4468,11 @@ namespace System.Data.SqlClient { finally { TdsParser.ReliabilitySection.Assert("unreliable call to CompleteAsyncExecuteReader"); // you need to setup for a thread abort somewhere before you call this method if (processFinallyBlock) { - cachedAsyncState.ResetAsyncState(); + // Don't reset the state for internal End. The user End will do that eventually. + if (!isInternal) { + cachedAsyncState.ResetAsyncState(); + } + PutStateObject(); } } @@ -4198,10 +4480,19 @@ namespace System.Data.SqlClient { return ds; } - private void FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, string resetOptionsString) { + private void FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, string resetOptionsString, bool isInternal, bool forDescribeParameterEncryption) { // always wrap with a try { FinishExecuteReader(...) } finally { PutStateObject(); } - NotifyDependency(); + // If this is not for internal usage, notify the dependency. If we have already initiated the end internally, the reader should be ready, so just return. + if (!isInternal && !forDescribeParameterEncryption) { + NotifyDependency(); + + if (_internalEndExecuteInitiated) { + Debug.Assert(_stateObj == null); + return; + } + } + if (runBehavior == RunBehavior.UntilDone) { try { bool dataReady; @@ -4618,6 +4909,14 @@ namespace System.Data.SqlClient { parameter.Value = status; } + + // If we are not in Batch RPC mode, update the query cache with the encryption MD. + // We can do this now that we have distinguished between ReturnValue and ReturnStatus. + // Read comment in AddQueryMetadata() for more details. + if (!BatchRPCMode && CachingQueryMetadataPostponed) { + SqlQueryMetadataCache.GetInstance().AddQueryMetadata(this, ignoreQueriesWithReturnValueParams: false); + } + break; } } diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnection.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnection.cs index 0ce4dbb0876..306a4207980 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnection.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnection.cs @@ -88,7 +88,51 @@ namespace System.Data.SqlClient return _ColumnEncryptionTrustedMasterKeyPaths; } } - + + /// + /// Defines whether query metadata caching is enabled. + /// + static private bool _ColumnEncryptionQueryMetadataCacheEnabled = true; + + [ + DefaultValue(null), + ResCategoryAttribute(Res.DataCategory_Data), + ResDescriptionAttribute(Res.TCE_SqlConnection_ColumnEncryptionQueryMetadataCacheEnabled), + ] + static public bool ColumnEncryptionQueryMetadataCacheEnabled + { + get + { + return _ColumnEncryptionQueryMetadataCacheEnabled; + } + set + { + _ColumnEncryptionQueryMetadataCacheEnabled = value; + } + } + + /// + /// Defines whether query metadata caching is enabled. + /// + static private TimeSpan _ColumnEncryptionKeyCacheTtl = TimeSpan.FromHours(2); + + [ + DefaultValue(null), + ResCategoryAttribute(Res.DataCategory_Data), + ResDescriptionAttribute(Res.TCE_SqlConnection_ColumnEncryptionKeyCacheTtl), + ] + static public TimeSpan ColumnEncryptionKeyCacheTtl + { + get + { + return _ColumnEncryptionKeyCacheTtl; + } + set + { + _ColumnEncryptionKeyCacheTtl = value; + } + } + /// /// This function should only be called once in an app. This does shallow copying of the dictionary so that /// the app cannot alter the custom provider list once it has been set. @@ -437,7 +481,15 @@ namespace System.Data.SqlClient get { return ((SqlConnectionString)ConnectionOptions).TypeSystemAssemblyVersion; } - } + } + + internal PoolBlockingPeriod PoolBlockingPeriod + { + get + { + return ((SqlConnectionString)ConnectionOptions).PoolBlockingPeriod; + } + } internal int ConnectRetryInterval { get { diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionString.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionString.cs index 85ed1b7bbf0..1dd74aec96b 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionString.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionString.cs @@ -30,6 +30,7 @@ namespace System.Data.SqlClient { internal const string Application_Name = TdsEnums.SQL_PROVIDER_NAME; internal const bool Asynchronous = false; internal const string AttachDBFilename = ""; + internal const PoolBlockingPeriod PoolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod; internal const int Connect_Timeout = ADP.DefaultConnectionTimeout; internal const bool Connection_Reset = true; internal const bool Context_Connection = false; @@ -69,6 +70,7 @@ namespace System.Data.SqlClient { internal const string Application_Name = "application name"; internal const string AsynchronousProcessing = "asynchronous processing"; internal const string AttachDBFilename = "attachdbfilename"; + internal const string PoolBlockingPeriod = "poolblockingperiod"; internal const string ColumnEncryptionSetting = "column encryption setting"; internal const string Connect_Timeout = "connect timeout"; internal const string Connection_Reset = "connection reset"; @@ -190,6 +192,7 @@ namespace System.Data.SqlClient { private readonly bool _integratedSecurity; + private readonly PoolBlockingPeriod _poolBlockingPeriod; private readonly bool _connectionReset; private readonly bool _contextConnection; private readonly bool _encrypt; @@ -247,6 +250,7 @@ namespace System.Data.SqlClient { ConvertValueToBoolean(KEY.AsynchronousProcessing, DEFAULT.Asynchronous); // while we don't use it anymore, we still need to verify it is true/false // SQLPT 41700: Ignore ResetConnection=False (still validate the keyword/value) + _poolBlockingPeriod = ConvertValueToPoolBlockingPeriod(); _connectionReset = ConvertValueToBoolean(KEY.Connection_Reset, DEFAULT.Connection_Reset); _contextConnection = ConvertValueToBoolean(KEY.Context_Connection, DEFAULT.Context_Connection); _encrypt = ConvertValueToEncrypt(); @@ -490,6 +494,7 @@ namespace System.Data.SqlClient { _userInstance = userInstance; _connectTimeout = connectionOptions._connectTimeout; _loadBalanceTimeout = connectionOptions._loadBalanceTimeout; + _poolBlockingPeriod = connectionOptions._poolBlockingPeriod; _maxPoolSize = connectionOptions._maxPoolSize; _minPoolSize = connectionOptions._minPoolSize; _multiSubnetFailover = connectionOptions._multiSubnetFailover; @@ -525,6 +530,8 @@ namespace System.Data.SqlClient { // will work. In the future we can deprecate the keyword entirely. internal bool Asynchronous { get { return true; } } + internal PoolBlockingPeriod PoolBlockingPeriod { get { return _poolBlockingPeriod; } } + // SQLPT 41700: Ignore ResetConnection=False, always reset the connection for security internal bool ConnectionReset { get { return true; } } internal bool ContextConnection { get { return _contextConnection; } } @@ -620,6 +627,7 @@ namespace System.Data.SqlClient { hash.Add(KEY.Application_Name, KEY.Application_Name); hash.Add(KEY.AsynchronousProcessing, KEY.AsynchronousProcessing); hash.Add(KEY.AttachDBFilename, KEY.AttachDBFilename); + hash.Add(KEY.PoolBlockingPeriod, KEY.PoolBlockingPeriod); hash.Add(KEY.Connect_Timeout, KEY.Connect_Timeout); hash.Add(KEY.Connection_Reset, KEY.Connection_Reset); hash.Add(KEY.Context_Connection, KEY.Context_Connection); @@ -779,6 +787,28 @@ namespace System.Data.SqlClient { // ArgumentException and other types are raised as is (no wrapping) } + internal System.Data.SqlClient.PoolBlockingPeriod ConvertValueToPoolBlockingPeriod() + { + object value = base.Parsetable[KEY.PoolBlockingPeriod]; + if (value == null) + { + return DEFAULT.PoolBlockingPeriod; + } + + try + { + return DbConnectionStringBuilderUtil.ConvertToPoolBlockingPeriod(KEY.PoolBlockingPeriod, value); + } + catch (FormatException e) + { + throw ADP.InvalidConnectionOptionValue(KEY.PoolBlockingPeriod, e); + } + catch (OverflowException e) + { + throw ADP.InvalidConnectionOptionValue(KEY.PoolBlockingPeriod, e); + } + } + internal SqlAuthenticationMethod ConvertValueToAuthenticationType() { object value = base.Parsetable[KEY.Authentication]; diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionStringBuilder.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionStringBuilder.cs index 8e7714341c4..ae3c2b1e67e 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionStringBuilder.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionStringBuilder.cs @@ -41,6 +41,7 @@ namespace System.Data.SqlClient { Pooling, MinPoolSize, MaxPoolSize, + PoolBlockingPeriod, AsynchronousProcessing, ConnectionReset, @@ -127,6 +128,7 @@ namespace System.Data.SqlClient { private bool _userInstance = DbConnectionStringDefaults.UserInstance; private SqlAuthenticationMethod _authentication = DbConnectionStringDefaults.Authentication; private SqlConnectionColumnEncryptionSetting _columnEncryptionSetting = DbConnectionStringDefaults.ColumnEncryptionSetting; + private PoolBlockingPeriod _poolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod; static SqlConnectionStringBuilder() { string[] validKeywords = new string[KeywordsCount]; @@ -134,6 +136,7 @@ namespace System.Data.SqlClient { validKeywords[(int)Keywords.ApplicationName] = DbConnectionStringKeywords.ApplicationName; validKeywords[(int)Keywords.AsynchronousProcessing] = DbConnectionStringKeywords.AsynchronousProcessing; validKeywords[(int)Keywords.AttachDBFilename] = DbConnectionStringKeywords.AttachDBFilename; + validKeywords[(int)Keywords.PoolBlockingPeriod] = DbConnectionStringKeywords.PoolBlockingPeriod; validKeywords[(int)Keywords.ConnectionReset] = DbConnectionStringKeywords.ConnectionReset; validKeywords[(int)Keywords.ContextConnection] = DbConnectionStringKeywords.ContextConnection; validKeywords[(int)Keywords.ConnectTimeout] = DbConnectionStringKeywords.ConnectTimeout; @@ -174,6 +177,7 @@ namespace System.Data.SqlClient { hash.Add(DbConnectionStringKeywords.ApplicationName, Keywords.ApplicationName); hash.Add(DbConnectionStringKeywords.AsynchronousProcessing, Keywords.AsynchronousProcessing); hash.Add(DbConnectionStringKeywords.AttachDBFilename, Keywords.AttachDBFilename); + hash.Add(DbConnectionStringKeywords.PoolBlockingPeriod, Keywords.PoolBlockingPeriod); hash.Add(DbConnectionStringKeywords.ConnectTimeout, Keywords.ConnectTimeout); hash.Add(DbConnectionStringKeywords.ConnectionReset, Keywords.ConnectionReset); hash.Add(DbConnectionStringKeywords.ContextConnection, Keywords.ContextConnection); @@ -278,6 +282,7 @@ namespace System.Data.SqlClient { case Keywords.Authentication: Authentication = ConvertToAuthenticationType(keyword, value); break; case Keywords.ColumnEncryptionSetting: ColumnEncryptionSetting = ConvertToColumnEncryptionSetting(keyword, value); break; case Keywords.AsynchronousProcessing: AsynchronousProcessing = ConvertToBoolean(value); break; + case Keywords.PoolBlockingPeriod: PoolBlockingPeriod = ConvertToPoolBlockingPeriod(keyword, value); break; #pragma warning disable 618 // Obsolete ConnectionReset case Keywords.ConnectionReset: ConnectionReset = ConvertToBoolean(value); break; #pragma warning restore 618 @@ -360,6 +365,25 @@ namespace System.Data.SqlClient { } } + [DisplayName(DbConnectionStringKeywords.PoolBlockingPeriod)] + [ResCategoryAttribute(Res.DataCategory_Pooling)] + [ResDescriptionAttribute(Res.DbConnectionString_PoolBlockingPeriod)] + [RefreshPropertiesAttribute(RefreshProperties.All)] + public PoolBlockingPeriod PoolBlockingPeriod + { + get { return _poolBlockingPeriod; } + set + { + if (!DbConnectionStringBuilderUtil.IsValidPoolBlockingPeriodValue(value)) + { + throw ADP.InvalidEnumerationValue(typeof(PoolBlockingPeriod), (int)value); + } + + SetPoolBlockingPeriodValue(value); + _poolBlockingPeriod = value; + } + } + [Browsable(false)] [DisplayName(DbConnectionStringKeywords.ConnectionReset)] [Obsolete("ConnectionReset has been deprecated. SqlConnection will ignore the 'connection reset' keyword and always reset the connection")] // SQLPT 41700 @@ -881,6 +905,10 @@ namespace System.Data.SqlClient { private static SqlAuthenticationMethod ConvertToAuthenticationType(string keyword, object value) { return DbConnectionStringBuilderUtil.ConvertToAuthenticationType(keyword, value); } + private static PoolBlockingPeriod ConvertToPoolBlockingPeriod(string keyword, object value) + { + return DbConnectionStringBuilderUtil.ConvertToPoolBlockingPeriod(keyword, value); + } /// /// Convert to SqlConnectionColumnEncryptionSetting. @@ -906,6 +934,7 @@ namespace System.Data.SqlClient { case Keywords.ApplicationName: return ApplicationName; case Keywords.AsynchronousProcessing: return AsynchronousProcessing; case Keywords.AttachDBFilename: return AttachDBFilename; + case Keywords.PoolBlockingPeriod: return PoolBlockingPeriod; case Keywords.ConnectTimeout: return ConnectTimeout; #pragma warning disable 618 // Obsolete ConnectionReset case Keywords.ConnectionReset: return ConnectionReset; @@ -1012,6 +1041,10 @@ namespace System.Data.SqlClient { case Keywords.Authentication: _authentication = DbConnectionStringDefaults.Authentication; break; + case Keywords.PoolBlockingPeriod: + _poolBlockingPeriod = DbConnectionStringDefaults.PoolBlockingPeriod; + break; + case Keywords.ConnectTimeout: _connectTimeout = DbConnectionStringDefaults.ConnectTimeout; break; @@ -1128,6 +1161,11 @@ namespace System.Data.SqlClient { Debug.Assert(DbConnectionStringBuilderUtil.IsValidApplicationIntentValue(value), "Invalid value for ApplicationIntent"); base[DbConnectionStringKeywords.ApplicationIntent] = DbConnectionStringBuilderUtil.ApplicationIntentToString(value); } + private void SetPoolBlockingPeriodValue(PoolBlockingPeriod value) + { + Debug.Assert(DbConnectionStringBuilderUtil.IsValidPoolBlockingPeriodValue(value), "Invalid value for PoolBlockingPeriod"); + base[DbConnectionStringKeywords.PoolBlockingPeriod] = DbConnectionStringBuilderUtil.PoolBlockingPeriodToString(value); + } private void SetAuthenticationValue(SqlAuthenticationMethod value) { Debug.Assert(DbConnectionStringBuilderUtil.IsValidAuthenticationTypeValue(value), "Invalid value for AuthenticationType"); base[DbConnectionStringKeywords.Authentication] = DbConnectionStringBuilderUtil.AuthenticationTypeToString(value); diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionTimeoutErrorInternal.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionTimeoutErrorInternal.cs index 879a86d61a8..0e799476baf 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionTimeoutErrorInternal.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlConnectionTimeoutErrorInternal.cs @@ -207,10 +207,10 @@ namespace System.Data.SqlClient durationString = null; break; } - + // This message is to be added only when within the various stages of a connection. // In all other cases, it will default to the original error message. - if ((currentPhase != SqlConnectionTimeoutErrorPhase.Undefined) || (currentPhase != SqlConnectionTimeoutErrorPhase.Complete)) + if ((currentPhase != SqlConnectionTimeoutErrorPhase.Undefined) && (currentPhase != SqlConnectionTimeoutErrorPhase.Complete)) { // NOTE: In case of a failover scenario, add a string that this failure occured as part of the primary or secondary server if (isFailoverScenario) @@ -229,13 +229,13 @@ namespace System.Data.SqlClient originalPhaseDurations[(int)SqlConnectionTimeoutErrorPhase.ProcessConnectionAuth].GetMilliSecondDuration(), originalPhaseDurations[(int)SqlConnectionTimeoutErrorPhase.PostLogin].GetMilliSecondDuration()); } + } - // NOTE: To display duration in each phase. - if (durationString != null) - { - errorBuilder.Append(" "); - errorBuilder.Append(durationString); - } + // NOTE: To display duration in each phase. + if (durationString != null) + { + errorBuilder.Append(" "); + errorBuilder.Append(durationString); } return errorBuilder.ToString(); diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlInternalConnectionTds.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlInternalConnectionTds.cs index c07b195ac1b..376909b9abd 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlInternalConnectionTds.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlInternalConnectionTds.cs @@ -889,6 +889,7 @@ namespace System.Data.SqlClient } internal void DecrementAsyncCount() { + Debug.Assert(_asyncCommandCount > 0); Interlocked.Decrement(ref _asyncCommandCount); } diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlParameter.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlParameter.cs index 9b238a47061..81274a6b846 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlParameter.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlParameter.cs @@ -99,9 +99,6 @@ namespace System.Data.SqlClient { } set { - Debug.Assert(_columnEncryptionCipherMetadata == null || value == null, - "_columnEncryptionCipherMetadata should be set to a non-null value only once."); - _columnEncryptionCipherMetadata = value; } } diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlSymmetricKeyCache.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlSymmetricKeyCache.cs index fa371fb7222..8df0617428c 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlSymmetricKeyCache.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlSymmetricKeyCache.cs @@ -13,18 +13,19 @@ namespace System.Data.SqlClient { using System.Diagnostics; using System.Globalization; using System.Linq; + using System.Runtime.Caching; using System.Text; /// /// Implements a cache of Symmetric Keys (once they are decrypted).Useful for rapidly decrypting multiple data values. /// sealed internal class SqlSymmetricKeyCache { - private readonly ConcurrentDictionary _cache; + private readonly MemoryCache _cache; private static readonly SqlSymmetricKeyCache _singletonInstance = new SqlSymmetricKeyCache(); private SqlSymmetricKeyCache () { - _cache = new ConcurrentDictionary(concurrencyLevel: 4 * Environment.ProcessorCount /* default value in ConcurrentDictionary*/, capacity: 2); + _cache = new MemoryCache("ColumnEncryptionKeyCache"); } internal static SqlSymmetricKeyCache GetInstance () { @@ -54,10 +55,10 @@ namespace System.Data.SqlClient { Debug.Assert(cacheLookupKey.Length <= capacity, "We needed to allocate a larger array"); #endif //DEBUG - encryptionKey = null; - // Lookup the key in cache - if (!_cache.TryGetValue(cacheLookupKey, out encryptionKey)) { + encryptionKey = _cache.Get(cacheLookupKey) as SqlClientSymmetricKey; + + if (encryptionKey == null) { Debug.Assert(SqlConnection.ColumnEncryptionTrustedMasterKeyPaths != null, @"SqlConnection.ColumnEncryptionTrustedMasterKeyPaths should not be null"); // Check against the trusted key paths @@ -96,9 +97,13 @@ namespace System.Data.SqlClient { encryptionKey = new SqlClientSymmetricKey (plaintextKey); - // In case multiple threads reach here at the same time, the first one wins. - // The allocated memory will be reclaimed by Garbage Collector. - _cache.TryAdd(cacheLookupKey, encryptionKey); + // If the cache TTL is zero, don't even bother inserting to the cache. + if (SqlConnection.ColumnEncryptionKeyCacheTtl != TimeSpan.Zero) { + // In case multiple threads reach here at the same time, the first one wins. + // The allocated memory will be reclaimed by Garbage Collector. + DateTimeOffset expirationTime = DateTimeOffset.UtcNow.Add(SqlConnection.ColumnEncryptionKeyCacheTtl); + _cache.Add(cacheLookupKey, encryptionKey, expirationTime); + } } return true; diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlUtil.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlUtil.cs index ae7086f0a06..a15b1893767 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlUtil.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/SqlUtil.cs @@ -1543,7 +1543,7 @@ namespace System.Data.SqlClient { return Res.GetString(Res.SQL_SSPIGenerateError); } static internal string Timeout() { - return Res.GetString(Res.SQL_Timeout); + return Res.GetString(Res.SQL_Timeout_Execution); } static internal string Timeout_PreLogin_Begin() { return Res.GetString(Res.SQL_Timeout_PreLogin_Begin); diff --git a/mcs/class/referencesource/System.Data/System/Data/SqlClient/TdsEnums.cs b/mcs/class/referencesource/System.Data/System/Data/SqlClient/TdsEnums.cs index 319e252b21b..11e3cdd98ef 100644 --- a/mcs/class/referencesource/System.Data/System/Data/SqlClient/TdsEnums.cs +++ b/mcs/class/referencesource/System.Data/System/Data/SqlClient/TdsEnums.cs @@ -544,6 +544,9 @@ namespace System.Data.SqlClient { public const int IMPERSONATION_FAILED = 1346; public const int P_TOKENTOOLONG = 103; + // SQL error that indicates retry for Always Encrypted + public const int TCE_CONVERSION_ERROR_CLIENT_RETRY = 33514; + // SNI\Win32 error values // NOTE: these are simply windows system error codes, not SNI specific public const uint SNI_UNINITIALIZED = unchecked((uint)-1); diff --git a/mcs/class/referencesource/System.Data/System/NewXml/XPathNodePointer.cs b/mcs/class/referencesource/System.Data/System/NewXml/XPathNodePointer.cs index f8f3d1d95c5..1af6e149ac5 100644 --- a/mcs/class/referencesource/System.Data/System/NewXml/XPathNodePointer.cs +++ b/mcs/class/referencesource/System.Data/System/NewXml/XPathNodePointer.cs @@ -883,7 +883,6 @@ namespace System.Xml { RealFoliate(); AssertValid(); if ( NodeType == XPathNodeType.Namespace ) { - Debug.Assert( _parentOfNS != null ); MoveTo( _parentOfNS ); return true; } diff --git a/mcs/class/referencesource/System.IdentityModel/InternalApis/Clr/inc/AppContextDefaultValues.cs b/mcs/class/referencesource/System.IdentityModel/InternalApis/Clr/inc/AppContextDefaultValues.cs index 8a130a0f342..9224bf8b8fb 100644 --- a/mcs/class/referencesource/System.IdentityModel/InternalApis/Clr/inc/AppContextDefaultValues.cs +++ b/mcs/class/referencesource/System.IdentityModel/InternalApis/Clr/inc/AppContextDefaultValues.cs @@ -3,6 +3,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== + +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + using System; using System.Collections.Generic; @@ -167,3 +176,5 @@ namespace System static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version); } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/System.IdentityModel/InternalApis/Clr/inc/LocalAppContext.cs b/mcs/class/referencesource/System.IdentityModel/InternalApis/Clr/inc/LocalAppContext.cs index f05b599ed3d..33662b54280 100644 --- a/mcs/class/referencesource/System.IdentityModel/InternalApis/Clr/inc/LocalAppContext.cs +++ b/mcs/class/referencesource/System.IdentityModel/InternalApis/Clr/inc/LocalAppContext.cs @@ -4,6 +4,14 @@ // // ==--== +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + // NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches using System; using System.Collections.Generic; @@ -126,3 +134,5 @@ namespace System } } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/Claims/X509CertificateClaimSet.cs b/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/Claims/X509CertificateClaimSet.cs index 4113bd328c7..7561fffb97f 100644 --- a/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/Claims/X509CertificateClaimSet.cs +++ b/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/Claims/X509CertificateClaimSet.cs @@ -5,12 +5,14 @@ namespace System.IdentityModel.Claims { using System.Collections.Generic; + using System.Diagnostics; using System.IdentityModel.Policy; using System.Net.Mail; using System.Security.Claims; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Principal; + using Globalization; public class X509CertificateClaimSet : ClaimSet, IIdentityInfo, IDisposable { @@ -172,24 +174,7 @@ namespace System.IdentityModel.Claims if (!string.IsNullOrEmpty(value)) claims.Add(Claim.CreateX500DistinguishedNameClaim(this.certificate.SubjectName)); - // App context switch for disabling support for multiple dns entries in a SAN certificate - if (LocalAppContextSwitches.DisableMultipleDNSEntriesInSANCertificate) - { - // old behavior, default for <= 4.6 - value = this.certificate.GetNameInfo(X509NameType.DnsName, false); - if (!string.IsNullOrEmpty(value)) - claims.Add(Claim.CreateDnsClaim(value)); - } - else - { - // new behavior as this is the default long term behavior - // Since a SAN can have multiple DNS entries - string[] entries = GetDnsFromExtensions(this.certificate); - for (int i = 0; i < entries.Length; ++i) - { - claims.Add(Claim.CreateDnsClaim(entries[i])); - } - } + claims.AddRange(GetDnsClaims(this.certificate)); value = this.certificate.GetNameInfo(X509NameType.SimpleName, false); if (!string.IsNullOrEmpty(value)) @@ -258,25 +243,8 @@ namespace System.IdentityModel.Claims { if (right == null || Rights.PossessProperty.Equals(right)) { - // App context switch for disabling support for multiple dns entries in a SAN certificate - if (LocalAppContextSwitches.DisableMultipleDNSEntriesInSANCertificate) - { - // old behavior, default for <= 4.6 - string value = this.certificate.GetNameInfo(X509NameType.DnsName, false); - if (!string.IsNullOrEmpty(value)) - { - yield return Claim.CreateDnsClaim(value); - } - } - else - { - // new behavior since this is the default long term behavior - string[] entries = GetDnsFromExtensions(certificate); - for (int i = 0; i < entries.Length; ++i) - { - yield return Claim.CreateDnsClaim(entries[i]); - } - } + foreach (var claim in GetDnsClaims(certificate)) + yield return claim; } } else @@ -299,31 +267,44 @@ namespace System.IdentityModel.Claims } } - // Fixing Bug 795660: SAN having multiple DNS entries - private static string[] GetDnsFromExtensions(X509Certificate2 cert) + private static List GetDnsClaims(X509Certificate2 cert) { - foreach (X509Extension ext in cert.Extensions) + List dnsClaimEntries = new List(); + + // old behavior, default for <= 4.6 + string value = cert.GetNameInfo(X509NameType.DnsName, false); + if (!string.IsNullOrEmpty(value)) + dnsClaimEntries.Add(Claim.CreateDnsClaim(value)); + + // App context switch for disabling support for multiple dns entries in a SAN certificate + // If we can't dynamically parse the alt subject names, we will not add any dns claims ONLY for the alt subject names. + // In this way, if the X509NameType.DnsName was enough to succeed for the out-bound-message. We would have a success. + if (!LocalAppContextSwitches.DisableMultipleDNSEntriesInSANCertificate && X509SubjectAlternativeNameConstants.SuccessfullyInitialized) { - // Extension is SAN or SAN2 - if (ext.Oid.Value == "2.5.29.7" || ext.Oid.Value == "2.5.29.17") + foreach (X509Extension ext in cert.Extensions) { - string asnString = ext.Format(true); - if (string.IsNullOrEmpty(asnString)) + // Extension is SAN or SAN2 + if (ext.Oid.Value == X509SubjectAlternativeNameConstants.SanOid || ext.Oid.Value == X509SubjectAlternativeNameConstants.San2Oid) { - return new string[0]; - } - - string[] rawDnsEntries = asnString.Split(new string[1] { "\n" }, StringSplitOptions.RemoveEmptyEntries); - string[] dnsEntries = new string[rawDnsEntries.Length]; - for (int i = 0; i < rawDnsEntries.Length; ++i) - { - int equalSignIndex = rawDnsEntries[i].IndexOf('='); - dnsEntries[i] = rawDnsEntries[i].Substring(equalSignIndex + 1).Trim(); + string asnString = ext.Format(false); + if (string.IsNullOrWhiteSpace(asnString)) + break; + + // SubjectAlternativeNames might contain something other than a dNSName, + // so we have to parse through and only use the dNSNames + // + string[] rawDnsEntries = asnString.Split(X509SubjectAlternativeNameConstants.SeparatorArray, StringSplitOptions.RemoveEmptyEntries); + for (int i = 0; i < rawDnsEntries.Length; i++) + { + string[] keyval = rawDnsEntries[i].Split(X509SubjectAlternativeNameConstants.Delimiter); + if (string.Equals(keyval[0], X509SubjectAlternativeNameConstants.Identifier)) + dnsClaimEntries.Add(Claim.CreateDnsClaim(keyval[1])); + } } - return dnsEntries; } } - return new string[0]; + + return dnsClaimEntries; } public override IEnumerator GetEnumerator() @@ -367,6 +348,107 @@ namespace System.IdentityModel.Claims get { return this.identity; } } } + + // We don't have a strongly typed extension to parse Subject Alt Names, so we have to do a workaround + // to figure out what the identifier, delimiter, and separator is by using a well-known extension + private static class X509SubjectAlternativeNameConstants + { + public const string SanOid = "2.5.29.7"; + public const string San2Oid = "2.5.29.17"; + + public static string Identifier + { + get; + private set; + } + + public static char Delimiter + { + get; + private set; + } + + public static string Separator + { + get; + private set; + } + + public static string[] SeparatorArray + { + get; + private set; + } + + public static bool SuccessfullyInitialized + { + get; + private set; + } + + // static initializer will run before properties are accessed + static X509SubjectAlternativeNameConstants() + { + // Extracted a well-known X509Extension + byte[] x509ExtensionBytes = new byte[] { + 48, 36, 130, 21, 110, 111, 116, 45, 114, 101, 97, 108, 45, 115, 117, 98, 106, 101, 99, + 116, 45, 110, 97, 109, 101, 130, 11, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109 + }; + const string subjectName = "not-real-subject-name"; + string x509ExtensionFormattedString = string.Empty; + try + { + X509Extension x509Extension = new X509Extension(SanOid, x509ExtensionBytes, true); + x509ExtensionFormattedString = x509Extension.Format(false); + + // Each OS has a different dNSName identifier and delimiter + // On Windows, dNSName == "DNS Name" (localizable), on Linux, dNSName == "DNS" + // e.g., + // Windows: x509ExtensionFormattedString is: "DNS Name=not-real-subject-name, DNS Name=example.com" + // Linux: x509ExtensionFormattedString is: "DNS:not-real-subject-name, DNS:example.com" + // Parse: + + int delimiterIndex = x509ExtensionFormattedString.IndexOf(subjectName) - 1; + Delimiter = x509ExtensionFormattedString[delimiterIndex]; + + // Make an assumption that all characters from the the start of string to the delimiter + // are part of the identifier + Identifier = x509ExtensionFormattedString.Substring(0, delimiterIndex); + + int separatorFirstChar = delimiterIndex + subjectName.Length + 1; + int separatorLength = 1; + for (int i = separatorFirstChar + 1; i < x509ExtensionFormattedString.Length; i++) + { + // We advance until the first character of the identifier to determine what the + // separator is. This assumes that the identifier assumption above is correct + if (x509ExtensionFormattedString[i] == Identifier[0]) + { + break; + } + + separatorLength++; + } + + Separator = x509ExtensionFormattedString.Substring(separatorFirstChar, separatorLength); + SeparatorArray = new string[1] { Separator }; + SuccessfullyInitialized = true; + } + catch (Exception ex) + { + SuccessfullyInitialized = false; + DiagnosticUtility.TraceHandledException( + new FormatException(string.Format(CultureInfo.InvariantCulture, + "There was an error parsing the SubjectAlternativeNames: '{0}'. See inner exception for more details.{1}Detected values were: Identifier: '{2}'; Delimiter:'{3}'; Separator:'{4}'", + x509ExtensionFormattedString, + Environment.NewLine, + Identifier, + Delimiter, + Separator), + ex), + TraceEventType.Warning); + } + } + } } class X509Identity : GenericIdentity, IDisposable diff --git a/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/LocalAppContextSwitches.cs b/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/LocalAppContextSwitches.cs index f18ab5dd582..b6bc822248a 100644 --- a/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/LocalAppContextSwitches.cs +++ b/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/LocalAppContextSwitches.cs @@ -15,9 +15,11 @@ namespace System.IdentityModel { private const string EnableCachedEmptyDefaultAuthorizationContextString = "Switch.System.IdentityModel.EnableCachedEmptyDefaultAuthorizationContext"; private const string DisableMultipleDNSEntriesInSANCertificateString = "Switch.System.IdentityModel.DisableMultipleDNSEntriesInSANCertificate"; + private const string DisableUpdatingRsaProviderTypeString = "Switch.System.IdentityModel.DisableUpdatingRsaProviderType"; private static int enableCachedEmptyDefaultAuthorizationContext; private static int disableMultipleDNSEntriesInSANCertificate; + private static int disableUpdatingRsaProviderType; public static bool EnableCachedEmptyDefaultAuthorizationContext { @@ -37,16 +39,29 @@ namespace System.IdentityModel } } + public static bool DisableUpdatingRsaProviderType + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(DisableUpdatingRsaProviderTypeString, ref disableUpdatingRsaProviderType); + } + } + public static void SetDefaultsLessOrEqual_452() { +#pragma warning disable BCL0012 // Define the switches that should be true for 4.5.2 or less, false for 4.6+. LocalAppContext.DefineSwitchDefault(EnableCachedEmptyDefaultAuthorizationContextString, true); +#pragma warning restore BCL0012 } public static void SetDefaultsLessOrEqual_46() { +#pragma warning disable BCL0012 // Define the switches that should be true for 4.6 or less, false for 4.6.1+. LocalAppContext.DefineSwitchDefault(DisableMultipleDNSEntriesInSANCertificateString, true); +#pragma warning restore BCL0012 } } } diff --git a/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/Tokens/X509AsymmetricSecurityKey.cs b/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/Tokens/X509AsymmetricSecurityKey.cs index 397194f6446..fb1918c6ca6 100644 --- a/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/Tokens/X509AsymmetricSecurityKey.cs +++ b/mcs/class/referencesource/System.IdentityModel/System/IdentityModel/Tokens/X509AsymmetricSecurityKey.cs @@ -309,22 +309,26 @@ namespace System.IdentityModel.Tokens { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(algorithm, SR.GetString(SR.EmptyOrNullArgumentString, "algorithm")); } - // We support one of the two algoritms, but not both. + + // We support: // XmlDsigDSAUrl = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; // XmlDsigRSASHA1Url = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; + // RsaSha256Signature = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"; + AsymmetricAlgorithm privateKey = LevelUpRsa(this.PrivateKey, algorithm); + object algorithmObject = CryptoHelper.GetAlgorithmFromConfig(algorithm); if (algorithmObject != null) { SignatureDescription description = algorithmObject as SignatureDescription; if (description != null) - return description.CreateFormatter(this.PrivateKey); + return description.CreateFormatter(privateKey); try { AsymmetricSignatureFormatter asymmetricSignatureFormatter = algorithmObject as AsymmetricSignatureFormatter; if (asymmetricSignatureFormatter != null) { - asymmetricSignatureFormatter.SetKey(this.PrivateKey); + asymmetricSignatureFormatter.SetKey(privateKey); return asymmetricSignatureFormatter; } } @@ -356,19 +360,10 @@ namespace System.IdentityModel.Tokens case SecurityAlgorithms.RsaSha256Signature: // Ensure that we have an RSA algorithm object. - RSACryptoServiceProvider rsa_prov_full = (this.PrivateKey as RSACryptoServiceProvider); - if (rsa_prov_full == null) + RSA rsaSha256 = (privateKey as RSA); + if (rsaSha256 == null) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.PrivateKeyNotRSA))); - CspParameters csp = new CspParameters(); - csp.ProviderType = 24; - csp.KeyContainerName = rsa_prov_full.CspKeyContainerInfo.KeyContainerName; - csp.KeyNumber = (int)rsa_prov_full.CspKeyContainerInfo.KeyNumber; - if (rsa_prov_full.CspKeyContainerInfo.MachineKeyStore) - csp.Flags = CspProviderFlags.UseMachineKeyStore; - - csp.Flags |= CspProviderFlags.UseExistingKey; - - return new RSAPKCS1SignatureFormatter(new RSACryptoServiceProvider(csp)); + return new RSAPKCS1SignatureFormatter(rsaSha256); default: throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SR.GetString(SR.UnsupportedCryptoAlgorithm, algorithm))); @@ -376,6 +371,45 @@ namespace System.IdentityModel.Tokens } + private static AsymmetricAlgorithm LevelUpRsa(AsymmetricAlgorithm asymmetricAlgorithm, string algorithm) + { + // If user turned off leveling up at app level, return + if (LocalAppContextSwitches.DisableUpdatingRsaProviderType) + return asymmetricAlgorithm; + + if (asymmetricAlgorithm == null) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("asymmetricAlgorithm")); + + if (string.IsNullOrEmpty(algorithm)) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(algorithm, SR.GetString(SR.EmptyOrNullArgumentString, "algorithm")); + + // only level up if alg is sha256 + if (!string.Equals(algorithm, SecurityAlgorithms.RsaSha256Signature)) + return asymmetricAlgorithm; + + RSACryptoServiceProvider rsaCsp = asymmetricAlgorithm as RSACryptoServiceProvider; + if (rsaCsp == null) + return asymmetricAlgorithm; + + // ProviderType == 1(PROV_RSA_FULL) and providerType == 12(PROV_RSA_SCHANNEL) are provider types that only support SHA1. Change them to PROV_RSA_AES=24 that supports SHA2 also. + // Only levels up if the associated key is not a hardware key. + // Another provider type related to rsa, PROV_RSA_SIG == 2 that only supports Sha1 is no longer supported + if ((rsaCsp.CspKeyContainerInfo.ProviderType == 1 || rsaCsp.CspKeyContainerInfo.ProviderType == 12) && !rsaCsp.CspKeyContainerInfo.HardwareDevice) + { + CspParameters csp = new CspParameters(); + csp.ProviderType = 24; + csp.KeyContainerName = rsaCsp.CspKeyContainerInfo.KeyContainerName; + csp.KeyNumber = (int)rsaCsp.CspKeyContainerInfo.KeyNumber; + if (rsaCsp.CspKeyContainerInfo.MachineKeyStore) + csp.Flags = CspProviderFlags.UseMachineKeyStore; + + csp.Flags |= CspProviderFlags.UseExistingKey; + return new RSACryptoServiceProvider(csp); + } + + return rsaCsp; + } + public override bool HasPrivateKey() { return (this.PrivateKey != null); diff --git a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/CacheMemoryMonitor.cs b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/CacheMemoryMonitor.cs index 8b32bedf742..05af1435998 100644 --- a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/CacheMemoryMonitor.cs +++ b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/CacheMemoryMonitor.cs @@ -27,7 +27,7 @@ namespace System.Runtime.Caching { private long[] _cacheSizeSamples; private DateTime[] _cacheSizeSampleTimes; private int _idx; - private SRef _sizedRef; + private SRefMultiple _sizedRefMultiple; private int _gen2Count; private long _memoryLimit; @@ -51,7 +51,7 @@ namespace System.Runtime.Caching { private void InitDisposableMembers(int cacheMemoryLimitMegabytes) { bool dispose = true; try { - _sizedRef = new SRef(_memoryCache); + _sizedRefMultiple = new SRefMultiple(_memoryCache.AllSRefTargets); SetLimit(cacheMemoryLimitMegabytes); InitHistory(); dispose = false; @@ -112,8 +112,8 @@ namespace System.Runtime.Caching { } public void Dispose() { - SRef sref = _sizedRef; - if (sref != null && Interlocked.CompareExchange(ref _sizedRef, null, sref) == sref) { + SRefMultiple sref = _sizedRefMultiple; + if (sref != null && Interlocked.CompareExchange(ref _sizedRefMultiple, null, sref) == sref) { sref.Dispose(); } IMemoryCacheManager memoryCacheManager = s_memoryCacheManager; @@ -139,7 +139,7 @@ namespace System.Runtime.Caching { // This update must happen, otherwise the CacheManager won't // know the total cache size. int gen2Count = GC.CollectionCount(2); - SRef sref = _sizedRef; + SRefMultiple sref = _sizedRefMultiple; if (gen2Count != _gen2Count && sref != null) { // update _gen2Count _gen2Count = gen2Count; diff --git a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCache.cs b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCache.cs index 816319755cb..f74996a20e1 100644 --- a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCache.cs +++ b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCache.cs @@ -27,9 +27,8 @@ namespace System.Runtime.Caching { private static object s_initLock = new object(); private static MemoryCache s_defaultCache; private static CacheEntryRemovedCallback s_sentinelRemovedCallback = new CacheEntryRemovedCallback(SentinelEntry.OnCacheEntryRemovedCallback); - private MemoryCacheStore[] _stores; + private GCHandleRef[] _storeRefs; private int _storeCount; - private int _storeMask; private int _disposed; private MemoryCacheStatistics _stats; private string _name; @@ -150,8 +149,18 @@ namespace System.Runtime.Caching { if (hashCode < 0) { hashCode = (hashCode == Int32.MinValue) ? 0 : -hashCode; } - int idx = hashCode & _storeMask; - return _stores[idx]; + int idx = hashCode % _storeCount; + return _storeRefs[idx].Target; + } + + internal object[] AllSRefTargets { + get { + var allStores = new MemoryCacheStore[_storeCount]; + for (int i = 0; i < _storeCount; i++) { + allStores[i] = _storeRefs[i].Target; + } + return allStores; + } } [SecuritySafeCritical] @@ -166,8 +175,8 @@ namespace System.Runtime.Caching { catch { // ignore exceptions from perf counters } - for (int i = 0; i < _stores.Length; i++) { - _stores[i] = new MemoryCacheStore(this, _perfCounters); + for (int i = 0; i < _storeCount; i++) { + _storeRefs[i] = new GCHandleRef (new MemoryCacheStore(this, _perfCounters)); } _stats = new MemoryCacheStatistics(this, config); AppDomain appDomain = Thread.GetDomain(); @@ -321,8 +330,7 @@ namespace System.Runtime.Caching { } } #endif - _storeMask = _storeCount - 1; - _stores = new MemoryCacheStore[_storeCount]; + _storeRefs = new GCHandleRef[_storeCount]; InitDisposableMembers(config); } @@ -392,10 +400,10 @@ namespace System.Runtime.Caching { if (_stats != null) { _stats.Dispose(); } - if (_stores != null) { - foreach (MemoryCacheStore store in _stores) { - if (store != null) { - store.Dispose(); + if (_storeRefs != null) { + foreach (var storeRef in _storeRefs) { + if (storeRef != null) { + storeRef.Dispose(); } } } @@ -442,8 +450,8 @@ namespace System.Runtime.Caching { IEnumerator IEnumerable.GetEnumerator() { Hashtable h = new Hashtable(); if (!IsDisposed) { - foreach (MemoryCacheStore store in _stores) { - store.CopyTo(h); + foreach (var storeRef in _storeRefs) { + storeRef.Target.CopyTo(h); } } return h.GetEnumerator(); @@ -452,8 +460,8 @@ namespace System.Runtime.Caching { protected override IEnumerator> GetEnumerator() { Dictionary h = new Dictionary(); if (!IsDisposed) { - foreach (MemoryCacheStore store in _stores) { - store.CopyTo(h); + foreach (var storeRef in _storeRefs) { + storeRef.Target.CopyTo(h); } } return h.GetEnumerator(); @@ -471,8 +479,8 @@ namespace System.Runtime.Caching { } long trimmed = 0; if (_disposed == 0) { - foreach (MemoryCacheStore store in _stores) { - trimmed += store.TrimInternal(percent); + foreach (var storeRef in _storeRefs) { + trimmed += storeRef.Target.TrimInternal(percent); } } return trimmed; @@ -680,8 +688,8 @@ namespace System.Runtime.Caching { } long count = 0; if (!IsDisposed) { - foreach (MemoryCacheStore store in _stores) { - count += store.Count; + foreach (var storeRef in _storeRefs) { + count += storeRef.Target.Count; } } return count; diff --git a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheStatistics.cs b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheStatistics.cs index 61d3ce3ace7..99196c05f5d 100644 --- a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheStatistics.cs +++ b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/MemoryCacheStatistics.cs @@ -27,7 +27,7 @@ namespace System.Runtime.Caching { private int _lastTrimPercent; private DateTime _lastTrimTime; private int _pollingInterval; - private Timer _timer; + private GCHandleRef _timerHandleRef; private Object _timerLock; private long _totalCountBeforeTrim; @@ -44,16 +44,18 @@ namespace System.Runtime.Caching { private void AdjustTimer() { lock (_timerLock) { - if (_timer == null) + if (_timerHandleRef == null) return; + Timer timer = _timerHandleRef.Target; + // the order of these if statements is important // When above the high pressure mark, interval should be 5 seconds or less if (_physicalMemoryMonitor.IsAboveHighPressure() || _cacheMemoryMonitor.IsAboveHighPressure()) { if (_pollingInterval > MEMORYSTATUS_INTERVAL_5_SECONDS) { _pollingInterval = MEMORYSTATUS_INTERVAL_5_SECONDS; - _timer.Change(_pollingInterval, _pollingInterval); + timer.Change(_pollingInterval, _pollingInterval); } return; } @@ -65,7 +67,7 @@ namespace System.Runtime.Caching { int newPollingInterval = Math.Min(_configPollingInterval, MEMORYSTATUS_INTERVAL_30_SECONDS); if (_pollingInterval != newPollingInterval) { _pollingInterval = newPollingInterval; - _timer.Change(_pollingInterval, _pollingInterval); + timer.Change(_pollingInterval, _pollingInterval); } return; } @@ -73,7 +75,7 @@ namespace System.Runtime.Caching { // there is no pressure, interval should be the value from config if (_pollingInterval != _configPollingInterval) { _pollingInterval = _configPollingInterval; - _timer.Change(_pollingInterval, _pollingInterval); + timer.Change(_pollingInterval, _pollingInterval); } } } @@ -126,7 +128,8 @@ namespace System.Runtime.Caching { bool dispose = true; try { _cacheMemoryMonitor = new CacheMemoryMonitor(_memoryCache, _configCacheMemoryLimitMegabytes); - _timer = new Timer(new TimerCallback(CacheManagerTimerCallback), null, _configPollingInterval, _configPollingInterval); + Timer timer = new Timer(new TimerCallback(CacheManagerTimerCallback), null, _configPollingInterval, _configPollingInterval); + _timerHandleRef = new GCHandleRef(timer); dispose = false; } finally { @@ -246,9 +249,9 @@ namespace System.Runtime.Caching { public void Dispose() { if (Interlocked.Exchange(ref _disposed, 1) == 0) { lock (_timerLock) { - Timer timer = _timer; - if (timer != null && Interlocked.CompareExchange(ref _timer, null, timer) == timer) { - timer.Dispose(); + GCHandleRef timerHandleRef = _timerHandleRef; + if (timerHandleRef != null && Interlocked.CompareExchange(ref _timerHandleRef, null, timerHandleRef) == timerHandleRef) { + timerHandleRef.Dispose(); Dbg.Trace("MemoryCacheStats", "Stopped CacheMemoryTimers"); } } diff --git a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/SRef.cs b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/SRef.cs index 27ee134e46e..50374308baf 100644 --- a/mcs/class/referencesource/System.Runtime.Caching/System/Caching/SRef.cs +++ b/mcs/class/referencesource/System.Runtime.Caching/System/Caching/SRef.cs @@ -7,24 +7,33 @@ using System.Reflection; using System.Security; using System.Security.Permissions; using System.Diagnostics.CodeAnalysis; +using System.Runtime.InteropServices; namespace System.Runtime.Caching { internal class SRef { +#if !MONO private static Type s_type = Type.GetType("System.SizedReference", true, false); private Object _sizedRef; +#endif internal SRef(Object target) { +#if !MONO _sizedRef = Activator.CreateInstance(s_type, BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.CreateInstance, null, new object[] { target }, null); +#endif } internal long ApproximateSize { [SecuritySafeCritical] [PermissionSet(SecurityAction.Assert, Unrestricted = true)] get { +#if MONO + // TODO: .net uses System.SizedReference which contains approximate size after Gen 2 collection + return 16; +#else object o = s_type.InvokeMember("ApproximateSize", BindingFlags.Public | BindingFlags.Instance | BindingFlags.GetProperty, null, // binder @@ -32,6 +41,7 @@ namespace System.Runtime.Caching { null, // args CultureInfo.InvariantCulture); return (long)o; +#endif } } @@ -40,12 +50,87 @@ namespace System.Runtime.Caching { [SecuritySafeCritical] [PermissionSet(SecurityAction.Assert, Unrestricted = true)] internal void Dispose() { +#if !MONO s_type.InvokeMember("Dispose", BindingFlags.Public | BindingFlags.Instance | BindingFlags.InvokeMethod, null, // binder _sizedRef, // target null, // args CultureInfo.InvariantCulture); +#endif + } + } + + internal class SRefMultiple { + private SRef[] _srefs; + private long[] _sizes; // Getting SRef size in the debugger is extremely tedious so we keep the last read value here + + internal SRefMultiple(object[] targets) { + _srefs = new SRef[targets.Length]; + _sizes = new long[targets.Length]; + for (int i = 0; i < targets.Length; i++) { + _srefs[i] = new SRef(targets[i]); + } + } + + internal long ApproximateSize { + get { + long size = 0; + for (int i = 0; i < _srefs.Length; i++) { + size += (_sizes[i] = _srefs[i].ApproximateSize); + } + return size; + } + } + + internal void Dispose() { + foreach (SRef s in _srefs) { + s.Dispose(); + } + } + } + + internal class GCHandleRef : IDisposable + where T : class, IDisposable { + GCHandle _handle; + T _t; + + [SecuritySafeCritical] + [PermissionSet(SecurityAction.Assert, Unrestricted = true)] + public GCHandleRef(T t) { + _handle = GCHandle.Alloc(t); + } + + public T Target { + [SecuritySafeCritical] + [PermissionSet(SecurityAction.Assert, Unrestricted = true)] + get { + try { + T t = (T)_handle.Target; + if (t != null) { + return t; + } + } + catch (InvalidOperationException) { + // use the normal reference instead of throwing an exception when _handle is already freed + } + return _t; + } + } + + [SecuritySafeCritical] + [PermissionSet(SecurityAction.Assert, Unrestricted = true)] + public void Dispose() { + Target.Dispose(); + // Safe to call Dispose more than once but not thread-safe + if (_handle.IsAllocated) { + // We must free the GC handle to avoid leaks. + // However after _handle is freed we no longer have access to its Target + // which will cause AVs and various race conditions under stress. + // We revert to using normal references after disposing the GC handle + _t = (T)_handle.Target; + _handle.Free(); + } } } } diff --git a/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/DataContract.cs b/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/DataContract.cs index c63c76f9153..2ed1d48643d 100644 --- a/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/DataContract.cs +++ b/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/DataContract.cs @@ -458,7 +458,8 @@ namespace System.Runtime.Serialization if (dataContract == null) { dataContract = CreateGetOnlyCollectionDataContract(id, typeHandle, type); - dataContractCache[id] = dataContract; + + AssignDataContractToId(dataContract, id); } return dataContract; } @@ -480,7 +481,10 @@ namespace System.Runtime.Serialization { return id; } - for (int i = 0; i < DataContractCriticalHelper.dataContractID; i++) + + int currentDataContractId = DataContractCriticalHelper.dataContractID; + + for (int i = 0; i < currentDataContractId; i++) { if (ContractMatches(classContract, dataContractCache[i])) { @@ -542,49 +546,66 @@ namespace System.Runtime.Serialization // check whether a corresponding update is required in ClassDataContract.IsNonAttributedTypeValidForSerialization static DataContract CreateDataContract(int id, RuntimeTypeHandle typeHandle, Type type) { - lock (createDataContractLock) + DataContract dataContract = dataContractCache[id]; + + if (dataContract == null) { - DataContract dataContract = dataContractCache[id]; - if (dataContract == null) + lock (createDataContractLock) { - if (type == null) - type = Type.GetTypeFromHandle(typeHandle); - type = UnwrapNullableType(type); - type = GetDataContractAdapterType(type); - dataContract = GetBuiltInDataContract(type); + dataContract = dataContractCache[id]; + if (dataContract == null) { - if (type.IsArray) - dataContract = new CollectionDataContract(type); - else if (type.IsEnum) - dataContract = new EnumDataContract(type); - else if (type.IsGenericParameter) - dataContract = new GenericParameterDataContract(type); - else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type)) - dataContract = new XmlDataContract(type); - else + if (type == null) + type = Type.GetTypeFromHandle(typeHandle); + type = UnwrapNullableType(type); + type = GetDataContractAdapterType(type); + dataContract = GetBuiltInDataContract(type); + if (dataContract == null) { - //if (type.ContainsGenericParameters) - // ThrowInvalidDataContractException(SR.GetString(SR.TypeMustNotBeOpenGeneric, type), type); - if (type.IsPointer) - type = Globals.TypeOfReflectionPointer; - - if (!CollectionDataContract.TryCreate(type, out dataContract)) + if (type.IsArray) + dataContract = new CollectionDataContract(type); + else if (type.IsEnum) + dataContract = new EnumDataContract(type); + else if (type.IsGenericParameter) + dataContract = new GenericParameterDataContract(type); + else if (Globals.TypeOfIXmlSerializable.IsAssignableFrom(type)) + dataContract = new XmlDataContract(type); + else { - if (type.IsSerializable || type.IsDefined(Globals.TypeOfDataContractAttribute, false) || ClassDataContract.IsNonAttributedTypeValidForSerialization(type)) - { - dataContract = new ClassDataContract(type); - } - else + //if (type.ContainsGenericParameters) + // ThrowInvalidDataContractException(SR.GetString(SR.TypeMustNotBeOpenGeneric, type), type); + if (type.IsPointer) + type = Globals.TypeOfReflectionPointer; + + if (!CollectionDataContract.TryCreate(type, out dataContract)) { - ThrowInvalidDataContractException(SR.GetString(SR.TypeNotSerializable, type), type); + if (type.IsSerializable || type.IsDefined(Globals.TypeOfDataContractAttribute, false) || ClassDataContract.IsNonAttributedTypeValidForSerialization(type)) + { + dataContract = new ClassDataContract(type); + } + else + { + ThrowInvalidDataContractException(SR.GetString(SR.TypeNotSerializable, type), type); + } } } } - } + + AssignDataContractToId(dataContract, id); + } } + } + + return dataContract; + } + + [MethodImpl(MethodImplOptions.NoInlining)] + static void AssignDataContractToId(DataContract dataContract, int id) + { + lock (cacheLock) + { dataContractCache[id] = dataContract; - return dataContract; } } @@ -1200,7 +1221,8 @@ namespace System.Runtime.Serialization parseMethodSet = true; } - return parseMethod; } + return parseMethod; + } } internal virtual void WriteRootElement(XmlWriterDelegator writer, XmlDictionaryString name, XmlDictionaryString ns) diff --git a/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/Json/JsonWriterDelegator.cs b/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/Json/JsonWriterDelegator.cs index 54f0f3fa095..6e0e98201fe 100644 --- a/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/Json/JsonWriterDelegator.cs +++ b/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/Json/JsonWriterDelegator.cs @@ -204,7 +204,15 @@ namespace System.Runtime.Serialization.Json // This will break round-tripping of these dates (see bug 9690 in CSD Developer Framework) if (value.Kind != DateTimeKind.Utc) { - long tickCount = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks; + long tickCount; + if (!LocalAppContextSwitches.DoNotUseTimeZoneInfo) + { + tickCount = value.Ticks - TimeZoneInfo.Local.GetUtcOffset(value).Ticks; + } + else + { + tickCount = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks; + } if ((tickCount > DateTime.MaxValue.Ticks) || (tickCount < DateTime.MinValue.Ticks)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( @@ -220,7 +228,15 @@ namespace System.Runtime.Serialization.Json case DateTimeKind.Unspecified: case DateTimeKind.Local: // +"zzzz"; - TimeSpan ts = TimeZone.CurrentTimeZone.GetUtcOffset(value.ToLocalTime()); + TimeSpan ts; + if (!LocalAppContextSwitches.DoNotUseTimeZoneInfo) + { + ts = TimeZoneInfo.Local.GetUtcOffset(value.ToLocalTime()); + } + else + { + ts = TimeZone.CurrentTimeZone.GetUtcOffset(value.ToLocalTime()); + } if (ts.Ticks < 0) { writer.WriteString("-"); diff --git a/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/SchemaExporter.cs b/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/SchemaExporter.cs index b2c4586e3bb..ff5704a55df 100644 --- a/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/SchemaExporter.cs +++ b/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/SchemaExporter.cs @@ -75,7 +75,7 @@ namespace System.Runtime.Serialization if (!Schemas.Contains(Globals.SerializationNamespace)) { StringReader reader = new StringReader(Globals.SerializationSchema); - XmlSchema schema = XmlSchema.Read(reader, null); + XmlSchema schema = XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); if (schema == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CouldNotReadSerializationSchema, Globals.SerializationNamespace))); Schemas.Add(schema); diff --git a/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/SchemaImporter.cs b/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/SchemaImporter.cs index 32d06e427d2..29885641acc 100644 --- a/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/SchemaImporter.cs +++ b/mcs/class/referencesource/System.Runtime.Serialization/System/Runtime/Serialization/SchemaImporter.cs @@ -51,7 +51,7 @@ namespace System.Runtime.Serialization if (!schemaSet.Contains(Globals.SerializationNamespace)) { StringReader reader = new StringReader(Globals.SerializationSchema); - XmlSchema schema = XmlSchema.Read(reader, null); + XmlSchema schema = XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); if (schema == null) throw System.Runtime.Serialization.DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.CouldNotReadSerializationSchema, Globals.SerializationNamespace))); schemaSet.Add(schema); diff --git a/mcs/class/referencesource/System.ServiceModel.Activation/System/ServiceModel/Activation/HostedAspNetEnvironment.cs b/mcs/class/referencesource/System.ServiceModel.Activation/System/ServiceModel/Activation/HostedAspNetEnvironment.cs index c0dc0f32928..4e785e5b1ff 100644 --- a/mcs/class/referencesource/System.ServiceModel.Activation/System/ServiceModel/Activation/HostedAspNetEnvironment.cs +++ b/mcs/class/referencesource/System.ServiceModel.Activation/System/ServiceModel/Activation/HostedAspNetEnvironment.cs @@ -101,20 +101,13 @@ namespace System.ServiceModel.Activation } } - // Provides the version of the WebSocket protocol supported by IIS. Throws an exception if called before we determined the value. + // Provides the version of the WebSocket protocol supported by IIS. // Returns null if WebSockets are not supported (because the IIS WebSocketModule is not installed or enabled). public override string WebSocketVersion { get { - if (isWebSocketVersionSet) - { - return webSocketVersion; - } - else - { - throw Fx.AssertAndFailFast("The supported WebSocket protocol version is not determined at this time."); - } + return isWebSocketVersionSet ? webSocketVersion : null; } } @@ -136,8 +129,6 @@ namespace System.ServiceModel.Activation /// public static void TrySetWebSocketVersion(HttpApplication application) { - Fx.Assert(application != null, "Invalid argument."); - if (!isWebSocketVersionSet) { webSocketVersion = application.Request.ServerVariables[WebSocketVersionServerProperty]; diff --git a/mcs/class/referencesource/System.ServiceModel.Internals/System/Runtime/Diagnostics/EtwDiagnosticTrace.cs b/mcs/class/referencesource/System.ServiceModel.Internals/System/Runtime/Diagnostics/EtwDiagnosticTrace.cs index 4a81f353ca1..c84160682a5 100644 --- a/mcs/class/referencesource/System.ServiceModel.Internals/System/Runtime/Diagnostics/EtwDiagnosticTrace.cs +++ b/mcs/class/referencesource/System.ServiceModel.Internals/System/Runtime/Diagnostics/EtwDiagnosticTrace.cs @@ -288,6 +288,7 @@ namespace System.Runtime.Diagnostics [Fx.Tag.SecurityNote(Critical = "Usage of EventDescriptor, which is protected by a LinkDemand")] [SecurityCritical] + [SuppressMessage("Microsoft.Security.Xml", "CA3057:DoNotUseLoadXml", Justification = "It is internal code. No security concern.")] public void WriteTraceSource(ref EventDescriptor eventDescriptor, string description, TracePayload payload) { if (this.TracingEnabled) diff --git a/mcs/class/referencesource/System.ServiceModel/InternalApis/Clr/inc/AppContextDefaultValues.cs b/mcs/class/referencesource/System.ServiceModel/InternalApis/Clr/inc/AppContextDefaultValues.cs index 8a130a0f342..9224bf8b8fb 100644 --- a/mcs/class/referencesource/System.ServiceModel/InternalApis/Clr/inc/AppContextDefaultValues.cs +++ b/mcs/class/referencesource/System.ServiceModel/InternalApis/Clr/inc/AppContextDefaultValues.cs @@ -3,6 +3,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== + +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + using System; using System.Collections.Generic; @@ -167,3 +176,5 @@ namespace System static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version); } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/System.ServiceModel/InternalApis/Clr/inc/LocalAppContext.cs b/mcs/class/referencesource/System.ServiceModel/InternalApis/Clr/inc/LocalAppContext.cs index f05b599ed3d..33662b54280 100644 --- a/mcs/class/referencesource/System.ServiceModel/InternalApis/Clr/inc/LocalAppContext.cs +++ b/mcs/class/referencesource/System.ServiceModel/InternalApis/Clr/inc/LocalAppContext.cs @@ -4,6 +4,14 @@ // // ==--== +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + // NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches using System; using System.Collections.Generic; @@ -126,3 +134,5 @@ namespace System } } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/AppContextDefaultValues.Default.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/AppContextDefaultValues.Default.cs index 5f591137e39..e086fad2760 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/AppContextDefaultValues.Default.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/AppContextDefaultValues.Default.cs @@ -27,6 +27,11 @@ namespace System LocalAppContextSwitches.SetDefaultsLessOrEqual_452(); } + if (version <= 40601) + { + LocalAppContextSwitches.SetDefaultsLessOrEqual_461(); + } + break; } } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/HttpChannelListener.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/HttpChannelListener.cs index 785a9c05951..5dac93babe1 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/HttpChannelListener.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/HttpChannelListener.cs @@ -839,17 +839,11 @@ namespace System.ServiceModel.Channels { AspNetEnvironment env = AspNetEnvironment.Current; - // When IIS hosted, WebSockets can be used if the pipeline mode is integrated and the WebSocketModule is loaded. - // Otherwise, the client requests will not be upgraded to web sockets (see the code in HostedHttpTransportManager.HttpContextReceived(..)). - // We do the checks below (and fail the service activation), to avoid starting a WebSockets listener that won't get called. + // When IIS hosted, WebSockets can be used if the pipeline mode is integrated if (!env.UsingIntegratedPipeline) { throw FxTrace.Exception.AsError(new NotSupportedException(SR.GetString(SR.WebSocketsNotSupportedInClassicPipeline))); } - else if (!env.IsWebSocketModuleLoaded) - { - throw FxTrace.Exception.AsError(new NotSupportedException(SR.GetString(SR.WebSocketModuleNotLoaded))); - } } else if (!WebSocketHelper.OSSupportsWebSockets()) { diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/PipeConnection.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/PipeConnection.cs index f50e3667174..ee3fbc127a7 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/PipeConnection.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/PipeConnection.cs @@ -6,6 +6,7 @@ namespace System.ServiceModel.Channels { using System.Collections.Generic; using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Net; @@ -1684,6 +1685,9 @@ namespace System.ServiceModel.Channels // then the Exact HostName, and lastly the WeakWildcard string[] hostChoices = new string[] { "+", uri.Host, "*" }; bool[] globalChoices = new bool[] { true, false }; + string matchPath = String.Empty; + string matchPipeName = null; + for (int i = 0; i < hostChoices.Length; i++) { for (int iGlobal = 0; iGlobal < globalChoices.Length; iGlobal++) @@ -1696,7 +1700,7 @@ namespace System.ServiceModel.Channels continue; } - // walk up the path hierarchy, looking for first match + // walk up the path hierarchy, looking for match string path = PipeUri.GetPath(uri); while (path.Length > 0) @@ -1713,7 +1717,21 @@ namespace System.ServiceModel.Channels string pipeName = sharedMemory.GetPipeName(appInfo); if (pipeName != null) { - return pipeName; + // Found a matching pipe name. + // If the best match app setting is enabled, save the match if it is the best so far and continue. + // Otherwise, just return the first match we find. + if (ServiceModelAppSettings.UseBestMatchNamedPipeUri) + { + if (path.Length > matchPath.Length) + { + matchPath = path; + matchPipeName = pipeName; + } + } + else + { + return pipeName; + } } } finally @@ -1733,9 +1751,14 @@ namespace System.ServiceModel.Channels } } - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( - new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, uri.AbsoluteUri), - new PipeException(SR.GetString(SR.PipeEndpointNotFound, uri.AbsoluteUri)))); + if (string.IsNullOrEmpty(matchPipeName)) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( + new EndpointNotFoundException(SR.GetString(SR.EndpointNotFound, uri.AbsoluteUri), + new PipeException(SR.GetString(SR.PipeEndpointNotFound, uri.AbsoluteUri)))); + } + + return matchPipeName; } public IAsyncResult BeginConnect(Uri uri, TimeSpan timeout, AsyncCallback callback, object state) @@ -1758,7 +1781,6 @@ namespace System.ServiceModel.Channels new StringTraceRecord("Uri", remoteUri.ToString()), this, null); } resolvedAddress = GetPipeName(remoteUri, this.pipeSettings); - const int backoffBufferMilliseconds = 150; TimeSpan backoffTimeout; if (timeout >= TimeSpan.FromMilliseconds(backoffBufferMilliseconds * 2)) @@ -2815,6 +2837,7 @@ namespace System.ServiceModel.Channels return builder.ToString(); } + [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. It will cause compatibility issue. Not used for cryptographic purposes.")] static HashAlgorithm GetHashAlgorithm() { if (SecurityUtilsEx.RequiresFipsCompliance) diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/TransportDefaults.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/TransportDefaults.cs index 4de327474f7..d2c0f72a516 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/TransportDefaults.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/TransportDefaults.cs @@ -202,8 +202,8 @@ namespace System.ServiceModel.Channels internal const bool RequireClientCertificate = false; internal const int MaxFaultSize = MaxBufferSize; internal const int MaxSecurityFaultSize = 16384; - internal const SslProtocols SslProtocols = System.Security.Authentication.SslProtocols.Ssl3 | - System.Security.Authentication.SslProtocols.Tls | + + internal const SslProtocols SslProtocols = System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12; diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/UnsafeNativeMethods.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/UnsafeNativeMethods.cs index bade3dab69e..275270b401c 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/UnsafeNativeMethods.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/UnsafeNativeMethods.cs @@ -1101,31 +1101,82 @@ namespace System.ServiceModel.Channels #if !FEATURE_CORECLR - // On CoreCLR this is not the way to determine if a process is a tailored application (which means APPX). - // On CoreCLR AppX is determined by a flag past to the host which is exposed by AppDomain.IsAppXProcess in mscorlib. - // The reason for this if-def is to ensure nobody takes a dependency on this on CoreCLR. - + private static IntPtr GetCurrentProcessToken() { return new IntPtr(-4); } + + enum AppPolicyClrCompat + { + AppPolicyClrCompat_Others = 0, + AppPolicyClrCompat_ClassicDesktop = 1, + AppPolicyClrCompat_Universal = 2, + AppPolicyClrCompat_PackagedDesktop = 3 + }; + + [DllImport(KERNEL32, CharSet = CharSet.None, EntryPoint = "AppPolicyGetClrCompat")] + [System.Security.SecuritySafeCritical] + [return: MarshalAs(UnmanagedType.I4)] + private static extern Int32 _AppPolicyGetClrCompat(IntPtr processToken, out AppPolicyClrCompat appPolicyClrCompat); + // AppModel.h functions (Win8+) [DllImport(KERNEL32, CharSet = CharSet.None, EntryPoint = "GetCurrentPackageId")] - [SecurityCritical] + [System.Security.SecuritySafeCritical] [return: MarshalAs(UnmanagedType.I4)] - private static extern Int32 GetCurrentPackageId(ref Int32 pBufferLength, Byte[] pBuffer); + private static extern Int32 _GetCurrentPackageId(ref Int32 pBufferLength, Byte[] pBuffer); - [Fx.Tag.SecurityNote( - Critical = "Critical because it calls the native function GetCurrentPackageId.", - Safe = "Safe because it takes no user input and it doesn't leak security sensitive information.")] - [SecuritySafeCritical] + [DllImport(KERNEL32, CharSet=System.Runtime.InteropServices.CharSet.Auto, BestFitMapping=false)] + [ResourceExposure(ResourceScope.Machine)] + private static extern IntPtr GetModuleHandle(string modName); + + // Copied from Win32Native.cs + // Note - do NOT use this to call methods. Use P/Invoke, which will + // do much better things w.r.t. marshaling, pinning memory, security + // stuff, better interactions with thread aborts, etc. This is used + // solely by DoesWin32MethodExist for avoiding try/catch EntryPointNotFoundException + // in scenarios where an OS Version check is insufficient + [DllImport(KERNEL32, CharSet=CharSet.Ansi, BestFitMapping=false, SetLastError=true, ExactSpelling=true)] + [ResourceExposure(ResourceScope.None)] + private static extern IntPtr GetProcAddress(IntPtr hModule, String methodName); + + [System.Security.SecurityCritical] // auto-generated + private static bool DoesWin32MethodExist(String moduleName, String methodName) + { + // GetModuleHandle does not increment the module's ref count, so we don't need to call FreeLibrary. + IntPtr hModule = GetModuleHandle(moduleName); + if (hModule == IntPtr.Zero) { + System.Diagnostics.Debug.Assert(hModule != IntPtr.Zero, "GetModuleHandle failed. Dll isn't loaded?"); + return false; + } + IntPtr functionPointer = GetProcAddress(hModule, methodName); + return (functionPointer != IntPtr.Zero); + } + + // On CoreCLR this is not the way to determine if a process is a tailored application (which means APPX). + // On CoreCLR AppX is determined by a flag past to the host which is exposed by AppDomain.IsAppXProcess in mscorlib. + // The reason for this if-def is to ensure nobody takes a dependency on this on CoreCLR. + [System.Security.SecuritySafeCritical] private static bool _IsTailoredApplication() { - if (OSEnvironmentHelper.IsAtLeast(OSVersion.Win8)) + Version windows8Version = new Version(6, 2, 0, 0); + OperatingSystem os = Environment.OSVersion; + bool osSupportsPackagedProcesses = os.Platform == PlatformID.Win32NT && os.Version >= windows8Version; + + if (osSupportsPackagedProcesses && DoesWin32MethodExist(KERNEL32, "AppPolicyGetClrCompat")) { - int bufLen = 0; - // Will return ERROR_INSUFFICIENT_BUFFER when running within a tailored application, + // Use AppPolicyGetClrCompat if it is available. Return true if and only if this is a UWA which means if + // this is packaged desktop app this method will return false. This may cause some confusion however + // this is necessary to make the behavior of packaged desktop apps identical to desktop apps. + AppPolicyClrCompat appPolicyClrCompat; + return _AppPolicyGetClrCompat(GetCurrentProcessToken(), out appPolicyClrCompat) == ERROR_SUCCESS && + appPolicyClrCompat == AppPolicyClrCompat.AppPolicyClrCompat_Universal; + } + else if(osSupportsPackagedProcesses && DoesWin32MethodExist(KERNEL32, "GetCurrentPackageId")) + { + Int32 bufLen = 0; + // Will return ERROR_INSUFFICIENT_BUFFER when running within a packaged application, // and will return ERROR_NO_PACKAGE_IDENTITY otherwise. - return GetCurrentPackageId(ref bufLen, null) == ERROR_INSUFFICIENT_BUFFER; + return _GetCurrentPackageId(ref bufLen, null) == ERROR_INSUFFICIENT_BUFFER; } else - { + { // We must be running on a downlevel OS. return false; } } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/WebSocketHelper.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/WebSocketHelper.cs index 928d9be8f3e..b99db25d123 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/WebSocketHelper.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Channels/WebSocketHelper.cs @@ -6,6 +6,7 @@ namespace System.ServiceModel.Channels { using System; using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Linq; using System.Net; @@ -44,6 +45,7 @@ namespace System.ServiceModel.Channels static readonly HashSet InvalidSeparatorSet = new HashSet(new char[] { '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ' }); static string currentWebSocketVersion; + [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. Usage of SHA1 is part of WebSocket spec. Justification in RFC6455 section 10.8")] internal static string ComputeAcceptHeader(string webSocketKey) { Fx.Assert(webSocketKey != null, "webSocketKey should not be null."); diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/Properties.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/Properties.cs index 35c78297859..a457268b0ce 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/Properties.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Configuration/Properties.cs @@ -3472,7 +3472,7 @@ namespace System.ServiceModel.Configuration { ConfigurationPropertyCollection properties = new ConfigurationPropertyCollection(); properties.Add(new ConfigurationProperty("requireClientCertificate", typeof(System.Boolean), false, null, null, System.Configuration.ConfigurationPropertyOptions.None)); - properties.Add(new ConfigurationProperty("sslProtocols", typeof(System.Security.Authentication.SslProtocols), System.Security.Authentication.SslProtocols.Ssl3 | System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Default | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.Security.SslProtocolsHelper)), System.Configuration.ConfigurationPropertyOptions.None)); + properties.Add(new ConfigurationProperty("sslProtocols", typeof(System.Security.Authentication.SslProtocols), System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.Security.SslProtocolsHelper)), System.Configuration.ConfigurationPropertyOptions.None)); this.properties = properties; } return this.properties; @@ -3527,7 +3527,7 @@ namespace System.ServiceModel.Configuration properties.Add(new ConfigurationProperty("clientCredentialType", typeof(System.ServiceModel.TcpClientCredentialType), System.ServiceModel.TcpClientCredentialType.Windows, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.TcpClientCredentialTypeHelper)), System.Configuration.ConfigurationPropertyOptions.None)); properties.Add(new ConfigurationProperty("protectionLevel", typeof(System.Net.Security.ProtectionLevel), System.Net.Security.ProtectionLevel.EncryptAndSign, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.Security.ProtectionLevelHelper)), System.Configuration.ConfigurationPropertyOptions.None)); properties.Add(new ConfigurationProperty("extendedProtectionPolicy", typeof(System.Security.Authentication.ExtendedProtection.Configuration.ExtendedProtectionPolicyElement), null, null, null, System.Configuration.ConfigurationPropertyOptions.None)); - properties.Add(new ConfigurationProperty("sslProtocols", typeof(System.Security.Authentication.SslProtocols), System.Security.Authentication.SslProtocols.Ssl3 | System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Default | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.Security.SslProtocolsHelper)), System.Configuration.ConfigurationPropertyOptions.None)); + properties.Add(new ConfigurationProperty("sslProtocols", typeof(System.Security.Authentication.SslProtocols), System.Security.Authentication.SslProtocols.Tls | System.Security.Authentication.SslProtocols.Tls11 | System.Security.Authentication.SslProtocols.Tls12, null, new System.ServiceModel.Configuration.ServiceModelEnumValidator(typeof(System.ServiceModel.Security.SslProtocolsHelper)), System.Configuration.ConfigurationPropertyOptions.None)); this.properties = properties; } return this.properties; diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Description/MessageContractExporter.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Description/MessageContractExporter.cs index dbef91c1275..e4a23bcc00c 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Description/MessageContractExporter.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Description/MessageContractExporter.cs @@ -1347,31 +1347,38 @@ namespace System.ServiceModel.Description internal static XmlSchema CreateWsdl() { - return XmlSchema.Read(new StringReader(wsdl), null); + StringReader reader = new StringReader(wsdl); + return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); } + internal static XmlSchema CreateSoap() { - return XmlSchema.Read(new StringReader(soap), null); + StringReader reader = new StringReader(soap); + return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); } internal static XmlSchema CreateSoapEncoding() { - return XmlSchema.Read(new StringReader(soapEncoding), null); + StringReader reader = new StringReader(soapEncoding); + return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); } internal static XmlSchema CreateFakeSoapEncoding() { - return XmlSchema.Read(new StringReader(fakeSoapEncoding), null); + StringReader reader = new StringReader(fakeSoapEncoding); + return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); } internal static XmlSchema CreateFakeXsdSchema() { - return XmlSchema.Read(new StringReader(fakeXsd), null); + StringReader reader = new StringReader(fakeXsd); + return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); } internal static XmlSchema CreateFakeXmlSchema() { - return XmlSchema.Read(new StringReader(fakeXmlSchema), null); + StringReader reader = new StringReader(fakeXmlSchema); + return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); } internal static bool IsKnownSchema(string ns) diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Description/WsdlHelper.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Description/WsdlHelper.cs index c056108dd68..f8674ce614d 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Description/WsdlHelper.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Description/WsdlHelper.cs @@ -5,6 +5,7 @@ namespace System.ServiceModel.Description { using System.Collections.Generic; + using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.IO; using System.Linq; @@ -313,6 +314,8 @@ namespace System.ServiceModel.Description return newWsdl; } + [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader")] + [SuppressMessage("Microsoft.Security.Xml", "CA3069:ReviewDtdProcessingAssignment", Justification = "This is trusted server code from the application only. We should allow the customer add dtd.")] private static XmlSchema CloneXsd(XmlSchema originalXsd) { Fx.Assert(originalXsd != null, "originalXsd must not be null"); @@ -321,7 +324,7 @@ namespace System.ServiceModel.Description { originalXsd.Write(memoryStream); memoryStream.Seek(0, SeekOrigin.Begin); - newXsd = XmlSchema.Read(memoryStream, null); + newXsd = XmlSchema.Read(new XmlTextReader(memoryStream) { DtdProcessing = DtdProcessing.Parse }, null); } return newXsd; diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/QueryMatcher.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/QueryMatcher.cs index d34430b8733..c7fb3487217 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/QueryMatcher.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/QueryMatcher.cs @@ -7,6 +7,7 @@ namespace System.ServiceModel.Dispatcher using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; + using System.Diagnostics.CodeAnalysis; using System.Runtime; using System.ServiceModel.Channels; using System.ServiceModel.Diagnostics; @@ -262,6 +263,7 @@ namespace System.ServiceModel.Dispatcher } } + [SuppressMessage("Microsoft.Security.Xml", "CA3057:DoNotUseLoadXml")] static QueryMatcher() { QueryMatcher.defaultFunctionLibs = new IFunctionLibrary[] { new XPathFunctionLibrary() }; diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/TaskMethodInvoker.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/TaskMethodInvoker.cs index 9bf6328b822..2b9ff6aeda7 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/TaskMethodInvoker.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/TaskMethodInvoker.cs @@ -8,12 +8,11 @@ namespace System.ServiceModel.Dispatcher using System.Diagnostics; using System.Reflection; using System.Runtime; - using System.Runtime.Diagnostics; using System.Security; using System.ServiceModel.Description; using System.ServiceModel.Diagnostics; - using System.ServiceModel.Diagnostics.Application; using System.Threading.Tasks; + using Threading; /// /// An invoker used when some operation contract has a return value of Task or its generic counterpart (Task of T) @@ -21,14 +20,12 @@ namespace System.ServiceModel.Dispatcher internal class TaskMethodInvoker : IOperationInvoker { private const string ResultMethodName = "Result"; - private MethodInfo taskMethod; - private bool isGenericTask; + private readonly MethodInfo taskMethod; private InvokeDelegate invokeDelegate; private int inputParameterCount; private int outputParameterCount; - private object[] outputs; - private MethodInfo toAsyncMethodInfo; private MethodInfo taskTResultGetMethod; + private bool isGenericTask; public TaskMethodInvoker(MethodInfo taskMethod, Type taskType) { @@ -41,7 +38,6 @@ namespace System.ServiceModel.Dispatcher if (taskType != ServiceReflector.VoidType) { - this.toAsyncMethodInfo = TaskExtensions.MakeGenericMethod(taskType); this.taskTResultGetMethod = ((PropertyInfo)taskMethod.ReturnType.GetMember(ResultMethodName)[0]).GetGetMethod(); this.isGenericTask = true; } @@ -57,36 +53,11 @@ namespace System.ServiceModel.Dispatcher get { return this.taskMethod; } } - private InvokeDelegate InvokeDelegate - { - get - { - this.EnsureIsInitialized(); - return this.invokeDelegate; - } - } - - private int InputParameterCount - { - get - { - this.EnsureIsInitialized(); - return this.inputParameterCount; - } - } - - private int OutputParameterCount - { - get - { - this.EnsureIsInitialized(); - return this.outputParameterCount; - } - } - public object[] AllocateInputs() { - return EmptyArray.Allocate(this.InputParameterCount); + EnsureIsInitialized(); + + return EmptyArray.Allocate(this.inputParameterCount); } public object Invoke(object instance, object[] inputs, out object[] outputs) @@ -95,169 +66,249 @@ namespace System.ServiceModel.Dispatcher } public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) + { + return ToApm(InvokeAsync(instance, inputs), callback, state); + } + + public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) { if (instance == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNoServiceObject))); } - if (inputs == null) - { - if (this.InputParameterCount > 0) - { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceNull, this.InputParameterCount))); - } - } - else if (inputs.Length != this.InputParameterCount) - { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceInvalid, this.InputParameterCount, inputs.Length))); - } - - this.outputs = EmptyArray.Allocate(this.OutputParameterCount); - - AsyncMethodInvoker.StartOperationInvokePerformanceCounters(this.taskMethod.Name); - - IAsyncResult returnValue; + object returnVal = null; bool callFailed = true; bool callFaulted = false; ServiceModelActivity activity = null; + Activity boundOperation = null; try { - Activity boundActivity = null; - AsyncMethodInvoker.CreateActivityInfo(ref activity, ref boundActivity); + AsyncMethodInvoker.GetActivityInfo(ref activity, ref boundOperation); - AsyncMethodInvoker.StartOperationInvokeTrace(this.taskMethod.Name); - - using (boundActivity) + Task> invokeTask = result as Task>; + + if (invokeTask == null) { - if (DiagnosticUtility.ShouldUseActivity) + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.SFxInvalidCallbackIAsyncResult)); + } + + AggregateException ae = null; + Tuple tuple = null; + Task task = null; + + if (invokeTask.IsFaulted) + { + Fx.Assert(invokeTask.Exception != null, "Task.IsFaulted guarantees non-null exception."); + ae = invokeTask.Exception; + } + else + { + Fx.Assert(invokeTask.IsCompleted, "Task.Result is expected to be completed"); + + tuple = invokeTask.Result; + task = tuple.Item1 as Task; + + if (task == null) { - string activityName = SR.GetString(SR.ActivityExecuteMethod, this.taskMethod.DeclaringType.FullName, this.taskMethod.Name); - ServiceModelActivity.Start(activity, activityName, ActivityType.ExecuteUserCode); + outputs = tuple.Item2; + return null; } - object taskReturnValue = this.InvokeDelegate(instance, inputs, this.outputs); - - if (taskReturnValue == null) + if (task.IsFaulted) { - throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("task"); + Fx.Assert(task.Exception != null, "Task.IsFaulted guarantees non-null exception."); + ae = task.Exception; } - else if (this.isGenericTask) + } + + if (ae != null && ae.InnerException != null) + { + if (ae.InnerException is FaultException) { - returnValue = (IAsyncResult)this.toAsyncMethodInfo.Invoke(null, new object[] { taskReturnValue, callback, state }); + // If invokeTask.IsFaulted we produce the 'callFaulted' behavior below. + // Any other exception will retain 'callFailed' behavior. + callFaulted = true; + callFailed = false; } - else + + if (ae.InnerException is SecurityException) { - returnValue = ((Task)taskReturnValue).AsAsyncResult(callback, state); + DiagnosticUtility.TraceHandledException(ae.InnerException, TraceEventType.Warning); + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException()); } - callFailed = false; + invokeTask.GetAwaiter().GetResult(); } - } - catch (System.Security.SecurityException e) - { - DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning); - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException()); - } - catch (Exception e) - { - TraceUtility.TraceUserCodeException(e, this.taskMethod); - if (e is FaultException) + + // Task cancellation without an exception indicates failure but we have no + // additional information to provide. Accessing Task.Result will throw a + // TaskCanceledException. For consistency between void Tasks and Task, + // we detect and throw here. + if (task.IsCanceled) { - callFaulted = true; - callFailed = false; + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new TaskCanceledException(task)); } - throw; + outputs = tuple.Item2; + + returnVal = this.isGenericTask ? this.taskTResultGetMethod.Invoke(task, Type.EmptyTypes) : null; + callFailed = false; + + return returnVal; } finally { - ServiceModelActivity.Stop(activity); - - // Any exception above means InvokeEnd will not be called, so complete it here. - if (callFailed || callFaulted) + if (boundOperation != null) { - AsyncMethodInvoker.StopOperationInvokeTrace(callFailed, callFaulted, this.TaskMethod.Name); - AsyncMethodInvoker.StopOperationInvokePerformanceCounters(callFailed, callFaulted, this.TaskMethod.Name); + ((IDisposable)boundOperation).Dispose(); } - } - return returnValue; + ServiceModelActivity.Stop(activity); + AsyncMethodInvoker.StopOperationInvokeTrace(callFailed, callFaulted, this.TaskMethod.Name); + AsyncMethodInvoker.StopOperationInvokePerformanceCounters(callFailed, callFaulted, this.TaskMethod.Name); + } } - public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) + private async Task> InvokeAsync(object instance, object[] inputs) { - object returnVal; - bool callFailed = true; - bool callFaulted = false; - ServiceModelActivity activity = null; + EnsureIsInitialized(); if (instance == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNoServiceObject))); } + if (inputs == null) + { + if (this.inputParameterCount > 0) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceNull, this.inputParameterCount))); + } + } + else if (inputs.Length != this.inputParameterCount) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceInvalid, this.inputParameterCount, inputs.Length))); + } + + object[] outputs = EmptyArray.Allocate(this.outputParameterCount); + + AsyncMethodInvoker.StartOperationInvokePerformanceCounters(this.taskMethod.Name); + + object returnValue; + ServiceModelActivity activity = null; + Activity boundActivity = null; + try { - Activity boundOperation = null; - AsyncMethodInvoker.GetActivityInfo(ref activity, ref boundOperation); + AsyncMethodInvoker.CreateActivityInfo(ref activity, ref boundActivity); + AsyncMethodInvoker.StartOperationInvokeTrace(this.taskMethod.Name); - using (boundOperation) + if (DiagnosticUtility.ShouldUseActivity) { - Task task = result as Task; + string activityName = SR.GetString(SR.ActivityExecuteMethod, this.taskMethod.DeclaringType.FullName, this.taskMethod.Name); + ServiceModelActivity.Start(activity, activityName, ActivityType.ExecuteUserCode); + } - Fx.Assert(task != null, "InvokeEnd needs to be called with the result returned from InvokeBegin."); - if (task.IsFaulted) - { - Fx.Assert(task.Exception != null, "Task.IsFaulted guarantees non-null exception."); + OperationContext.EnableAsyncFlow(); - // If FaultException is thrown, we will get 'callFaulted' behavior below. - // Any other exception will retain 'callFailed' behavior. - throw FxTrace.Exception.AsError(task.Exception); - } + returnValue = this.invokeDelegate(instance, inputs, outputs); - // Task cancellation without an exception indicates failure but we have no - // additional information to provide. Accessing Task.Result will throw a - // TaskCanceledException. For consistency between void Tasks and Task, - // we detect and throw here. - if (task.IsCanceled) - { - throw FxTrace.Exception.AsError(new TaskCanceledException(task)); - } + if (returnValue == null) + { + throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("task"); + } - outputs = this.outputs; - if (this.isGenericTask) - { - returnVal = this.taskTResultGetMethod.Invoke(result, Type.EmptyTypes); - } - else - { - returnVal = null; - } + var returnValueTask = returnValue as Task; - callFailed = false; + if (returnValueTask != null) + { + // Only return once the task has completed + await returnValueTask; } + + return Tuple.Create(returnValue, outputs); } catch (SecurityException e) { DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException()); } - catch (FaultException) + catch (Exception e) { - callFaulted = true; - callFailed = false; + TraceUtility.TraceUserCodeException(e, this.taskMethod); throw; } finally { + OperationContext.DisableAsyncFlow(); + + if (boundActivity != null) + { + ((IDisposable)boundActivity).Dispose(); + } + ServiceModelActivity.Stop(activity); - AsyncMethodInvoker.StopOperationInvokeTrace(callFailed, callFaulted, this.TaskMethod.Name); - AsyncMethodInvoker.StopOperationInvokePerformanceCounters(callFailed, callFaulted, this.TaskMethod.Name); } + } + + // Helper method when implementing an APM wrapper around a Task based async method which returns a result. + // In the BeginMethod method, you would call use ToApm to wrap a call to MethodAsync: + // return MethodAsync(params).ToApm(callback, state); + // In the EndMethod, you would use ToApmEnd to ensure the correct exception handling + // This will handle throwing exceptions in the correct place and ensure the IAsyncResult contains the provided + // state object + private static Task ToApm(Task task, AsyncCallback callback, object state) + { + // When using APM, the returned IAsyncResult must have the passed in state object stored in AsyncState. This + // is so the callback can regain state. If the incoming task already holds the state object, there's no need + // to create a TaskCompletionSource to ensure the returned (IAsyncResult)Task has the right state object. + // This is a performance optimization for this special case. + if (task.AsyncState == state) + { + if (callback != null) + { + task.ContinueWith((antecedent, obj) => + { + AsyncCallback callbackObj = (AsyncCallback)obj; + callbackObj(antecedent); + }, callback, CancellationToken.None, TaskContinuationOptions.HideScheduler, TaskScheduler.Default); + } + + return task; + } + + // Need to create a TaskCompletionSource so that the returned Task object has the correct AsyncState value. + var tcs = new TaskCompletionSource(state); + var continuationState = Tuple.Create(tcs, callback); + + task.ContinueWith((antecedent, obj) => + { + Tuple, AsyncCallback> tuple = (Tuple, AsyncCallback>)obj; + TaskCompletionSource tcsObj = tuple.Item1; + AsyncCallback callbackObj = tuple.Item2; + + if (antecedent.IsFaulted) + { + tcsObj.TrySetException(antecedent.Exception.InnerException); + } + else if (antecedent.IsCanceled) + { + tcsObj.TrySetCanceled(); + } + else + { + tcsObj.TrySetResult(antecedent.Result); + } + + if (callbackObj != null) + { + callbackObj(tcsObj.Task); + } + }, continuationState, CancellationToken.None, TaskContinuationOptions.HideScheduler, TaskScheduler.Default); - return returnVal; + return tcs.Task; } private void EnsureIsInitialized() diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/XmlSerializerOperationFormatter.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/XmlSerializerOperationFormatter.cs index 5d826dfb489..0072f122b8a 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/XmlSerializerOperationFormatter.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Dispatcher/XmlSerializerOperationFormatter.cs @@ -92,7 +92,7 @@ namespace System.ServiceModel.Dispatcher bufferWriter.Flush(); XmlDocument doc = new XmlDocument(); memoryStream.Position = 0; - doc.Load(memoryStream); + doc.Load(new XmlTextReader(memoryStream) { DtdProcessing = DtdProcessing.Prohibit }); //doc.Save(Console.Out); foreach (XmlElement element in doc.DocumentElement.ChildNodes) { diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/EndpointAddress10.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/EndpointAddress10.cs index dd5b3ef3436..d7e24e00a8e 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/EndpointAddress10.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/EndpointAddress10.cs @@ -67,7 +67,7 @@ namespace System.ServiceModel static XmlSchema GetEprSchema() { - using (XmlTextReader reader = new XmlTextReader(new StringReader(Schema))) + using (XmlTextReader reader = new XmlTextReader(new StringReader(Schema)) { DtdProcessing = DtdProcessing.Prohibit }) { return XmlSchema.Read(reader, null); } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/EndpointAddressAugust2004.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/EndpointAddressAugust2004.cs index b60cc2b287a..d74bdeb89cc 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/EndpointAddressAugust2004.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/EndpointAddressAugust2004.cs @@ -67,7 +67,7 @@ namespace System.ServiceModel static XmlSchema GetEprSchema() { - using (XmlTextReader reader = new XmlTextReader(new StringReader(Schema))) + using (XmlTextReader reader = new XmlTextReader(new StringReader(Schema)) { DtdProcessing = DtdProcessing.Prohibit }) { return XmlSchema.Read(reader, null); } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/LocalAppContextSwitches.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/LocalAppContextSwitches.cs index 616b1feddc3..323304ff6ba 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/LocalAppContextSwitches.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/LocalAppContextSwitches.cs @@ -14,9 +14,11 @@ namespace System.ServiceModel { private const string DisableExplicitConnectionCloseHeaderString = "Switch.System.ServiceModel.DisableExplicitConnectionCloseHeader"; private const string AllowUnsignedToHeaderString = "Switch.System.ServiceModel.AllowUnsignedToHeader"; + private const string DisableCngCertificatesString = "Switch.System.ServiceModel.DisableCngCertificates"; private static int disableExplicitConnectionCloseHeader; private static int allowUnsignedToHeader; + private static int disableCngCertificates; public static bool DisableExplicitConnectionCloseHeader { @@ -36,10 +38,29 @@ namespace System.ServiceModel } } + public static bool DisableCngCertificates + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(DisableCngCertificatesString, ref disableCngCertificates); + } + } + public static void SetDefaultsLessOrEqual_452() { +#pragma warning disable BCL0012 // Define the switches that should be true for 4.5.2 or less, false for 4.6+. LocalAppContext.DefineSwitchDefault(DisableExplicitConnectionCloseHeaderString, true); +#pragma warning restore BCL0012 + } + + public static void SetDefaultsLessOrEqual_461() + { +#pragma warning disable BCL0012 + // Define the switches that should be true for 4.6.1 or less, false for 4.6.2+. + LocalAppContext.DefineSwitchDefault(DisableCngCertificatesString, true); +#pragma warning restore BCL0012 } } } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/OperationContext.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/OperationContext.cs index 08794986728..c08a1200cb8 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/OperationContext.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/OperationContext.cs @@ -5,19 +5,21 @@ namespace System.ServiceModel { using System.Collections.Generic; - using System.ComponentModel; using System.Runtime; using System.Security.Claims; using System.Security.Principal; using System.ServiceModel.Channels; using System.ServiceModel.Dispatcher; using System.ServiceModel.Security; + using System.Threading; public sealed class OperationContext : IExtensibleObject { [ThreadStatic] static Holder currentContext; + static AsyncLocal currentAsyncLocalContext = new AsyncLocal(); + ServiceChannel channel; Message clientReply; bool closeClientReply; @@ -33,6 +35,7 @@ namespace System.ServiceModel MessageHeaders outgoingMessageHeaders; MessageVersion outgoingMessageVersion; EndpointDispatcher endpointDispatcher; + bool isAsyncFlowEnabled; public event EventHandler OperationCompleted; @@ -92,12 +95,19 @@ namespace System.ServiceModel { get { - return CurrentHolder.Context; + return ShouldUseAsyncLocalContext ? OperationContext.currentAsyncLocalContext.Value : CurrentHolder.Context; } set { - CurrentHolder.Context = value; + if (ShouldUseAsyncLocalContext) + { + OperationContext.currentAsyncLocalContext.Value = value; + } + else + { + CurrentHolder.Context = value; + } } } @@ -115,6 +125,14 @@ namespace System.ServiceModel } } + private static bool ShouldUseAsyncLocalContext + { + get + { + return CurrentHolder.Context == null && OperationContext.currentAsyncLocalContext.Value != null && OperationContext.currentAsyncLocalContext.Value.isAsyncFlowEnabled; + } + } + public EndpointDispatcher EndpointDispatcher { get @@ -339,6 +357,21 @@ namespace System.ServiceModel this.clientReply = null; } + internal static void EnableAsyncFlow() + { + CurrentHolder.Context.isAsyncFlowEnabled = true; + currentAsyncLocalContext.Value = CurrentHolder.Context; + } + + internal static void DisableAsyncFlow() + { + if (OperationContext.Current != null && OperationContext.Current.isAsyncFlowEnabled) + { + OperationContext.Current.isAsyncFlowEnabled = false; + currentAsyncLocalContext.Value = null; + } + } + internal void FireOperationCompleted() { try diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/OperationContextScope.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/OperationContextScope.cs index 17da631e149..3d12f54c864 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/OperationContextScope.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/OperationContextScope.cs @@ -10,14 +10,12 @@ namespace System.ServiceModel public sealed class OperationContextScope : IDisposable { - [ThreadStatic] - static OperationContextScope currentScope; + static AsyncLocal currentScope = new AsyncLocal(); OperationContext currentContext; bool disposed; readonly OperationContext originalContext = OperationContext.Current; - readonly OperationContextScope originalScope = OperationContextScope.currentScope; - readonly Thread thread = Thread.CurrentThread; + readonly OperationContextScope originalScope = OperationContextScope.currentScope.Value; public OperationContextScope(IContextChannel channel) { @@ -41,22 +39,19 @@ namespace System.ServiceModel void PushContext(OperationContext context) { this.currentContext = context; - OperationContextScope.currentScope = this; + OperationContextScope.currentScope.Value = this; OperationContext.Current = this.currentContext; } void PopContext() { - if (this.thread != Thread.CurrentThread) - throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidContextScopeThread0))); - - if (OperationContextScope.currentScope != this) + if (OperationContextScope.currentScope.Value != this) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInterleavedContextScopes0))); if (OperationContext.Current != this.currentContext) throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxContextModifiedInsideScope0))); - OperationContextScope.currentScope = this.originalScope; + OperationContextScope.currentScope.Value = this.originalScope; OperationContext.Current = this.originalContext; if (this.currentContext != null) diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/CryptoHelper.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/CryptoHelper.cs index ff0d508ecb0..7c0b7a8cb2e 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/CryptoHelper.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/CryptoHelper.cs @@ -17,6 +17,7 @@ namespace System.ServiceModel.Security using System.Text; using System.Xml; using System.Diagnostics; + using System.Diagnostics.CodeAnalysis; using System.Security.Cryptography; using Psha1DerivedKeyGenerator = System.IdentityModel.Psha1DerivedKeyGenerator; @@ -57,6 +58,7 @@ namespace System.ServiceModel.Security return CryptoHelper.CreateHashAlgorithm(SecurityAlgorithms.Sha256Digest); } + [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. Required as SOAP spec requires supporting SHA1.")] internal static HashAlgorithm CreateHashAlgorithm(string digestMethod) { object algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(digestMethod); @@ -86,6 +88,7 @@ namespace System.ServiceModel.Security } } + [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:DoNotUseSHA1", Justification = "Cannot change. Required as SOAP spec requires supporting SHA1.")] internal static HashAlgorithm CreateHashForAsymmetricSignature(string signatureMethod) { object algorithmObject = CryptoAlgorithms.GetAlgorithmFromConfig(signatureMethod); diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/SecurityUtils.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/SecurityUtils.cs index 913840d0359..b62aceefcff 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/SecurityUtils.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/SecurityUtils.cs @@ -899,8 +899,45 @@ namespace System.ServiceModel.Security [SecuritySafeCritical] static bool CanKeyDoKeyExchange(X509Certificate2 certificate) { - CspKeyContainerInfo info = GetKeyContainerInfo(certificate); - return info != null && info.KeyNumber == KeyNumber.Exchange; + bool canDoKeyExchange = false; + + if (!LocalAppContextSwitches.DisableCngCertificates) + { + X509KeyUsageExtension keyUsageExtension = null; + for (int i = 0; i < certificate.Extensions.Count; i++) + { + keyUsageExtension = certificate.Extensions[i] as X509KeyUsageExtension; + if (keyUsageExtension != null) + { + break; + } + } + + // No KeyUsage extension means most usages are permitted including key exchange. + // See RFC 5280 section 4.2.1.3 (Key Usage) for details. If the extension is non-critical + // then it's non-enforcing and meant as an aid in choosing the best certificate when + // there are multiple certificates to choose from. + if (keyUsageExtension == null || !keyUsageExtension.Critical) + { + return true; + } + + // One of KeyAgreement, KeyEncipherment or DigitalSignature need to be allowed depending on the cipher + // being used. See RFC 5246 section 7.4.6 for more details. + // Additionally, according to msdn docs for PFXImportCertStore, the key specification is set to AT_KEYEXCHANGE + // when the data encipherment usage is set. + canDoKeyExchange = (keyUsageExtension.KeyUsages & + (X509KeyUsageFlags.KeyAgreement | X509KeyUsageFlags.KeyEncipherment | + X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.DataEncipherment)) != X509KeyUsageFlags.None; + } + + if (!canDoKeyExchange) + { + CspKeyContainerInfo info = GetKeyContainerInfo(certificate); + canDoKeyExchange = info != null && info.KeyNumber == KeyNumber.Exchange; + } + + return canDoKeyExchange; } [Fx.Tag.SecurityNote(Critical = "Elevates to call properties: X509Certificate2.PrivateKey and CspKeyContainerInfo. Caller must protect the return value.")] @@ -1866,6 +1903,52 @@ namespace System.ServiceModel.Security } } + public static bool CanReadPrivateKey(X509Certificate2 certificate) + { + if (!certificate.HasPrivateKey) + return false; + + try + { + // CNG key, CNG permissions tests + using (RSA rsa = CngLightup.GetRSAPrivateKey(certificate)) + { + if (rsa != null) + { + return true; + } + } + + using (DSA dsa = CngLightup.GetDSAPrivateKey(certificate)) + { + if (dsa != null) + { + return true; + } + } + + using (ECDsa ecdsa = CngLightup.GetECDsaPrivateKey(certificate)) + { + if (ecdsa != null) + { + return true; + } + } + + // CAPI key, CAPI permissions test + if (certificate.PrivateKey != null) + { + return true; + } + + return false; + } + catch (CryptographicException) + { + return false; + } + } + static class NetworkCredentialHelper { [Fx.Tag.SecurityNote(Critical = "Uses unsafe critical methods UnsafeGetUsername, UnsafeGetPassword, and UnsafeGetDomain to access the credential details without a Demand.", diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/TlsSspiNegotiation.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/TlsSspiNegotiation.cs index 0032edc9ea8..59722893438 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/TlsSspiNegotiation.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/TlsSspiNegotiation.cs @@ -543,7 +543,14 @@ namespace System.ServiceModel.Security bool hasPrivateKey = false; try { - hasPrivateKey = certificate != null && certificate.PrivateKey != null; + if (System.ServiceModel.LocalAppContextSwitches.DisableCngCertificates) + { + hasPrivateKey = certificate != null && certificate.PrivateKey != null; + } + else + { + hasPrivateKey = certificate.HasPrivateKey && SecurityUtils.CanReadPrivateKey(certificate); + } } catch (SecurityException e) { diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/Tokens/IssuedSecurityTokenProvider.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/Tokens/IssuedSecurityTokenProvider.cs index b9f10c42f55..5641522d6ed 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/Tokens/IssuedSecurityTokenProvider.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/Tokens/IssuedSecurityTokenProvider.cs @@ -461,7 +461,7 @@ namespace System.ServiceModel.Security.Tokens XmlDocument dom = new XmlDocument(); dom.PreserveWhitespace = true; - dom.Load(stream); + dom.Load(new XmlTextReader(stream) { DtdProcessing = DtdProcessing.Prohibit }); stream.Close(); return dom.DocumentElement; diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSSecurityPolicy.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSSecurityPolicy.cs index e3d7cf18cc0..417886dd3eb 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSSecurityPolicy.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSSecurityPolicy.cs @@ -2310,7 +2310,7 @@ namespace System.ServiceModel.Security writer.WriteEndElement(); writer.Flush(); stream.Seek(0, SeekOrigin.Begin); - result = (XmlElement)doc.ReadNode(new XmlTextReader(stream)); + result = (XmlElement)doc.ReadNode(new XmlTextReader(stream) { DtdProcessing = DtdProcessing.Prohibit }); } return result; } diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSTrust.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSTrust.cs index 2795cd2b3ec..2b65cc9326e 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSTrust.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSTrust.cs @@ -1417,7 +1417,7 @@ namespace System.ServiceModel.Security writer.Flush(); stream.Seek(0, SeekOrigin.Begin); XmlNode skiNode; - using (XmlDictionaryReader reader = XmlDictionaryReader.CreateDictionaryReader(new XmlTextReader(stream))) + using (XmlDictionaryReader reader = XmlDictionaryReader.CreateDictionaryReader(new XmlTextReader(stream) { DtdProcessing = DtdProcessing.Prohibit })) { reader.MoveToContent(); skiNode = doc.ReadNode(reader); diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSTrustServiceContract.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSTrustServiceContract.cs index 81df58a3069..1bd584b2806 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSTrustServiceContract.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/Security/WSTrustServiceContract.cs @@ -2064,7 +2064,8 @@ namespace System.ServiceModel.Security throw DiagnosticUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID5004, ns)); } - return XmlSchema.Read(new StringReader(xmlSchema), null); + StringReader reader = new StringReader(xmlSchema); + return XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); } /// diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/ServiceHost.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/ServiceHost.cs index 47a80aaf772..37ca8e48b95 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/ServiceHost.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/ServiceHost.cs @@ -1,4 +1,4 @@ - //----------------------------------------------------------------------------- +//----------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- @@ -1076,6 +1076,9 @@ namespace System.ServiceModel { ManagementExtension.OnServiceOpened(this); } + + // log telemetry data for the current WCF service. + TelemetryTraceLogging.LogSeriveKPIData(this.Description); } base.OnOpened(); diff --git a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/ServiceModelAppSettings.cs b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/ServiceModelAppSettings.cs index b7c7db2a426..19fba5c99a8 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/ServiceModelAppSettings.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/ServiceModel/ServiceModelAppSettings.cs @@ -15,12 +15,15 @@ namespace System.ServiceModel internal const string HttpTransportPerFactoryConnectionPoolString = "wcf:httpTransportBinding:useUniqueConnectionPoolPerFactory"; internal const string EnsureUniquePerformanceCounterInstanceNamesString = "wcf:ensureUniquePerformanceCounterInstanceNames"; internal const string UseConfiguredTransportSecurityHeaderLayoutString = "wcf:useConfiguredTransportSecurityHeaderLayout"; + internal const string UseBestMatchNamedPipeUriString = "wcf:useBestMatchNamedPipeUri"; const bool DefaultHttpTransportPerFactoryConnectionPool = false; const bool DefaultEnsureUniquePerformanceCounterInstanceNames = false; const bool DefaultUseConfiguredTransportSecurityHeaderLayout = false; + const bool DefaultUseBestMatchNamedPipeUri = false; static bool httpTransportPerFactoryConnectionPool; static bool ensureUniquePerformanceCounterInstanceNames; static bool useConfiguredTransportSecurityHeaderLayout; + static bool useBestMatchNamedPipeUri; static volatile bool settingsInitalized = false; static object appSettingsLock = new object(); @@ -54,6 +57,16 @@ namespace System.ServiceModel } } + internal static bool UseBestMatchNamedPipeUri + { + get + { + EnsureSettingsLoaded(); + + return useBestMatchNamedPipeUri; + } + } + [SuppressMessage(FxCop.Category.ReliabilityBasic, "Reliability104:CaughtAndHandledExceptionsRule", Justification = "Handle the configuration exceptions here to avoid regressions on customer's existing scenarios")] static void EnsureSettingsLoaded() @@ -89,6 +102,11 @@ namespace System.ServiceModel useConfiguredTransportSecurityHeaderLayout = DefaultUseConfiguredTransportSecurityHeaderLayout; } + if ((appSettingsSection == null) || !bool.TryParse(appSettingsSection[UseBestMatchNamedPipeUriString], out useBestMatchNamedPipeUri)) + { + useBestMatchNamedPipeUri = DefaultUseBestMatchNamedPipeUri; + } + settingsInitalized = true; } } diff --git a/mcs/class/referencesource/System.ServiceModel/System/UriTemplate.cs b/mcs/class/referencesource/System.ServiceModel/System/UriTemplate.cs index 969772454c5..a62d82e0b93 100644 --- a/mcs/class/referencesource/System.ServiceModel/System/UriTemplate.cs +++ b/mcs/class/referencesource/System.ServiceModel/System/UriTemplate.cs @@ -4,6 +4,7 @@ namespace System { + using System.Collections.Concurrent; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; @@ -11,6 +12,7 @@ namespace System using System.ServiceModel; using System.ServiceModel.Channels; using System.Text; + using System.Threading; using System.Runtime.CompilerServices; using System.Globalization; @@ -31,7 +33,7 @@ namespace System const string NullableDefault = "null"; readonly WildcardInfo wildcard; IDictionary defaults; - Dictionary unescapedDefaults; + ConcurrentDictionary unescapedDefaults; VariablesCollection variables; @@ -263,7 +265,7 @@ namespace System { if (this.defaults == null) { - this.defaults = new UriTemplateDefaults(this); + Interlocked.CompareExchange>(ref this.defaults, new UriTemplateDefaults(this), null); } return this.defaults; } @@ -943,16 +945,10 @@ namespace System } if (this.unescapedDefaults == null) { - this.unescapedDefaults = new Dictionary(StringComparer.Ordinal); - } - string unescapedValue; - if (!this.unescapedDefaults.TryGetValue(escapedValue, out unescapedValue)) - { - unescapedValue = Uri.UnescapeDataString(escapedValue); - this.unescapedDefaults.Add(escapedValue, unescapedValue); + this.unescapedDefaults = new ConcurrentDictionary(StringComparer.Ordinal); } - return unescapedValue; + return this.unescapedDefaults.GetOrAdd(escapedValue, Uri.UnescapeDataString); } struct BindInformation @@ -1181,8 +1177,8 @@ namespace System { if (this.pathSegmentVariableNamesSnapshot == null) { - this.pathSegmentVariableNamesSnapshot = new ReadOnlyCollection( - this.pathSegmentVariableNames); + Interlocked.CompareExchange>(ref this.pathSegmentVariableNamesSnapshot, new ReadOnlyCollection( + this.pathSegmentVariableNames), null); } return this.pathSegmentVariableNamesSnapshot; } @@ -1193,8 +1189,8 @@ namespace System { if (this.queryValueVariableNamesSnapshot == null) { - this.queryValueVariableNamesSnapshot = new ReadOnlyCollection( - this.queryValueVariableNames); + Interlocked.CompareExchange>(ref this.queryValueVariableNamesSnapshot, new ReadOnlyCollection( + this.queryValueVariableNames), null); } return this.queryValueVariableNamesSnapshot; } diff --git a/mcs/class/referencesource/System.Web.DynamicData/DynamicData/DynamicValidator.cs b/mcs/class/referencesource/System.Web.DynamicData/DynamicData/DynamicValidator.cs index 7e89f129e7c..51d5a3c922e 100644 --- a/mcs/class/referencesource/System.Web.DynamicData/DynamicData/DynamicValidator.cs +++ b/mcs/class/referencesource/System.Web.DynamicData/DynamicData/DynamicValidator.cs @@ -11,6 +11,7 @@ using System.Web.Resources; using System.Web.UI; using System.Web.UI.WebControls; + using System.Web.DynamicData.Util; /// /// Validator that enforces model validation. It can be used either at the field level or the entity level @@ -163,7 +164,7 @@ } if (!attrib.IsValid(value)) { - ErrorMessage = HttpUtility.HtmlEncode(attrib.FormatErrorMessage(Column.DisplayName)); + ErrorMessage = HttpUtility.HtmlEncode(StringLocalizerUtil.GetLocalizedString(attrib, Column.DisplayName)); return false; } } diff --git a/mcs/class/referencesource/System.Web.DynamicData/DynamicData/FieldTemplateUserControl.cs b/mcs/class/referencesource/System.Web.DynamicData/DynamicData/FieldTemplateUserControl.cs index 33381499ece..324ddf3a0a1 100644 --- a/mcs/class/referencesource/System.Web.DynamicData/DynamicData/FieldTemplateUserControl.cs +++ b/mcs/class/referencesource/System.Web.DynamicData/DynamicData/FieldTemplateUserControl.cs @@ -516,7 +516,8 @@ namespace System.Web.DynamicData { validator.MaximumValue = converter(rangeAttribute.Maximum); if (String.IsNullOrEmpty(validator.ErrorMessage)) { - validator.ErrorMessage = HttpUtility.HtmlEncode(rangeAttribute.FormatErrorMessage(column.DisplayName)); + validator.ErrorMessage = HttpUtility.HtmlEncode( + StringLocalizerUtil.GetLocalizedString(rangeAttribute, column.DisplayName)); } } @@ -533,7 +534,8 @@ namespace System.Web.DynamicData { validator.ValidationExpression = regexAttribute.Pattern; if (String.IsNullOrEmpty(validator.ErrorMessage)) { - validator.ErrorMessage = HttpUtility.HtmlEncode(regexAttribute.FormatErrorMessage(column.DisplayName)); + validator.ErrorMessage = HttpUtility.HtmlEncode( + StringLocalizerUtil.GetLocalizedString(regexAttribute, column.DisplayName)); } } diff --git a/mcs/class/referencesource/System.Web.DynamicData/DynamicData/MetaColumn.cs b/mcs/class/referencesource/System.Web.DynamicData/DynamicData/MetaColumn.cs index 41ce63ba26f..74fb8fb0fe7 100644 --- a/mcs/class/referencesource/System.Web.DynamicData/DynamicData/MetaColumn.cs +++ b/mcs/class/referencesource/System.Web.DynamicData/DynamicData/MetaColumn.cs @@ -250,7 +250,8 @@ namespace System.Web.DynamicData { public string RequiredErrorMessage { get { var requiredAttribute = Metadata.RequiredAttribute; - return requiredAttribute != null ? requiredAttribute.FormatErrorMessage(DisplayName) : String.Empty; + return requiredAttribute != null ? + StringLocalizerUtil.GetLocalizedString(requiredAttribute, DisplayName) : String.Empty; } } @@ -590,7 +591,7 @@ namespace System.Web.DynamicData { public string Description { get { - return DisplayAttribute.GetPropertyValue(a => a.GetDescription(), null) ?? + return DisplayAttribute.GetLocalizedDescription() ?? DescriptionAttribute.GetPropertyValue(a => a.Description, null); } } @@ -599,14 +600,14 @@ namespace System.Web.DynamicData { public string DisplayName { get { - return DisplayAttribute.GetPropertyValue(a => a.GetName(), null) ?? + return DisplayAttribute.GetLocalizedName() ?? DisplayNameAttribute.GetPropertyValue(a => a.DisplayName, null); } } public string ShortDisplayName { get { - return DisplayAttribute.GetPropertyValue(a => a.GetShortName(), null); + return DisplayAttribute.GetLocalizedShortName(); } } @@ -622,7 +623,7 @@ namespace System.Web.DynamicData { public string Prompt { get { - return DisplayAttribute.GetPropertyValue(a => a.GetPrompt(), null); + return DisplayAttribute.GetLocalizedPrompt(); } } diff --git a/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/DataSvcMapFileLoader.cs b/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/DataSvcMapFileLoader.cs index e0c957977bb..b7a62e03ad0 100644 --- a/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/DataSvcMapFileLoader.cs +++ b/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/DataSvcMapFileLoader.cs @@ -6,6 +6,7 @@ #endregion using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Xml.Schema; using System.Xml.Serialization; @@ -50,6 +51,7 @@ namespace Microsoft.VSDesigner.WCFModel return mapFile is DataSvcMapFile ? ((DataSvcMapFile)mapFile).Impl : null; } + [SuppressMessage("Microsoft.Security.Xml", "CA3060:UseXmlReaderForSchemaRead", Justification = "asp.net controls this .xsd file")] protected override XmlSchemaSet GetMapFileSchemaSet() { if (_mapFileSchemaSet == null) diff --git a/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/MetadataFile.cs b/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/MetadataFile.cs index 9aea425a735..d05896f2123 100644 --- a/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/MetadataFile.cs +++ b/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/MetadataFile.cs @@ -17,6 +17,7 @@ using XmlSerialization = System.Xml.Serialization; #if WEB_EXTENSIONS_CODE using System.Web.Resources; +using System.Diagnostics.CodeAnalysis; #else using Microsoft.VSDesigner.WCF.Resources; #endif @@ -551,6 +552,7 @@ namespace Microsoft.VSDesigner.WCFModel /// /// /// + [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Legacy code that trusts our developer-controlled input.")] private void LoadContentFromTextReader(TextReader contentReader) { if (contentReader == null) @@ -597,6 +599,7 @@ namespace Microsoft.VSDesigner.WCFModel /// /// /// + [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Legacy code that trusts our developer-controlled input.")] private MetadataContent LoadMetadataContent(MetadataType fileType) { if (ErrorInLoading != null) diff --git a/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/SvcMapFileLoader.cs b/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/SvcMapFileLoader.cs index d820af9e042..8b9e1ea2909 100644 --- a/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/SvcMapFileLoader.cs +++ b/mcs/class/referencesource/System.Web.Extensions/Compilation/WCFModel/SvcMapFileLoader.cs @@ -6,6 +6,7 @@ #endregion using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Xml.Schema; using System.Xml.Serialization; @@ -50,6 +51,7 @@ namespace Microsoft.VSDesigner.WCFModel return mapFile is SvcMapFile ? ((SvcMapFile)mapFile).Impl : null; } + [SuppressMessage("Microsoft.Security.Xml", "CA3060:UseXmlReaderForSchemaRead", Justification = "asp.net controls this .xsd file")] protected override XmlSchemaSet GetMapFileSchemaSet() { if (_mapFileSchemaSet == null) diff --git a/mcs/class/referencesource/System.Web.Mobile/UI/MobileControls/Adapters/ChtmlCalendarAdapter.cs b/mcs/class/referencesource/System.Web.Mobile/UI/MobileControls/Adapters/ChtmlCalendarAdapter.cs index 91b5f5e706b..a68af5f0a0f 100644 --- a/mcs/class/referencesource/System.Web.Mobile/UI/MobileControls/Adapters/ChtmlCalendarAdapter.cs +++ b/mcs/class/referencesource/System.Web.Mobile/UI/MobileControls/Adapters/ChtmlCalendarAdapter.cs @@ -59,7 +59,7 @@ namespace System.Web.UI.MobileControls.Adapters // This member variable is set each time when calendar info needs to // be accessed and be shared for other helper functions. - private Globalization.Calendar _threadCalendar; + private System.Globalization.Calendar _threadCalendar; private String _textBoxErrorMessage; diff --git a/mcs/class/referencesource/System.Web.Mobile/UI/MobileControls/Adapters/WmlCalendarAdapter.cs b/mcs/class/referencesource/System.Web.Mobile/UI/MobileControls/Adapters/WmlCalendarAdapter.cs index ad6d1c2ff54..c71652d11f1 100644 --- a/mcs/class/referencesource/System.Web.Mobile/UI/MobileControls/Adapters/WmlCalendarAdapter.cs +++ b/mcs/class/referencesource/System.Web.Mobile/UI/MobileControls/Adapters/WmlCalendarAdapter.cs @@ -57,7 +57,7 @@ namespace System.Web.UI.MobileControls.Adapters // This member variable is set each time when calendar info needs to // be accessed and be shared for other helper functions. - private Globalization.Calendar _threadCalendar; + private System.Globalization.Calendar _threadCalendar; private String _textBoxErrorMessage; diff --git a/mcs/class/referencesource/System.Web/AspNetEventSource.cs b/mcs/class/referencesource/System.Web/AspNetEventSource.cs index 47ceee67bd5..13648d0bf6c 100644 --- a/mcs/class/referencesource/System.Web/AspNetEventSource.cs +++ b/mcs/class/referencesource/System.Web/AspNetEventSource.cs @@ -140,6 +140,10 @@ namespace System.Web { // Event signals that ASP.NET has started processing a request. // Overload used only for deducing ETW parameters; use the public entry point instead. // + // Visual Studio Online #222067 - This event is hardcoded to opt-out of EventSource activityID tracking. + // This would normally be done by setting ActivityOptions = EventActivityOptions.Disable in the + // Event attribute, but this causes a dependency between System.Web and mscorlib that breaks servicing. + // // !! WARNING !! // The logic in RequestStartedImpl must be kept in [....] with these parameters, otherwise // type safety violations could occur. @@ -150,6 +154,10 @@ namespace System.Web { } // Event signals that ASP.NET has completed processing a request. + // + // Visual Studio Online #222067 - This event is hardcoded to opt-out of EventSource activityID tracking. + // This would normally be done by setting ActivityOptions = EventActivityOptions.Disable in the + // Event attribute, but this causes a dependency between System.Web and mscorlib that breaks servicing. [Event((int)Events.RequestCompleted, Level = EventLevel.Informational, Task = (EventTask)Tasks.Request, Opcode = EventOpcode.Stop, Version = 1)] [MethodImpl(MethodImplOptions.AggressiveInlining)] public void RequestCompleted() { diff --git a/mcs/class/referencesource/System.Web/Cache/CacheDependency.cs b/mcs/class/referencesource/System.Web/Cache/CacheDependency.cs index 60d00f6e846..9e137fd5fcd 100644 --- a/mcs/class/referencesource/System.Web/Cache/CacheDependency.cs +++ b/mcs/class/referencesource/System.Web/Cache/CacheDependency.cs @@ -909,10 +909,11 @@ namespace System.Web.Caching { return false; } - // - // This method will return only the file dependencies from this dependency - // - internal virtual string[] GetFileDependencies() + /// + /// This method will return only the file dependencies from this dependency + /// + /// + public virtual string[] GetFileDependencies() { #if USE_MEMORY_CACHE if (CacheInternal.UseMemoryCache) { @@ -1121,11 +1122,12 @@ namespace System.Web.Caching { return true; } - - // - // This method will return only the file dependencies from this dependency - // - internal override string[] GetFileDependencies() + + /// + /// This method will return only the file dependencies from this dependency + /// + /// + public override string[] GetFileDependencies() { ArrayList fileNames = null; CacheDependency[] dependencies = null; diff --git a/mcs/class/referencesource/System.Web/Cache/SRef.cs b/mcs/class/referencesource/System.Web/Cache/SRef.cs index 993569bd854..4ecdaa43015 100644 --- a/mcs/class/referencesource/System.Web/Cache/SRef.cs +++ b/mcs/class/referencesource/System.Web/Cache/SRef.cs @@ -10,6 +10,7 @@ namespace System.Web.Caching { internal class SRef { private static Type s_type = Type.GetType("System.SizedReference", true, false); private Object _sizedRef; + private long _lastReportedSize; // This helps tremendously when looking at large dumps internal SRef(Object target) { _sizedRef = HttpRuntime.CreateNonPublicInstance(s_type, new object[] {target}); @@ -24,7 +25,7 @@ namespace System.Web.Caching { _sizedRef, // target null, // args CultureInfo.InvariantCulture); - return (long) o; + return _lastReportedSize = (long) o; } } diff --git a/mcs/class/referencesource/System.Web/Cache/cache.cs b/mcs/class/referencesource/System.Web/Cache/cache.cs index 811f6e7da2d..0dd2f027e68 100644 --- a/mcs/class/referencesource/System.Web/Cache/cache.cs +++ b/mcs/class/referencesource/System.Web/Cache/cache.cs @@ -519,13 +519,14 @@ namespace System.Web.Caching { internal Cache _cachePublic; internal protected CacheMemoryStats _cacheMemoryStats; private object _timerLock = new object(); - private Timer _timer; + private DisposableGCHandleRef _timerHandleRef; private int _currentPollInterval = MEMORYSTATUS_INTERVAL_30_SECONDS; internal int _inCacheManagerThread; internal bool _enableMemoryCollection; internal bool _enableExpiration; internal bool _internalConfigRead; internal SRefMultiple _srefMultiple; + private int _disposed = 0; internal CacheCommon() { _cachePublic = new Cache(0); @@ -537,13 +538,16 @@ namespace System.Web.Caching { internal void Dispose(bool disposing) { if (disposing) { - EnableCacheMemoryTimer(false); - _cacheMemoryStats.Dispose(); + // This method must be tolerant to multiple calls to Dispose on the same instance + if (Interlocked.Exchange(ref _disposed, 1) == 0) { + EnableCacheMemoryTimer(false); + _cacheMemoryStats.Dispose(); + } } } - internal void AddSRefTarget(CacheInternal c) { - _srefMultiple.AddSRefTarget(c); + internal void AddSRefTarget(object o) { + _srefMultiple.AddSRefTarget(o); } internal void SetCacheInternal(CacheInternal cacheInternal) { @@ -591,19 +595,20 @@ namespace System.Web.Caching { if (enable) { - if (_timer == null) { + if (_timerHandleRef == null) { // has not been read yet - _timer = new Timer(new TimerCallback(this.CacheManagerTimerCallback), null, _currentPollInterval, _currentPollInterval); + Timer timer = new Timer(new TimerCallback(this.CacheManagerTimerCallback), null, _currentPollInterval, _currentPollInterval); + _timerHandleRef = new DisposableGCHandleRef(timer); Debug.Trace("Cache", "Started CacheMemoryTimers"); } else { - _timer.Change(_currentPollInterval, _currentPollInterval); + _timerHandleRef.Target.Change(_currentPollInterval, _currentPollInterval); } } else { - Timer timer = _timer; - if (timer != null && Interlocked.CompareExchange(ref _timer, null, timer) == timer) { - timer.Dispose(); + var timerHandleRef = _timerHandleRef; + if (timerHandleRef != null && Interlocked.CompareExchange(ref _timerHandleRef, null, timerHandleRef) == timerHandleRef) { + timerHandleRef.Dispose(); Debug.Trace("Cache", "Stopped CacheMemoryTimers"); } } @@ -620,7 +625,7 @@ namespace System.Web.Caching { void AdjustTimer() { lock (_timerLock) { - if (_timer == null) + if (_timerHandleRef == null) return; // the order of these if statements is important @@ -629,7 +634,7 @@ namespace System.Web.Caching { if (_cacheMemoryStats.IsAboveHighPressure()) { if (_currentPollInterval > MEMORYSTATUS_INTERVAL_5_SECONDS) { _currentPollInterval = MEMORYSTATUS_INTERVAL_5_SECONDS; - _timer.Change(_currentPollInterval, _currentPollInterval); + _timerHandleRef.Target.Change(_currentPollInterval, _currentPollInterval); } return; } @@ -641,7 +646,7 @@ namespace System.Web.Caching { int newPollInterval = Math.Min(CacheMemorySizePressure.PollInterval, MEMORYSTATUS_INTERVAL_30_SECONDS); if (_currentPollInterval != newPollInterval) { _currentPollInterval = newPollInterval; - _timer.Change(_currentPollInterval, _currentPollInterval); + _timerHandleRef.Target.Change(_currentPollInterval, _currentPollInterval); } return; } @@ -649,7 +654,7 @@ namespace System.Web.Caching { // there is no pressure, interval should be the value from config if (_currentPollInterval != CacheMemorySizePressure.PollInterval) { _currentPollInterval = CacheMemorySizePressure.PollInterval; - _timer.Change(_currentPollInterval, _currentPollInterval); + _timerHandleRef.Target.Change(_currentPollInterval, _currentPollInterval); } } } @@ -666,7 +671,7 @@ namespace System.Web.Caching { #endif try { // Dev10 633335: if the timer has been disposed, return without doing anything - if (_timer == null) + if (_timerHandleRef == null) return 0; // The timer thread must always call Update so that the CacheManager @@ -1188,7 +1193,7 @@ namespace System.Web.Caching { _usage = new CacheUsage(this); _lock = new object(); _insertBlock = new ManualResetEvent(true); - cacheCommon.AddSRefTarget(this); + cacheCommon.AddSRefTarget(new { _entries, _expires, _usage }); } /* @@ -1880,24 +1885,32 @@ namespace System.Web.Caching { class CacheMultiple : CacheInternal { int _disposed; - CacheSingle[] _caches; + DisposableGCHandleRef[] _cachesRefs; int _cacheIndexMask; internal CacheMultiple(CacheCommon cacheCommon, int numSingleCaches) : base(cacheCommon) { Debug.Assert(numSingleCaches > 1, "numSingleCaches is not greater than 1"); Debug.Assert((numSingleCaches & (numSingleCaches - 1)) == 0, "numSingleCaches is not a power of 2"); _cacheIndexMask = numSingleCaches - 1; - _caches = new CacheSingle[numSingleCaches]; + + // Each CacheSingle will have its own SRef reporting the size of the data it references. + // Objects in this CacheSingle may have refs to the root Cache and therefore reference other instances of CacheSingle. + // This leads to an unbalanced tree of SRefs and makes GC less efficient while calculating multiple SRefs on multiple cores. + // Using DisposableGCHandleRef here prevents SRefs from calculating data that does not belong to other CacheSingle instances. + _cachesRefs = new DisposableGCHandleRef[numSingleCaches]; for (int i = 0; i < numSingleCaches; i++) { - _caches[i] = new CacheSingle(cacheCommon, this, i); + _cachesRefs[i] = new DisposableGCHandleRef(new CacheSingle(cacheCommon, this, i)); } } protected override void Dispose(bool disposing) { if (disposing) { if (Interlocked.Exchange(ref _disposed, 1) == 0) { - foreach (CacheSingle cacheSingle in _caches) { - cacheSingle.Dispose(); + foreach (var cacheSingleRef in _cachesRefs) { + // Unfortunately the application shutdown logic allows user to access cache even after its disposal. + // We'll keep the GCHandle inside cacheSingleRef until it gets reclaimed during appdomain shutdown. + // And we'll only dispose the Target to preserve the old behavior. + cacheSingleRef.Target.Dispose(); } } } @@ -1908,8 +1921,8 @@ namespace System.Web.Caching { internal override int PublicCount { get { int count = 0; - foreach (CacheSingle cacheSingle in _caches) { - count += cacheSingle.PublicCount; + foreach (var cacheSingleRef in _cachesRefs) { + count += cacheSingleRef.Target.PublicCount; } return count; @@ -1919,8 +1932,8 @@ namespace System.Web.Caching { internal override long TotalCount { get { long count = 0; - foreach (CacheSingle cacheSingle in _caches) { - count += cacheSingle.TotalCount; + foreach (var cacheSingleRef in _cachesRefs) { + count += cacheSingleRef.Target.TotalCount; } return count; @@ -1928,22 +1941,23 @@ namespace System.Web.Caching { } internal override IDictionaryEnumerator CreateEnumerator() { - IDictionaryEnumerator[] enumerators = new IDictionaryEnumerator[_caches.Length]; - for (int i = 0, c = _caches.Length; i < c; i++) { - enumerators[i] = _caches[i].CreateEnumerator(); + IDictionaryEnumerator[] enumerators = new IDictionaryEnumerator[_cachesRefs.Length]; + for (int i = 0, c = _cachesRefs.Length; i < c; i++) { + enumerators[i] = _cachesRefs[i].Target.CreateEnumerator(); } return new AggregateEnumerator(enumerators); } internal CacheSingle GetCacheSingle(int hashCode) { - Debug.Assert(_caches != null && _caches.Length != 0); + Debug.Assert(_cachesRefs != null && _cachesRefs.Length != 0); // Dev10 865907: Math.Abs throws OverflowException for Int32.MinValue if (hashCode < 0) { hashCode = (hashCode == Int32.MinValue) ? 0 : -hashCode; } int index = (hashCode & _cacheIndexMask); - return _caches[index]; + Debug.Assert(_cachesRefs[index].Target != null); + return _cachesRefs[index].Target; } internal override CacheEntry UpdateCache( @@ -1960,15 +1974,15 @@ namespace System.Web.Caching { internal override long TrimIfNecessary(int percent) { long count = 0; - foreach (CacheSingle cacheSingle in _caches) { - count += cacheSingle.TrimIfNecessary(percent); + foreach (var cacheSingleRef in _cachesRefs) { + count += cacheSingleRef.Target.TrimIfNecessary(percent); } return count; } internal override void EnableExpirationTimer(bool enable) { - foreach (CacheSingle cacheSingle in _caches) { - cacheSingle.EnableExpirationTimer(enable); + foreach (var cacheSingleRef in _cachesRefs) { + cacheSingleRef.Target.EnableExpirationTimer(enable); } } } diff --git a/mcs/class/referencesource/System.Web/Compilation/BuildManager.cs b/mcs/class/referencesource/System.Web/Compilation/BuildManager.cs index 9f26b6ed449..65f0272002f 100644 --- a/mcs/class/referencesource/System.Web/Compilation/BuildManager.cs +++ b/mcs/class/referencesource/System.Web/Compilation/BuildManager.cs @@ -2636,6 +2636,7 @@ namespace System.Web.Compilation { } [SuppressMessage("Microsoft.Security", "MSEC1207:UseXmlReaderForLoad", Justification = "Xml file is created by us and only accessible to admins.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Xml file is created by us and only accessible to admins.")] private static bool ReadPrecompMarkerFile(string appRoot, out bool updatable) { updatable = false; diff --git a/mcs/class/referencesource/System.Web/Compilation/PreservationFileReader.cs b/mcs/class/referencesource/System.Web/Compilation/PreservationFileReader.cs index ebcce1503c3..b1903416702 100644 --- a/mcs/class/referencesource/System.Web/Compilation/PreservationFileReader.cs +++ b/mcs/class/referencesource/System.Web/Compilation/PreservationFileReader.cs @@ -61,6 +61,7 @@ internal class PreservationFileReader { } [SuppressMessage("Microsoft.Security", "MSEC1207:UseXmlReaderForLoad", Justification = "Xml file is created by us and only accessible to admins.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Xml file is created by us and only accessible to admins.")] private BuildResult ReadFileInternal(VirtualPath virtualPath, string preservationFile, long hashCode, bool ensureIsUpToDate) { XmlDocument doc = new XmlDocument(); diff --git a/mcs/class/referencesource/System.Web/Compilation/XsdBuildProvider.cs b/mcs/class/referencesource/System.Web/Compilation/XsdBuildProvider.cs index 7802a250b56..94988330594 100644 --- a/mcs/class/referencesource/System.Web/Compilation/XsdBuildProvider.cs +++ b/mcs/class/referencesource/System.Web/Compilation/XsdBuildProvider.cs @@ -30,6 +30,7 @@ using TypedDataSetGenerator=System.Data.Design.TypedDataSetGenerator; internal class XsdBuildProvider: BuildProvider { [SuppressMessage("Microsoft.Security", "MSEC1207:UseXmlReaderForLoad", Justification = "Developer-controlled .xsd files in application directory are implicitly trusted by ASP.Net.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Developer-controlled .xml files in application directory are implicitly trusted by ASP.Net.")] public override void GenerateCode(AssemblyBuilder assemblyBuilder) { #if !FEATURE_PAL // FEATURE_PAL does not support System.Data.Design // Get the namespace that we will use diff --git a/mcs/class/referencesource/System.Web/Configuration/BrowserCapabilitiesCodeGenerator.cs b/mcs/class/referencesource/System.Web/Configuration/BrowserCapabilitiesCodeGenerator.cs index 5dd5d4b54fd..01ef95f8af7 100644 --- a/mcs/class/referencesource/System.Web/Configuration/BrowserCapabilitiesCodeGenerator.cs +++ b/mcs/class/referencesource/System.Web/Configuration/BrowserCapabilitiesCodeGenerator.cs @@ -32,6 +32,7 @@ namespace System.Web.Configuration { using Microsoft.Build.Utilities; using Microsoft.CSharp; + using System.Diagnostics.CodeAnalysis; [PermissionSet(SecurityAction.LinkDemand, Unrestricted = true)] [PermissionSet(SecurityAction.InheritanceDemand, Unrestricted = true)] @@ -400,6 +401,7 @@ namespace System.Web.Configuration { return false; } + [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Developer-controlled .xml files in application directory are implicitly trusted by ASP.Net.")] protected void ProcessBrowserFiles(bool useVirtualPath, string virtualDir) { _browserTree = new BrowserTree(); _defaultTree = new BrowserTree(); @@ -507,6 +509,7 @@ namespace System.Web.Configuration { ProcessCustomBrowserFiles(false, String.Empty); } + [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Developer-controlled .xml files in application directory are implicitly trusted by ASP.Net.")] internal void ProcessCustomBrowserFiles(bool useVirtualPath, string virtualDir) { //get all custom browser files and put them in the "tree" DirectoryInfo browserDirInfo = null; diff --git a/mcs/class/referencesource/System.Web/Configuration/HttpCapabilitiesSectionHandler.cs b/mcs/class/referencesource/System.Web/Configuration/HttpCapabilitiesSectionHandler.cs index cddc9f294af..2bd04aa4ba2 100644 --- a/mcs/class/referencesource/System.Web/Configuration/HttpCapabilitiesSectionHandler.cs +++ b/mcs/class/referencesource/System.Web/Configuration/HttpCapabilitiesSectionHandler.cs @@ -8,6 +8,7 @@ namespace System.Web.Configuration { using System.Collections; using System.Configuration; + using System.Diagnostics.CodeAnalysis; using System.IO; using System.Security; using System.Security.Permissions; @@ -15,7 +16,6 @@ namespace System.Web.Configuration { using System.Web.Configuration; using System.Web.Util; using System.Xml; - using Pair = System.Web.UI.Pair; // @@ -276,6 +276,7 @@ namespace System.Web.Configuration { // // ResolveFiles - parse files referenced with // + [SuppressMessage("Microsoft.Security.Xml", "CA3056:UseXmlReaderForLoad", Justification = "Developer-controlled .xml files in application directory are implicitly trusted by ASP.Net.")] static void ResolveFiles(ParseState parseState, object configurationContext) { // diff --git a/mcs/class/referencesource/System.Web/Configuration/RemoteWebConfigurationHostServer.cs b/mcs/class/referencesource/System.Web/Configuration/RemoteWebConfigurationHostServer.cs index 8100d465916..e40ceb29e59 100644 --- a/mcs/class/referencesource/System.Web/Configuration/RemoteWebConfigurationHostServer.cs +++ b/mcs/class/referencesource/System.Web/Configuration/RemoteWebConfigurationHostServer.cs @@ -21,6 +21,7 @@ namespace System.Web.Configuration { using System.Security.AccessControl; #endif // !FEATURE_PAL using System.Security.Permissions; + using System.Diagnostics.CodeAnalysis; #if !FEATURE_PAL // FEATURE_PAL does not enable COM @@ -215,6 +216,7 @@ namespace System.Web.Configuration { return sb.ToString(); } + [SuppressMessage("Microsoft.Security.Xml", "CA3057:DoNotUseLoadXml", Justification = "Developer-controlled xml contents are implicitly trusted by ASP.Net.")] public string DoEncryptOrDecrypt(bool doEncrypt, string xmlString, string protectionProviderName, string protectionProviderType, string[] paramKeys, string[] paramValues) { Type t = Type.GetType(protectionProviderType, true); diff --git a/mcs/class/referencesource/System.Web/Handlers/TransferRequestHandler.cs b/mcs/class/referencesource/System.Web/Handlers/TransferRequestHandler.cs index 5c74438c23a..0534ff1c51d 100644 --- a/mcs/class/referencesource/System.Web/Handlers/TransferRequestHandler.cs +++ b/mcs/class/referencesource/System.Web/Handlers/TransferRequestHandler.cs @@ -6,11 +6,21 @@ namespace System.Web.Handlers { using System; + using System.Threading.Tasks; using System.Web.Hosting; - - internal class TransferRequestHandler : IHttpHandler { - - public void ProcessRequest(HttpContext context) { + + internal class TransferRequestHandler : IHttpAsyncHandler { + public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData) + { + return TaskAsyncHelper.BeginTask(() => ProcessRequestAsync(context), cb, extraData); + } + + public void EndProcessRequest(IAsyncResult result) + { + TaskAsyncHelper.EndTask(result); + } + + private Task ProcessRequestAsync(HttpContext context) { IIS7WorkerRequest wr = context.WorkerRequest as IIS7WorkerRequest; if (wr == null) { throw new PlatformNotSupportedException(SR.GetString(SR.Requires_Iis_Integrated_Mode)); @@ -24,14 +34,26 @@ namespace System.Web.Handlers { context.Request.EntityBody, null, preserveUser: false); - + // force the completion of the current request so that the // child execution can be performed immediately after unwind - context.ApplicationInstance.EnsureReleaseState(); + var releaseStateTask = context.ApplicationInstance.EnsureReleaseStateAsync(); // DevDiv Bugs 162750: IIS7 Integrated Mode: TransferRequest performance issue // Instead of calling Response.End we call HttpApplication.CompleteRequest() - context.ApplicationInstance.CompleteRequest(); + if (releaseStateTask.IsCompleted) { + context.ApplicationInstance.CompleteRequest(); + return TaskAsyncHelper.CompletedTask; + } + else { + return releaseStateTask.ContinueWith((_) => context.ApplicationInstance.CompleteRequest()); + } + } + + public void ProcessRequest(HttpContext context) + { + string errorMessage = SR.GetString(SR.HttpTaskAsyncHandler_CannotExecuteSynchronously, GetType()); + throw new NotSupportedException(errorMessage); } public bool IsReusable { diff --git a/mcs/class/referencesource/System.Web/Hosting/ApplicationManager.cs b/mcs/class/referencesource/System.Web/Hosting/ApplicationManager.cs index e02ad7fb551..9a24a5b37f2 100644 --- a/mcs/class/referencesource/System.Web/Hosting/ApplicationManager.cs +++ b/mcs/class/referencesource/System.Web/Hosting/ApplicationManager.cs @@ -82,6 +82,9 @@ namespace System.Web.Hosting { // delegate OnRespondToPing private WaitCallback _onRespondToPingWaitCallback; + // flag indicates whether any fatal exception has been recorded + private bool _fatalExceptionRecorded = false; + // single instance of app manager private static ApplicationManager _theAppManager; @@ -154,6 +157,16 @@ namespace System.Web.Hosting { } } + private bool FatalExceptionRecorded + { + get { + return _fatalExceptionRecorded; + } + set { + _fatalExceptionRecorded = value; + } + } + internal static void RecordFatalException(Exception e) { RecordFatalException(AppDomain.CurrentDomain, e); } @@ -168,7 +181,7 @@ namespace System.Web.Hosting { } } - private static void OnUnhandledException(Object sender, UnhandledExceptionEventArgs eventArgs) { + internal static void OnUnhandledException(Object sender, UnhandledExceptionEventArgs eventArgs) { // if the CLR is not terminating, ignore the notification if (!eventArgs.IsTerminating) { return; @@ -184,6 +197,15 @@ namespace System.Web.Hosting { return; } + // If any fatal exception was recorded in applicaiton AppDomains, + // we wouldn't record exceptions in the default AppDomain. + var appManager = GetApplicationManager(); + if (AppDomain.CurrentDomain.IsDefaultAppDomain() && appManager.FatalExceptionRecorded) { + return; + } + + appManager.FatalExceptionRecorded = true; + RecordFatalException(appDomain, exception); } diff --git a/mcs/class/referencesource/System.Web/Hosting/HostingEnvironment.cs b/mcs/class/referencesource/System.Web/Hosting/HostingEnvironment.cs index d5d2c15e352..27ce613025e 100644 --- a/mcs/class/referencesource/System.Web/Hosting/HostingEnvironment.cs +++ b/mcs/class/referencesource/System.Web/Hosting/HostingEnvironment.cs @@ -184,6 +184,11 @@ namespace System.Web.Hosting { // start watching for app domain unloading _onAppDomainUnload = new EventHandler(OnAppDomainUnload); Thread.GetDomain().DomainUnload += _onAppDomainUnload; + + // VSO 160528: We used to listen to the default AppDomain's UnhandledException only. + // However, non-serializable exceptions cannot be passed to the default domain. Therefore + // we should try to log exceptions in application AppDomains. + Thread.GetDomain().UnhandledException += new UnhandledExceptionEventHandler(ApplicationManager.OnUnhandledException); } internal long TrimCache(int percent) { diff --git a/mcs/class/referencesource/System.Web/HttpApplication.cs b/mcs/class/referencesource/System.Web/HttpApplication.cs index eff422558e3..41564928cce 100644 --- a/mcs/class/referencesource/System.Web/HttpApplication.cs +++ b/mcs/class/referencesource/System.Web/HttpApplication.cs @@ -500,17 +500,37 @@ namespace System.Web { } } - // DevDiv Bugs 151914: Release session state before executing child request - internal void EnsureReleaseState() { + private ISessionStateModule FindISessionStateModule() { + if (!HttpRuntime.UseIntegratedPipeline) + return null; + if (_moduleCollection != null) { for (int i = 0; i < _moduleCollection.Count; i++) { - IHttpModule module = _moduleCollection.Get(i); - if (module is SessionStateModule) { - ((SessionStateModule) module).EnsureReleaseState(this); - break; + ISessionStateModule module = _moduleCollection.Get(i) as ISessionStateModule; + if (module != null) { + return module; } } } + + return null; + } + + // DevDiv Bugs 151914: Release session state before executing child request + internal void EnsureReleaseState() { + ISessionStateModule module = FindISessionStateModule(); + if (module != null) { + module.ReleaseSessionState(Context); + } + } + + internal Task EnsureReleaseStateAsync() { + ISessionStateModule module = FindISessionStateModule(); + if (module != null) { + return module.ReleaseSessionStateAsync(Context); + } + + return TaskAsyncHelper.CompletedTask; } /// diff --git a/mcs/class/referencesource/System.Web/HttpCacheParams.cs b/mcs/class/referencesource/System.Web/HttpCacheParams.cs index 6d4bae316f5..f54da48a4aa 100644 --- a/mcs/class/referencesource/System.Web/HttpCacheParams.cs +++ b/mcs/class/referencesource/System.Web/HttpCacheParams.cs @@ -39,10 +39,11 @@ namespace System.Web { _ignoreParams = -1; } - /* - * Reset based on the cached vary headers. - */ - internal void ResetFromParams(String[] parameters) { + /// + /// Set the Parameters in Cache Vary + /// + /// + public void SetParams(string[] parameters) { int i, n; Reset(); @@ -75,16 +76,20 @@ namespace System.Web { return _ignoreParams == 1 || _paramsStar || _parameters != null; } - internal String[] GetParams() { - String[] s = null; + /// + /// Get the Parameters in Cache Vary + /// + /// + public string[] GetParams() { + string[] s = null; Object item; int i, j, c, n; if (_ignoreParams == 1) { - s = new String[1] {String.Empty}; + s = new string[1] {string.Empty}; } else if (_paramsStar) { - s = new String[1] {"*"}; + s = new string[1] {"*"}; } else if (_parameters != null) { n = _parameters.Size; @@ -102,7 +107,7 @@ namespace System.Web { for (i = 0; i < n; i++) { item = _parameters.GetValue(i); if (item != null) { - s[j] = (String) item; + s[j] = (string) item; j++; } } @@ -116,7 +121,7 @@ namespace System.Web { // // Public methods and properties - // + // /// diff --git a/mcs/class/referencesource/System.Web/HttpCachePolicy.cs b/mcs/class/referencesource/System.Web/HttpCachePolicy.cs index 5cdde5d3006..0e5efebd84f 100644 --- a/mcs/class/referencesource/System.Web/HttpCachePolicy.cs +++ b/mcs/class/referencesource/System.Web/HttpCachePolicy.cs @@ -30,7 +30,7 @@ namespace System.Web { // // Public constants for cache-control // - + /// /// @@ -573,12 +573,10 @@ namespace System.Web { int i, n; string[] fields; - - _utcTimestampRequest = utcTimestampRequest; - - _varyByContentEncodings.ResetFromContentEncodings(settings.VaryByContentEncodings); - _varyByHeaders.ResetFromHeaders(settings.VaryByHeaders); - _varyByParams.ResetFromParams(settings.VaryByParams); + + _varyByContentEncodings.SetContentEncodings(settings.VaryByContentEncodings); + _varyByHeaders.SetHeaders(settings.VaryByHeaders); + _varyByParams.SetParams(settings.VaryByParams); _isModified = settings.IsModified; _hasSetCookieHeader = settings.hasSetCookieHeader; @@ -645,7 +643,11 @@ namespace System.Web { } } - internal bool IsModified() { + /// + /// Return true if the CachePolicy has been modified + /// + /// + public bool IsModified() { return _isModified || _varyByContentEncodings.IsModified() || _varyByHeaders.IsModified() || _varyByParams.IsModified(); } @@ -771,20 +773,18 @@ namespace System.Web { return; } - Debug.Assert((_utcTimestampCreated == DateTime.MinValue && _utcTimestampRequest == DateTime.MinValue) || - (_utcTimestampCreated != DateTime.MinValue && _utcTimestampRequest != DateTime.MinValue), - "_utcTimestampCreated and _utcTimestampRequest are out of [....] in UpdateCachedHeaders"); - + //To enable Out of Band OutputCache Module support, we will always refresh the UtcTimestampRequest. if (_utcTimestampCreated == DateTime.MinValue) { - _utcTimestampCreated = _utcTimestampRequest = response.Context.UtcTimestamp; + _utcTimestampCreated = response.Context.UtcTimestamp; } + _utcTimestampRequest = response.Context.UtcTimestamp; if (_slidingExpiration != 1) { _slidingDelta = TimeSpan.Zero; } else if (_isMaxAgeSet) { _slidingDelta = _maxAge; - } + } else if (_isExpiresSet) { _slidingDelta = _utcExpires - _utcTimestampCreated; } @@ -840,7 +840,7 @@ namespace System.Web { } sb.Append('\"'); - } + } if (_noStore) { AppendValueToHeader(sb, "no-store"); @@ -1056,10 +1056,10 @@ namespace System.Web { headers.Add(_headerVaryBy); } } - + /* - * Public methods - */ + * Public methods + */ internal HttpCachePolicySettings GetCurrentSettings(HttpResponse response) { String[] varyByContentEncodings; @@ -1191,6 +1191,16 @@ namespace System.Web { return absoluteExpiration; } + // Expose this property to OutputCacheUtility class + // In order to enable Out of Band output cache module to access the Validation Callback Info + internal IEnumerable GetValidationCallbacks() { + if (_validationCallbackInfo == null) { + return new ArrayList(); + } + + return _validationCallbackInfo; + } + /* * Cache at server? */ @@ -1203,7 +1213,11 @@ namespace System.Web { _noServerCaching = true; } - internal bool GetNoServerCaching() { + /// + /// Return True if we should stops all server caching for current response + /// + /// + public bool GetNoServerCaching() { return _noServerCaching; } @@ -1229,6 +1243,13 @@ namespace System.Web { _varyByCustom = custom; } + /// + /// Get the Vary by Custom Value + /// + /// + public string GetVaryByCustom() { + return _varyByCustom; + } /* * Cache-Control: extension */ @@ -1250,6 +1271,14 @@ namespace System.Web { } } + /// + /// Get Cache Extensions Value + /// + /// + public string GetCacheExtensions() { + return _cacheExtension; + } + /* * Cache-Control: no-transform */ @@ -1263,11 +1292,27 @@ namespace System.Web { _noTransforms = true; } + /// + /// Return true if No-transform directive, enables the sending of the CacheControl + /// + /// + public bool GetNoTransforms() { + return _noTransforms; + } + internal void SetIgnoreRangeRequests() { Dirtied(); _ignoreRangeRequests = true; } + /// + /// Return true if ignore range request + /// + /// + public bool GetIgnoreRangeRequests() { + return _ignoreRangeRequests; + } + /// /// Contains policy for the Vary: header. /// @@ -1320,11 +1365,15 @@ namespace System.Web { } } - internal HttpCacheability GetCacheability() { + /// + /// Get the Cache-control (public, private and no-cache) directive + /// + /// + public HttpCacheability GetCacheability() { return _cacheability; } - - + + /// /// Sets the Cache-Control header to one of the values of HttpCacheability in /// conjunction with a field-level exclusion directive. @@ -1376,6 +1425,14 @@ namespace System.Web { Dirtied(); _hasUserProvidedDependencies = hasUserProvidedDependencies; } + + /// + /// return true if no store is set + /// + /// + public bool GetNoStore() { + return _noStore; + } /* * Expiration policy. @@ -1405,6 +1462,14 @@ namespace System.Web { } } + /// + /// Return the expire header as absolute expire datetime + /// + /// + public DateTime GetExpires() { + return _utcExpires; + } + /* * Cache-Control: max-age=delta-seconds */ @@ -1428,6 +1493,14 @@ namespace System.Web { } } + /// + /// Get the Cache-Control Max Age + /// + /// + public TimeSpan GetMaxAge() { + return _maxAge; + } + // Suppress max-age and s-maxage in cache-control header (required for IIS6 kernel mode cache) internal void SetNoMaxAgeInCacheControl() { _noMaxAgeInCacheControl = true; @@ -1452,6 +1525,14 @@ namespace System.Web { } } + /// + /// Get the Cache-Control: Proxy Max Age Value + /// + /// + public TimeSpan GetProxyMaxAge() { + return _proxyMaxAge; + } + /* * Sliding Expiration */ @@ -1470,6 +1551,17 @@ namespace System.Web { } } + /// + /// Return true if to make expiration sliding. that is, if cached, it should be renewed with each + /// response. This feature is identical in spirit to the IIS + /// configuration option to add an expiration header relative to the current response + /// time. This feature is identical in spirit to the IIS configuration option to add + /// an expiration header relative to the current response time. + /// + /// + public bool HasSlidingExpiration() { + return _slidingExpiration == 1; + } public void SetValidUntilExpires(bool validUntilExpires) { if (_validUntilExpires == -1 || _validUntilExpires == 1) { @@ -1478,6 +1570,13 @@ namespace System.Web { } } + /// + /// Return true if valid until expires + /// + /// + public bool IsValidUntilExpires() { + return _validUntilExpires == 1; + } public void SetAllowResponseInBrowserHistory(bool allow) { if (_allowInHistory == -1 || _allowInHistory == 1) { @@ -1512,7 +1611,17 @@ namespace System.Web { } } - /* + /// + /// Get the Cache-Control: header to reflect either the must-revalidate or + /// proxy-revalidate directives. + /// The default is to not send either of these directives unless explicitly enabled using this method. + /// + /// + public HttpCacheRevalidation GetRevalidation() { + return _revalidation; + } + + /* * Etag */ @@ -1537,6 +1646,16 @@ namespace System.Web { _etag = etag; } + /// + /// Get the ETag header. Once an ETag is set, + /// subsequent attempts to set it will fail and an exception will be thrown. + /// + /// + public string GetETag() { + return _etag; + } + + /* * Last-Modified: RFC Date */ @@ -1577,6 +1696,14 @@ namespace System.Web { } } + /// + /// Get the Last-Modified header. + /// + /// + public DateTime GetUtcLastModified() { + return _utcLastModified; + } + /// /// Sets the Last-Modified: header based on the timestamps of the @@ -1587,6 +1714,15 @@ namespace System.Web { _generateLastModifiedFromFiles = true; } + /// + /// Return true if the Last-Modified header is set to base on the timestamps of the + /// file dependencies of the handler. + /// + /// + public bool GetLastModifiedFromFileDependencies() { + return _generateLastModifiedFromFiles; + } + /// /// Sets the Etag header based on the timestamps of the file @@ -1601,6 +1737,14 @@ namespace System.Web { _generateEtagFromFiles = true; } + /// + /// Return true if the Etag header has been set to base on the timestamps of the file + /// dependencies of the handler + /// + /// + public bool GetETagFromFileDependencies() { + return _generateEtagFromFiles; + } public void SetOmitVaryStar(bool omit) { Dirtied(); @@ -1610,6 +1754,13 @@ namespace System.Web { } } + /// + /// Return true if to omit Vary Star + /// + /// + public int GetOmitVaryStar() { + return _omitVaryStar; + } /// /// Registers a validation callback for the current response. @@ -1628,5 +1779,16 @@ namespace System.Web { _validationCallbackInfo.Add(new ValidationCallbackInfo(handler, data)); } + /// + /// Utc Timestamp Created + /// + public DateTime UtcTimestampCreated { + get { + return _utcTimestampCreated; + } + set { + _utcTimestampCreated = value; + } + } } } diff --git a/mcs/class/referencesource/System.Web/HttpCacheVary.cs b/mcs/class/referencesource/System.Web/HttpCacheVary.cs index e55c71d0514..7f8a952f004 100644 --- a/mcs/class/referencesource/System.Web/HttpCacheVary.cs +++ b/mcs/class/referencesource/System.Web/HttpCacheVary.cs @@ -37,10 +37,12 @@ namespace System.Web { _headers = null; } - /* - * Reset based on the cached vary headers. - */ - internal void ResetFromHeaders(String[] headers) { + /// + /// Set the Headers in Cache Vary + /// + /// + public void SetHeaders(string[] headers) { + int i, n; if (headers == null) { @@ -48,7 +50,7 @@ namespace System.Web { _varyStar = false; _headers = null; } - else { + else { _isModified = true; if (headers[0].Equals("*")) { Debug.Assert(headers.Length == 1, "headers.Length == 1"); @@ -97,19 +99,19 @@ namespace System.Web { return null; } + + /// + /// Get the Headers in Cache Vary + /// + /// + public string[] GetHeaders() { + string[] s = null; - /* - * Returns the headers, for package access only. - * - * @return the headers. - */ - internal String[] GetHeaders() { - String[] s = null; Object item; int i, j, c, n; if (_varyStar) { - return new String[1] {"*"}; + return new string[1] {"*"}; } else if (_headers != null) { n = _headers.Size; @@ -127,7 +129,7 @@ namespace System.Web { for (i = 0; i < n; i++) { item = _headers.GetValue(i); if (item != null) { - s[j] = (String) item; + s[j] = (string) item; j++; } } @@ -138,7 +140,7 @@ namespace System.Web { return s; } - + // // Public methods and properties // diff --git a/mcs/class/referencesource/System.Web/HttpCacheVaryByContentEncodings.cs b/mcs/class/referencesource/System.Web/HttpCacheVaryByContentEncodings.cs index fe1e6d355f2..236adffa9a0 100644 --- a/mcs/class/referencesource/System.Web/HttpCacheVaryByContentEncodings.cs +++ b/mcs/class/referencesource/System.Web/HttpCacheVaryByContentEncodings.cs @@ -32,11 +32,13 @@ namespace System.Web { _isModified = false; _contentEncodings = null; } + + /// + /// Set the Content Encodings in Cache Vary + /// + /// + public void SetContentEncodings(string[] contentEncodings) { - /* - * Reset based on content encodings. - */ - internal void ResetFromContentEncodings(String[] contentEncodings) { Reset(); if (contentEncodings != null) { _isModified = true; @@ -75,9 +77,18 @@ namespace System.Web { internal bool IsModified() { return _isModified; } - - internal String[] GetContentEncodings() { - return _contentEncodings; + + /// + /// Get the Content Encodings in Cache Vary + /// + /// + public string[] GetContentEncodings() { + if (_contentEncodings != null) { + string[] contentEncodings = new string[_contentEncodings.Length]; + _contentEncodings.CopyTo(contentEncodings, 0); + return contentEncodings; + } + return null; } // diff --git a/mcs/class/referencesource/System.Web/HttpContext.cs b/mcs/class/referencesource/System.Web/HttpContext.cs index 4d02a0a8a8f..812c779064e 100644 --- a/mcs/class/referencesource/System.Web/HttpContext.cs +++ b/mcs/class/referencesource/System.Web/HttpContext.cs @@ -22,6 +22,7 @@ namespace System.Web { using System.Linq; using System.Net; using System.Reflection; + using System.Runtime.CompilerServices; using System.Runtime.Remoting.Messaging; using System.Security.Permissions; using System.Security.Principal; @@ -1009,6 +1010,8 @@ namespace System.Web { if (_delayedSessionState) { lock (this) { if (_delayedSessionState) { + Debug.Assert(_sessionStateModule != null, "_sessionStateModule != null"); + // If it's not null, it means we have a delayed session state item _sessionStateModule.InitStateStoreItem(true); _delayedSessionState = false; @@ -1020,8 +1023,21 @@ namespace System.Web { } } + [MethodImpl(MethodImplOptions.NoInlining)] internal void EnsureSessionStateIfNecessary() { - Debug.Assert(_sessionStateModule != null, "_sessionStateModule != null"); + if (_sessionStateModule == null) + { + // If _sessionStateModule is null, we wouldn't be able to call + // _sessionStateModule.EnsureStateStoreItemLocked(), so we return here. + // _sessionStateModule could be null in the following cases, + // 1. No session state acquired. + // 2. HttpResponse.Flush() happens after session state being released. + // 3. The session state module in use is not System.Web.SessionState.SessionStateModule. + // + // This method is for the in-framework SessionStateModule only. + // OOB SessionStateModule can achieve this by using HttpResponse.AddOnSendingHeaders. + return; + } HttpSessionState session = (HttpSessionState)Items[SessionStateUtility.SESSION_KEY]; @@ -1042,7 +1058,6 @@ namespace System.Web { } internal void RemoveHttpSessionStateModule() { - Debug.Assert(_sessionStateModule != null, "_sessionStateModule != null"); _delayedSessionState = false; _sessionStateModule = null; } diff --git a/mcs/class/referencesource/System.Web/HttpResponse.cs b/mcs/class/referencesource/System.Web/HttpResponse.cs index b92ce62520b..db4f721437c 100644 --- a/mcs/class/referencesource/System.Web/HttpResponse.cs +++ b/mcs/class/referencesource/System.Web/HttpResponse.cs @@ -1126,9 +1126,18 @@ namespace System.Web { } // restore content - _httpWriter.UseSnapshot(rawResponse.Buffers); + SetResponseBuffers(rawResponse.Buffers); + + _suppressContent = !sendBody; + } + + // set the response content bufffers + internal void SetResponseBuffers(ArrayList buffers) { + if (_httpWriter == null) { + throw new HttpException(SR.GetString(SR.Cannot_use_snapshot_for_TextWriter)); + } - _suppressContent = !sendBody; + _httpWriter.UseSnapshot(buffers); } internal void CloseConnectionAfterError() { diff --git a/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelMetadataProvider.cs b/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelMetadataProvider.cs index aa91b330627..3c0296df9e3 100644 --- a/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelMetadataProvider.cs +++ b/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelMetadataProvider.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using System.ComponentModel.DataAnnotations; using System.Linq; + using System.Web.Globalization; public class DataAnnotationsModelMetadataProvider : AssociatedMetadataProvider { @@ -11,7 +12,7 @@ List attributeList = new List(attributes); DisplayColumnAttribute displayColumnAttribute = attributeList.OfType().FirstOrDefault(); DataAnnotationsModelMetadata result = new DataAnnotationsModelMetadata(this, containerType, modelAccessor, modelType, propertyName, displayColumnAttribute); - + #if UNDEF // Do [HiddenInput] before [UIHint], so you can override the template hint HiddenInputAttribute hiddenInputAttribute = attributeList.OfType().FirstOrDefault(); @@ -71,12 +72,13 @@ DisplayAttribute display = attributes.OfType().FirstOrDefault(); string name = null; if (display != null) { - result.Description = display.GetDescription(); - result.ShortDisplayName = display.GetShortName(); - result.Watermark = display.GetPrompt(); - result.Order = display.GetOrder() ?? ModelMetadata.DefaultOrder; + var displayAdapter = new DisplayAttributeAdapter(display); + result.Description = displayAdapter.GetDescription(); + result.ShortDisplayName = displayAdapter.GetShortName(); + result.Watermark = displayAdapter.GetPrompt(); + result.Order = displayAdapter.GetOrder() ?? ModelMetadata.DefaultOrder; - name = display.GetName(); + name = displayAdapter.GetName(); } if (name != null) { diff --git a/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelValidator.cs b/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelValidator.cs index cff887cbb5f..79bf561a2ad 100644 --- a/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelValidator.cs +++ b/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelValidator.cs @@ -2,8 +2,10 @@ using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; + using System.Threading; + using System.Web.Globalization; - public class DataAnnotationsModelValidator : ModelValidator { + public class DataAnnotationsModelValidator : ModelValidator { public DataAnnotationsModelValidator(ModelMetadata metadata, ModelBindingExecutionContext context, ValidationAttribute attribute) : base(metadata, context) { @@ -18,7 +20,24 @@ protected internal string ErrorMessage { get { - return Attribute.FormatErrorMessage(Metadata.GetDisplayName()); + if (UseStringLocalizerProvider) { + var errorMsg = GetLocalizedString(Attribute.ErrorMessage); + + return errorMsg ?? Attribute.FormatErrorMessage(Metadata.GetDisplayName()); + } + else { + return Attribute.FormatErrorMessage(Metadata.GetDisplayName()); + } + } + } + + protected string GetLocalizedString(string name, params object[] arguments) { + if (StringLocalizerProviders.DataAnnotationStringLocalizerProvider != null) { + return StringLocalizerProviders.DataAnnotationStringLocalizerProvider + .GetLocalizedString(Thread.CurrentThread.CurrentUICulture, name, arguments); + } + else { + return null; } } @@ -55,9 +74,37 @@ ValidationResult result = Attribute.GetValidationResult(Metadata.Model, context); if (result != ValidationResult.Success) { yield return new ModelValidationResult { - Message = result.ErrorMessage + Message = GetValidationErrorMessage(result) }; } } + + protected virtual string GetLocalizedErrorMessage(string errorMessage) { + return GetLocalizedString(errorMessage, Metadata.GetDisplayName()); + } + + private string GetValidationErrorMessage(ValidationResult result) { + string errorMsg; + + if (UseStringLocalizerProvider) { + errorMsg = GetLocalizedErrorMessage(Attribute.ErrorMessage); + + errorMsg = errorMsg ?? result.ErrorMessage; + } + else { + errorMsg = result.ErrorMessage; + } + return errorMsg; + } + + private bool UseStringLocalizerProvider { + get { + // if developer already uses existing localization feature, + // then we don't opt in the new localization feature. + return (!string.IsNullOrEmpty(Attribute.ErrorMessage) && + string.IsNullOrEmpty(Attribute.ErrorMessageResourceName) && + Attribute.ErrorMessageResourceType == null); + } + } } } diff --git a/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelValidatorProvider.cs b/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelValidatorProvider.cs index 11cce2416e2..ae952e12a8c 100644 --- a/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelValidatorProvider.cs +++ b/mcs/class/referencesource/System.Web/ModelBinding/DataAnnotationsModelValidatorProvider.cs @@ -1,5 +1,5 @@ namespace System.Web.ModelBinding { - using System; +using System; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Diagnostics.CodeAnalysis; @@ -7,6 +7,7 @@ using System.Globalization; using System.Linq; using System.Reflection; using System.Threading; +using System.Web.Globalization; // A factory for validators based on ValidationAttribute public delegate ModelValidator DataAnnotationsModelValidationFactory(ModelMetadata metadata, ModelBindingExecutionContext context, ValidationAttribute attribute); @@ -26,7 +27,7 @@ using System.Threading; public class DataAnnotationsModelValidatorProvider : AssociatedValidatorProvider { private static bool _addImplicitRequiredAttributeForValueTypes = true; private static ReaderWriterLockSlim _adaptersLock = new ReaderWriterLockSlim(); - + // Factories for validation attributes internal static DataAnnotationsModelValidationFactory DefaultAttributeFactory = @@ -49,6 +50,14 @@ using System.Threading; typeof(StringLengthAttribute), (metadata, context, attribute) => new StringLengthAttributeAdapter(metadata, context, (StringLengthAttribute)attribute) }, + { + typeof(MinLengthAttribute), + (metadata, context, attribute) => new MinLengthAttributeAdapter(metadata, context, (MinLengthAttribute)attribute) + }, + { + typeof(MaxLengthAttribute), + (metadata, context, attribute) => new MaxLengthAttributeAdapter(metadata, context, (MaxLengthAttribute)attribute) + }, }; // Factories for IValidatableObject models @@ -66,7 +75,7 @@ using System.Threading; _addImplicitRequiredAttributeForValueTypes = value; } } - + protected override IEnumerable GetValidators(ModelMetadata metadata, ModelBindingExecutionContext context, IEnumerable attributes) { _adaptersLock.EnterReadLock(); diff --git a/mcs/class/referencesource/System.Web/ModelBinding/RangeAttributeAdapter.cs b/mcs/class/referencesource/System.Web/ModelBinding/RangeAttributeAdapter.cs index 2c5acf046fc..28858643c11 100644 --- a/mcs/class/referencesource/System.Web/ModelBinding/RangeAttributeAdapter.cs +++ b/mcs/class/referencesource/System.Web/ModelBinding/RangeAttributeAdapter.cs @@ -6,6 +6,11 @@ : base(metadata, context, attribute) { } + protected override string GetLocalizedErrorMessage(string errorMessage) { + return GetLocalizedString(errorMessage, Metadata.GetDisplayName(), Attribute.Minimum, Attribute.Maximum); + + } + #if UNDEF public override IEnumerable GetClientValidationRules() { string errorMessage = ErrorMessage; // Per Dev10 Bug #923283, need to make sure ErrorMessage is called before Minimum/Maximum diff --git a/mcs/class/referencesource/System.Web/ModelBinding/RegularExpressionAttributeAdapter.cs b/mcs/class/referencesource/System.Web/ModelBinding/RegularExpressionAttributeAdapter.cs index c5c0f0d527f..2a49853c2f6 100644 --- a/mcs/class/referencesource/System.Web/ModelBinding/RegularExpressionAttributeAdapter.cs +++ b/mcs/class/referencesource/System.Web/ModelBinding/RegularExpressionAttributeAdapter.cs @@ -6,6 +6,10 @@ : base(metadata, context, attribute) { } + protected override string GetLocalizedErrorMessage(string errorMessage) { + return GetLocalizedString(errorMessage, Metadata.GetDisplayName(), Attribute.Pattern); + } + #if UNDEF public override IEnumerable GetClientValidationRules() { return new[] { new ModelClientValidationRegexRule(ErrorMessage, Attribute.Pattern) }; diff --git a/mcs/class/referencesource/System.Web/ModelBinding/StringLengthAttributeAdapter.cs b/mcs/class/referencesource/System.Web/ModelBinding/StringLengthAttributeAdapter.cs index 354cc3a8617..a27cba17dfb 100644 --- a/mcs/class/referencesource/System.Web/ModelBinding/StringLengthAttributeAdapter.cs +++ b/mcs/class/referencesource/System.Web/ModelBinding/StringLengthAttributeAdapter.cs @@ -6,6 +6,10 @@ : base(metadata, context, attribute) { } + protected override string GetLocalizedErrorMessage(string errorMessage) { + return GetLocalizedString(errorMessage, Metadata.GetDisplayName(), Attribute.MinimumLength, Attribute.MaximumLength); + } + #if UNDEF public override IEnumerable GetClientValidationRules() { return new[] { new ModelClientValidationStringLengthRule(ErrorMessage, Attribute.MinimumLength, Attribute.MaximumLength) }; diff --git a/mcs/class/referencesource/System.Web/Security/Cryptography/CryptoAlgorithms.cs b/mcs/class/referencesource/System.Web/Security/Cryptography/CryptoAlgorithms.cs index a4fcc08f63c..a4147901f2e 100644 --- a/mcs/class/referencesource/System.Web/Security/Cryptography/CryptoAlgorithms.cs +++ b/mcs/class/referencesource/System.Web/Security/Cryptography/CryptoAlgorithms.cs @@ -44,6 +44,7 @@ namespace System.Web.Security.Cryptography { return new DESCryptoServiceProvider(); } + [SuppressMessage("Microsoft.Security.Cryptography", "CA5354:SHA1CannotBeUsed", Justification = @"This is only used by legacy code; new features do not use this algorithm.")] internal static HMACSHA1 CreateHMACSHA1() { return new HMACSHA1(); } diff --git a/mcs/class/referencesource/System.Web/Security/FormsIdentity.cs b/mcs/class/referencesource/System.Web/Security/FormsIdentity.cs index 2fba9c4592a..a07c223408d 100644 --- a/mcs/class/referencesource/System.Web/Security/FormsIdentity.cs +++ b/mcs/class/referencesource/System.Web/Security/FormsIdentity.cs @@ -17,6 +17,7 @@ namespace System.Web.Security { using System.Security; using System.Security.Claims; using System.Security.Permissions; + using System.Security.Principal; /// /// This class is an IIdentity derived class @@ -77,7 +78,7 @@ namespace System.Web.Security { /// Constructor. /// protected FormsIdentity(FormsIdentity identity) - : base(identity) + : base((IIdentity)identity) { _Ticket = identity._Ticket; } diff --git a/mcs/class/referencesource/System.Web/State/SessionStateModule.cs b/mcs/class/referencesource/System.Web/State/SessionStateModule.cs index 2e9144cceb4..84b3d55a8ae 100644 --- a/mcs/class/referencesource/System.Web/State/SessionStateModule.cs +++ b/mcs/class/referencesource/System.Web/State/SessionStateModule.cs @@ -27,6 +27,7 @@ namespace System.Web.SessionState { using System.Globalization; using System.Security.Permissions; using System.Text; + using System.Threading.Tasks; using System.Web.Hosting; using System.Web.Management; using Microsoft.Win32; @@ -111,7 +112,7 @@ namespace System.Web.SessionState { /// /// [To be supplied.] /// - public sealed class SessionStateModule : IHttpModule { + public sealed class SessionStateModule : ISessionStateModule { internal const string SQL_CONNECTION_STRING_DEFAULT = "data source=localhost;Integrated Security=SSPI"; internal const string STATE_CONNECTION_STRING_DEFAULT = "tcpip=loopback:42424"; @@ -1446,15 +1447,19 @@ namespace System.Web.SessionState { } } } - - // DevDiv Bugs 151914: Release session state before executing child request - internal void EnsureReleaseState(HttpApplication app) { + + public void ReleaseSessionState(HttpContext context) { if (HttpRuntime.UseIntegratedPipeline && _acquireCalled && !_releaseCalled) { try { - OnReleaseState(app, null); + OnReleaseState(context.ApplicationInstance, null); } catch { } } } + + public Task ReleaseSessionStateAsync(HttpContext context) { + ReleaseSessionState(context); + return TaskAsyncHelper.CompletedTask; + } } } diff --git a/mcs/class/referencesource/System.Web/State/SessionStateUtil.cs b/mcs/class/referencesource/System.Web/State/SessionStateUtil.cs index 8116fbc2711..19c6d73938a 100644 --- a/mcs/class/referencesource/System.Web/State/SessionStateUtil.cs +++ b/mcs/class/referencesource/System.Web/State/SessionStateUtil.cs @@ -73,6 +73,24 @@ namespace System.Web.SessionState { return context.Application.SessionStaticObjects.Clone(); } + /// + /// Gets a value that indicates whether session state is required by the context. + /// + /// The HttpContext. + /// A value that indicates whether session state is required by the context. + static public bool IsSessionStateRequired(HttpContext context) { + return context.RequiresSessionState; + } + + /// + /// Gets a value that indicates whether session state is read-only in the context. + /// + /// The HttpContext. + /// A value that indicates whether session state is read-only in the context. + static public bool IsSessionStateReadOnly(HttpContext context) { + return context.ReadOnlySessionState; + } + internal static SessionStateStoreData CreateLegitStoreData(HttpContext context, ISessionStateItemCollection sessionItems, HttpStaticObjectsCollection staticObjects, diff --git a/mcs/class/referencesource/System.Web/TaskAsyncHelper.cs b/mcs/class/referencesource/System.Web/TaskAsyncHelper.cs index 2558f75a0d5..85e2bef8a05 100644 --- a/mcs/class/referencesource/System.Web/TaskAsyncHelper.cs +++ b/mcs/class/referencesource/System.Web/TaskAsyncHelper.cs @@ -16,6 +16,8 @@ namespace System.Web { internal static class TaskAsyncHelper { + private static readonly Task s_completedTask = Task.FromResult(null); + internal static IAsyncResult BeginTask(Func taskFunc, AsyncCallback callback, object state) { Task task = taskFunc(); if (task == null) { @@ -76,5 +78,10 @@ namespace System.Web { taskWrapper.Task.GetAwaiter().GetResult(); } + internal static Task CompletedTask { + get { + return s_completedTask; + } + } } } diff --git a/mcs/class/referencesource/System.Web/UI/PartialCachingControl.cs b/mcs/class/referencesource/System.Web/UI/PartialCachingControl.cs index 9efc13a5871..e70f02a264d 100644 --- a/mcs/class/referencesource/System.Web/UI/PartialCachingControl.cs +++ b/mcs/class/referencesource/System.Web/UI/PartialCachingControl.cs @@ -6,27 +6,27 @@ namespace System.Web.UI { -using System; -using System.IO; -using System.Text; -using System.Collections; -using System.Collections.Specialized; -using System.ComponentModel; -using System.ComponentModel.Design; -using System.Globalization; -using System.Web; -using System.Web.Util; -using System.Web.UI.HtmlControls; -using System.Web.UI.WebControls; -using System.Web.Caching; -using System.Web.Compilation; -using System.Web.Configuration; -using System.Security.Permissions; - - -// Keeps track of one call to Page Register* API -// The semantics of the fields depends to the call type -[Serializable] + using System; + using System.IO; + using System.Text; + using System.Collections; + using System.Collections.Specialized; + using System.ComponentModel; + using System.ComponentModel.Design; + using System.Globalization; + using System.Web; + using System.Web.Util; + using System.Web.UI.HtmlControls; + using System.Web.UI.WebControls; + using System.Web.Caching; + using System.Web.Compilation; + using System.Web.Configuration; + using System.Security.Permissions; + + + // Keeps track of one call to Page Register* API + // The semantics of the fields depends to the call type + [Serializable] internal class RegisterCallData { internal ClientAPIRegisterType Type; internal ScriptKey Key; @@ -406,8 +406,8 @@ public abstract class BasePartialCachingControl : Control { } else { string[] varyByParams = null; - if (_varyByParamsCollection != null) - varyByParams = _varyByParamsCollection.GetParams(); + if (_varyByParamsCollection != null) + varyByParams = _varyByParamsCollection.GetParams(); cachedVary = new ControlCachedVary(varyByParams, _varyByControlsCollection, _varyByCustom); @@ -576,7 +576,7 @@ public abstract class BasePartialCachingControl : Control { string[] varyByParamsStrings = varyByParams.Split(varySeparator); _varyByParamsCollection = new HttpCacheVaryByParams(); - _varyByParamsCollection.ResetFromParams(varyByParamsStrings); + _varyByParamsCollection.SetParams(varyByParamsStrings); } internal void RegisterPostBackScript() { diff --git a/mcs/class/referencesource/System.Web/UI/WebControls/Calendar.cs b/mcs/class/referencesource/System.Web/UI/WebControls/Calendar.cs index ce3d85949f0..ea3c1e08be9 100644 --- a/mcs/class/referencesource/System.Web/UI/WebControls/Calendar.cs +++ b/mcs/class/referencesource/System.Web/UI/WebControls/Calendar.cs @@ -56,7 +56,7 @@ namespace System.Web.UI.WebControls { private ArrayList dateList; private SelectedDatesCollection selectedDates; - private Globalization.Calendar threadCalendar; + private System.Globalization.Calendar threadCalendar; private DateTime minSupportedDate; private DateTime maxSupportedDate; #if DEBUG diff --git a/mcs/class/referencesource/System.Web/UI/WebControls/QueryExtensions.cs b/mcs/class/referencesource/System.Web/UI/WebControls/QueryExtensions.cs index ac1bbae574d..3657d75cca4 100644 --- a/mcs/class/referencesource/System.Web/UI/WebControls/QueryExtensions.cs +++ b/mcs/class/referencesource/System.Web/UI/WebControls/QueryExtensions.cs @@ -32,7 +32,17 @@ namespace System.Web.UI.WebControls { } ParameterExpression parameter = Expression.Parameter(source.ElementType, String.Empty); - MemberExpression property = Expression.Property(parameter, sortExpression); + //VSO bug 173528-- Add support for sorting by nested property names + MemberExpression property = null; + string[] sortExpressionFields = sortExpression.Split('.'); + foreach (string sortExpressionField in sortExpressionFields) { + if (property == null) { + property = Expression.Property(parameter, sortExpressionField); + } + else { + property = Expression.Property(property, sortExpressionField); + } + } LambdaExpression lambda = Expression.Lambda(property, parameter); string methodName = (isDescending) ? "OrderByDescending" : "OrderBy" ; diff --git a/mcs/class/referencesource/System.Web/UI/WebControls/xml.cs b/mcs/class/referencesource/System.Web/UI/WebControls/xml.cs index bb97a7c2823..93ec3e60d03 100644 --- a/mcs/class/referencesource/System.Web/UI/WebControls/xml.cs +++ b/mcs/class/referencesource/System.Web/UI/WebControls/xml.cs @@ -41,6 +41,7 @@ namespace System.Web.UI.WebControls { [SuppressMessage("Microsoft.Security", "MSEC1220:ReviewDtdProcessingAssignment", Justification = "Dtd processing is needed for back-compat, but is being done as safely as possible.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3069:ReviewDtdProcessingAssignment", Justification = "Dtd processing is needed for back-compat, but is being done as safely as possible.")] public override void SetTagInnerText(string text) { if (!Util.IsWhiteSpaceString(text)) { @@ -114,7 +115,9 @@ namespace System.Web.UI.WebControls { #pragma warning restore 0618 [SuppressMessage("Microsoft.Security", "MSEC1201:DoNotUseXslTransform", Justification = "_identityTransform contents are trusted hard-coded string.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3050:DoNotUseXslTransform", Justification = "_identityTransform contents are trusted hard-coded string.")] [SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "_identityTransform contents are trusted hard-coded string.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "_identityTransform contents are trusted hard-coded string.")] [PermissionSet(SecurityAction.Assert, Unrestricted = true)] static Xml() { @@ -332,6 +335,7 @@ namespace System.Web.UI.WebControls { [SuppressMessage("Microsoft.Security", "MSEC1218:ReviewWebControlForSet_DocumentContent", Justification = "Legacy code that trusts our developer input. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3067:ReviewWebControlForSet_DocumentContent", Justification = "Legacy code that trusts our developer input. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] protected override void AddParsedSubObject(object obj) { if (obj is LiteralControl) { // Trim the initial whitespaces since XML is very picky (related to ASURT 58100) diff --git a/mcs/class/referencesource/System.Web/Util/GCUtil.cs b/mcs/class/referencesource/System.Web/Util/GCUtil.cs index 0e48e6d162c..f6c84a21775 100644 --- a/mcs/class/referencesource/System.Web/Util/GCUtil.cs +++ b/mcs/class/referencesource/System.Web/Util/GCUtil.cs @@ -36,4 +36,33 @@ namespace System.Web.Util { } } + + // This wrapper around a managed object is opaque to SizedReference GC handle + // and therefore helps with calculating size of only relevant graph of objects + internal class DisposableGCHandleRef : IDisposable + where T : class, IDisposable { + GCHandle _handle; + [PermissionSet(SecurityAction.Assert, Unrestricted = true)] + public DisposableGCHandleRef(T t) { + Debug.Assert(t != null); + _handle = GCHandle.Alloc(t); + } + + public T Target { + [PermissionSet(SecurityAction.Assert, Unrestricted = true)] + get { + Debug.Assert(_handle.IsAllocated); + return (T)_handle.Target; + } + } + + [PermissionSet(SecurityAction.Assert, Unrestricted = true)] + public void Dispose() { + Target.Dispose(); + Debug.Assert(_handle.IsAllocated); + if (_handle.IsAllocated) { + _handle.Free(); + } + } + } } diff --git a/mcs/class/referencesource/System.Web/Util/StringUtil.cs b/mcs/class/referencesource/System.Web/Util/StringUtil.cs index 545023b7a24..94ef87f0291 100644 --- a/mcs/class/referencesource/System.Web/Util/StringUtil.cs +++ b/mcs/class/referencesource/System.Web/Util/StringUtil.cs @@ -15,6 +15,7 @@ using System.Text; using System.Globalization; using System.Runtime.InteropServices; using System.Web.Hosting; +using System.Diagnostics.CodeAnalysis; /* * Various string handling utilities @@ -294,6 +295,7 @@ internal static class StringUtil { // Instead use the default AppDomain, because it doesn't have string hash randomization enabled. // Marshal the call to reuse the default StringComparer behavior. // PERF isn't optimal, so apply consideration! + [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification = "We carefully control the callers.")] internal static int GetNonRandomizedStringComparerHashCode(string s) { // Preserve the default behavior when string hash randomization is off if (!AppSettings.UseRandomizedStringHashAlgorithm) { diff --git a/mcs/class/referencesource/System.Web/Util/SynchronizationHelper.cs b/mcs/class/referencesource/System.Web/Util/SynchronizationHelper.cs index d442f0cc89c..64a86b68118 100644 --- a/mcs/class/referencesource/System.Web/Util/SynchronizationHelper.cs +++ b/mcs/class/referencesource/System.Web/Util/SynchronizationHelper.cs @@ -105,7 +105,7 @@ namespace System.Web.Util { // This method only schedules work; it doesn't itself do any work. The lock is held for a very // short period of time. lock (_lockObj) { - Task newTask = _lastScheduledTask.ContinueWith(_ => SafeWrapCallback(action)); + Task newTask = _lastScheduledTask.ContinueWith(_ => SafeWrapCallback(action), TaskScheduler.Default); _lastScheduledTask = newTask; // the newly-created task is now the last one } } diff --git a/mcs/class/referencesource/System.Web/Util/XmlUtils.cs b/mcs/class/referencesource/System.Web/Util/XmlUtils.cs index eb237040da0..a07e9df58d2 100644 --- a/mcs/class/referencesource/System.Web/Util/XmlUtils.cs +++ b/mcs/class/referencesource/System.Web/Util/XmlUtils.cs @@ -17,6 +17,7 @@ namespace System.Web.Util { public static readonly long MaxEntityExpansion = 1024 * 1024; [SuppressMessage("Microsoft.Security", "MSEC1208:DoNotUseLoadXml", Justification = "Handles developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3057:DoNotUseLoadXml", Justification = "Handles developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] public static XmlDocument CreateXmlDocumentFromContent(string content) { XmlDocument doc = new XmlDocument(); @@ -35,6 +36,7 @@ namespace System.Web.Util { } [SuppressMessage("Microsoft.Security", "MSEC1210:UseXmlReaderForXPathDocument", Justification = "Handles developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3059:UseXmlReaderForXPathDocument", Justification = "Handles developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] public static XPathDocument CreateXPathDocumentFromContent(string content) { StringReader reader = new StringReader(content); @@ -47,6 +49,7 @@ namespace System.Web.Util { } [SuppressMessage("Microsoft.Security", "MSEC1220:ReviewDtdProcessingAssignment", Justification = "Dtd processing is needed for back-compat, but is being done as safely as possible.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3069:ReviewDtdProcessingAssignment", Justification = "Dtd processing is needed for back-compat, but is being done as safely as possible.")] public static XmlReaderSettings CreateXmlReaderSettings() { XmlReaderSettings settings = new XmlReaderSettings(); @@ -68,7 +71,9 @@ namespace System.Web.Util { // try to guess at how to set matching defaults with XmlReader.Create(). // (E.g. DtdProcessing is Parse by default using XmlTextReader directly. It's Prohibit in default XmlReaderSettings.) [SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] [SuppressMessage("Microsoft.Security", "MSEC1225:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3074:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")] public static XmlReader CreateXmlReader(string filepath) { if (AppSettings.RestrictXmlControls) @@ -84,7 +89,9 @@ namespace System.Web.Util { } [SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] [SuppressMessage("Microsoft.Security", "MSEC1225:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3074:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")] public static XmlReader CreateXmlReader(Stream datastream) { if (AppSettings.RestrictXmlControls) @@ -100,7 +107,9 @@ namespace System.Web.Util { } [SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] [SuppressMessage("Microsoft.Security", "MSEC1225:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3074:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")] public static XmlReader CreateXmlReader(TextReader reader) { if (AppSettings.RestrictXmlControls) @@ -116,7 +125,9 @@ namespace System.Web.Util { } [SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Handles trusted or developer-controlled input xml. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] [SuppressMessage("Microsoft.Security", "MSEC1225:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3074:ReviewClassesDerivedFromXmlTextReader", Justification = "NoEntitiesXmlReader is our internal mechanism for using XmlTextReaders in a reasonably safe manner.")] public static XmlReader CreateXmlReader(Stream contentStream, string baseURI) { if (AppSettings.RestrictXmlControls) @@ -179,6 +190,7 @@ namespace System.Web.Util { #pragma warning disable 0618 // To avoid deprecation warning [SuppressMessage("Microsoft.Security", "MSEC1201:DoNotUseXslTransform", Justification = "Handles developer-controlled input xsl. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3050:DoNotUseXslTransform", Justification = "Handles developer-controlled input xsl. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] public static XslTransform CreateXslTransform(XmlReader reader) { if (!AppSettings.RestrictXmlControls) @@ -191,6 +203,7 @@ namespace System.Web.Util { } [SuppressMessage("Microsoft.Security", "MSEC1201:DoNotUseXslTransform", Justification = "Handles developer-controlled input xsl. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3050:DoNotUseXslTransform", Justification = "Handles developer-controlled input xsl. Optional safer codepath available via appSettings/aspnet:RestrictXmlControls configuration.")] public static XslTransform CreateXslTransform(XmlReader reader, XmlResolver resolver) { if (!AppSettings.RestrictXmlControls) diff --git a/mcs/class/referencesource/System.Web/XmlSiteMapProvider.cs b/mcs/class/referencesource/System.Web/XmlSiteMapProvider.cs index 736c8f48b88..917aeea9154 100644 --- a/mcs/class/referencesource/System.Web/XmlSiteMapProvider.cs +++ b/mcs/class/referencesource/System.Web/XmlSiteMapProvider.cs @@ -232,6 +232,7 @@ namespace System.Web { [SuppressMessage("Microsoft.Security", "MSEC1205:DoNotAllowDtdOnXmlTextReader", Justification = "Legacy code that trusts our developer-controlled input.")] + [SuppressMessage("Microsoft.Security.Xml", "CA3054:DoNotAllowDtdOnXmlTextReader", Justification = "Legacy code that trusts our developer-controlled input.")] public override SiteMapNode BuildSiteMap() { SiteMapNode tempNode = _siteMapNode; diff --git a/mcs/class/referencesource/System.Workflow.ComponentModel/AuthoringOM/Compiler/CompileXomlTask.cs b/mcs/class/referencesource/System.Workflow.ComponentModel/AuthoringOM/Compiler/CompileXomlTask.cs index 5290f57da13..d1a7668ea7a 100644 --- a/mcs/class/referencesource/System.Workflow.ComponentModel/AuthoringOM/Compiler/CompileXomlTask.cs +++ b/mcs/class/referencesource/System.Workflow.ComponentModel/AuthoringOM/Compiler/CompileXomlTask.cs @@ -6,6 +6,7 @@ namespace System.Workflow.ComponentModel.Compiler using System.Diagnostics; using System.Globalization; using System.IO; + using System.Xml; using System.Text; using System.Collections; using System.Collections.Specialized; @@ -1142,7 +1143,7 @@ namespace System.Workflow.ComponentModel.Compiler string name = null; try { - Xml.XmlTextReader reader = new Xml.XmlTextReader(binaryStream); + Xml.XmlTextReader reader = new Xml.XmlTextReader(binaryStream) { DtdProcessing = DtdProcessing.Prohibit }; if (reader.MoveToContent() == System.Xml.XmlNodeType.Element) { if (reader.MoveToAttribute("Class", StandardXomlKeys.Definitions_XmlNs)) diff --git a/mcs/class/referencesource/System.Workflow.ComponentModel/AuthoringOM/Design/ComponentSerializationService.cs b/mcs/class/referencesource/System.Workflow.ComponentModel/AuthoringOM/Design/ComponentSerializationService.cs index 1e658c689b2..5488a93ae69 100644 --- a/mcs/class/referencesource/System.Workflow.ComponentModel/AuthoringOM/Design/ComponentSerializationService.cs +++ b/mcs/class/referencesource/System.Workflow.ComponentModel/AuthoringOM/Design/ComponentSerializationService.cs @@ -193,7 +193,7 @@ namespace System.Workflow.ComponentModel.Design { ArrayList objects = new ArrayList(); WorkflowMarkupSerializationManager xomlSerializationManager = new WorkflowMarkupSerializationManager(serializationManager); - XmlTextReader reader = new XmlTextReader(this.serializedXmlString, XmlNodeType.Element, null); + XmlTextReader reader = new XmlTextReader(this.serializedXmlString, XmlNodeType.Element, null) { DtdProcessing = DtdProcessing.Prohibit }; reader.MoveToElement(); do { @@ -235,7 +235,7 @@ namespace System.Workflow.ComponentModel.Design xomlSerializationManager.AddSerializationProvider(propertySegmentSerializationProvider); StringReader stringReader = new StringReader(this.serializedXmlString); - using (XmlTextReader reader = new XmlTextReader(stringReader)) + using (XmlTextReader reader = new XmlTextReader(stringReader) { DtdProcessing = DtdProcessing.Prohibit }) { while (reader.NodeType != XmlNodeType.Element && reader.NodeType != XmlNodeType.ProcessingInstruction && reader.Read()); diff --git a/mcs/class/referencesource/System.Workflow.Runtime/Tracking.cs b/mcs/class/referencesource/System.Workflow.Runtime/Tracking.cs index 55ef70d7197..df277deaef3 100644 --- a/mcs/class/referencesource/System.Workflow.Runtime/Tracking.cs +++ b/mcs/class/referencesource/System.Workflow.Runtime/Tracking.cs @@ -1837,18 +1837,25 @@ namespace System.Workflow.Runtime return HashServiceType(serviceType.AssemblyQualifiedName); } - [SuppressMessage("Microsoft.Cryptographic.Standard", "CA5350:MD5CannotBeUsed", + [SuppressMessage("Microsoft.Cryptographic.Standard", "CA5350:MD5CannotBeUsed", Justification = "Design has been approved. We are not using MD5 for any security or cryptography purposes but rather as a hash.")] internal static Guid HashServiceType(String serviceFullTypeName) { - MD5 md5 = new MD5CryptoServiceProvider(); byte[] data; byte[] result; UnicodeEncoding ue = new UnicodeEncoding(); data = ue.GetBytes(serviceFullTypeName); - result = md5.ComputeHash(data); + if (AppSettings.FIPSRequired) + { + result = MD5PInvokeHelper.CalculateHash(data); + } + else + { + MD5 md5 = new MD5CryptoServiceProvider(); + result = md5.ComputeHash(data); + } return new Guid(result); } diff --git a/mcs/class/referencesource/System.Workflow.Runtime/Tracking/TrackingProfileSerializer.cs b/mcs/class/referencesource/System.Workflow.Runtime/Tracking/TrackingProfileSerializer.cs index 79d95e3450b..7c6905f92bb 100644 --- a/mcs/class/referencesource/System.Workflow.Runtime/Tracking/TrackingProfileSerializer.cs +++ b/mcs/class/referencesource/System.Workflow.Runtime/Tracking/TrackingProfileSerializer.cs @@ -28,7 +28,8 @@ namespace System.Workflow.Runtime.Tracking { public TrackingProfileSerializer() { - _schema = XmlSchema.Read(new StringReader(_xsd), null); + StringReader reader = new StringReader(_xsd); + _schema = XmlSchema.Read(new XmlTextReader(reader) { DtdProcessing = DtdProcessing.Prohibit }, null); _schema.Namespaces.Add("", _ns); } diff --git a/mcs/class/referencesource/System.Workflow.Runtime/WorkflowRuntime.cs b/mcs/class/referencesource/System.Workflow.Runtime/WorkflowRuntime.cs index 718b7556e48..1697c085654 100644 --- a/mcs/class/referencesource/System.Workflow.Runtime/WorkflowRuntime.cs +++ b/mcs/class/referencesource/System.Workflow.Runtime/WorkflowRuntime.cs @@ -129,6 +129,17 @@ namespace System.Workflow.Runtime // listen to activity definition resolve events Activity.ActivityResolve += OnActivityDefinitionResolve; Activity.WorkflowChangeActionsResolve += OnWorkflowChangeActionsResolve; + + try + { + using (TelemetryEventSource eventSource = new TelemetryEventSource()) + { + eventSource.V1Runtime(); + } + } + catch + { + } } public WorkflowRuntime() diff --git a/mcs/class/referencesource/System.Xml/InternalApis/Clr/inc/AppContextDefaultValues.cs b/mcs/class/referencesource/System.Xml/InternalApis/Clr/inc/AppContextDefaultValues.cs index 8a130a0f342..9224bf8b8fb 100644 --- a/mcs/class/referencesource/System.Xml/InternalApis/Clr/inc/AppContextDefaultValues.cs +++ b/mcs/class/referencesource/System.Xml/InternalApis/Clr/inc/AppContextDefaultValues.cs @@ -3,6 +3,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== + +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + using System; using System.Collections.Generic; @@ -167,3 +176,5 @@ namespace System static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version); } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/System.Xml/InternalApis/Clr/inc/LocalAppContext.cs b/mcs/class/referencesource/System.Xml/InternalApis/Clr/inc/LocalAppContext.cs index f05b599ed3d..33662b54280 100644 --- a/mcs/class/referencesource/System.Xml/InternalApis/Clr/inc/LocalAppContext.cs +++ b/mcs/class/referencesource/System.Xml/InternalApis/Clr/inc/LocalAppContext.cs @@ -4,6 +4,14 @@ // // ==--== +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + // NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches using System; using System.Collections.Generic; @@ -126,3 +134,5 @@ namespace System } } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Core/AppContextDefaultValues.Defaults.cs b/mcs/class/referencesource/System.Xml/System/Xml/Core/AppContextDefaultValues.Defaults.cs index 01ac463e479..ac29b893843 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Core/AppContextDefaultValues.Defaults.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Core/AppContextDefaultValues.Defaults.cs @@ -28,6 +28,10 @@ namespace System LocalAppContext.DefineSwitchDefault("Switch.System.Xml.DontThrowOnInvalidSurrogatePairs", true); LocalAppContext.DefineSwitchDefault("Switch.System.Xml.IgnoreEmptyKeySequences", true); } + if (version <= 40601) + { + LocalAppContext.DefineSwitchDefault("Switch.System.Xml.IgnoreKindInUtcTimeSerialization", true); + } break; } case "WindowsPhone": @@ -37,6 +41,7 @@ namespace System { LocalAppContext.DefineSwitchDefault("Switch.System.Xml.DontThrowOnInvalidSurrogatePairs", true); LocalAppContext.DefineSwitchDefault("Switch.System.Xml.IgnoreEmptyKeySequences", true); + LocalAppContext.DefineSwitchDefault("Switch.System.Xml.IgnoreKindInUtcTimeSerialization", true); } break; } diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Core/LocalAppContextSwitches.cs b/mcs/class/referencesource/System.Xml/System/Xml/Core/LocalAppContextSwitches.cs index c744ba1c0dc..ddc33234132 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Core/LocalAppContextSwitches.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Core/LocalAppContextSwitches.cs @@ -29,5 +29,15 @@ namespace System return LocalAppContext.GetCachedSwitchValue(@"Switch.System.Xml.IgnoreEmptyKeySequences", ref _ignoreEmptyKeySequences); } } + + private static int _ignoreKindInUtcTimeSerialization; + public static bool IgnoreKindInUtcTimeSerialization + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(@"Switch.System.Xml.IgnoreKindInUtcTimeSerialization", ref _ignoreKindInUtcTimeSerialization); + } + } } } diff --git a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/Xmlcustomformatter.cs b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/Xmlcustomformatter.cs index d186daa2aa5..98038155948 100644 --- a/mcs/class/referencesource/System.Xml/System/Xml/Serialization/Xmlcustomformatter.cs +++ b/mcs/class/referencesource/System.Xml/System/Xml/Serialization/Xmlcustomformatter.cs @@ -77,7 +77,14 @@ namespace System.Xml.Serialization { } internal static string FromTime(DateTime value) { - return XmlConvert.ToString(DateTime.MinValue + value.TimeOfDay, "HH:mm:ss.fffffffzzzzzz"); + if (!LocalAppContextSwitches.IgnoreKindInUtcTimeSerialization && value.Kind == DateTimeKind.Utc) + { + return XmlConvert.ToString(DateTime.MinValue + value.TimeOfDay, "HH:mm:ss.fffffffZ"); + } + else + { + return XmlConvert.ToString(DateTime.MinValue + value.TimeOfDay, "HH:mm:ss.fffffffzzzzzz"); + } } internal static string FromDateTime(DateTime value) { @@ -337,7 +344,14 @@ namespace System.Xml.Serialization { } internal static DateTime ToTime(string value) { - return DateTime.ParseExact(value, allTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite|DateTimeStyles.AllowTrailingWhite|DateTimeStyles.NoCurrentDateDefault); + if (!LocalAppContextSwitches.IgnoreKindInUtcTimeSerialization) + { + return DateTime.ParseExact(value, allTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.NoCurrentDateDefault | DateTimeStyles.RoundtripKind); + } + else + { + return DateTime.ParseExact(value, allTimeFormats, DateTimeFormatInfo.InvariantInfo, DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite | DateTimeStyles.NoCurrentDateDefault); + } } internal static char ToChar(string value) { diff --git a/mcs/class/referencesource/System/InternalApis/Clr/inc/AppContextDefaultValues.cs b/mcs/class/referencesource/System/InternalApis/Clr/inc/AppContextDefaultValues.cs index 8a130a0f342..9224bf8b8fb 100644 --- a/mcs/class/referencesource/System/InternalApis/Clr/inc/AppContextDefaultValues.cs +++ b/mcs/class/referencesource/System/InternalApis/Clr/inc/AppContextDefaultValues.cs @@ -3,6 +3,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== + +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + using System; using System.Collections.Generic; @@ -167,3 +176,5 @@ namespace System static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version); } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/System/InternalApis/Clr/inc/LocalAppContext.cs b/mcs/class/referencesource/System/InternalApis/Clr/inc/LocalAppContext.cs index f05b599ed3d..33662b54280 100644 --- a/mcs/class/referencesource/System/InternalApis/Clr/inc/LocalAppContext.cs +++ b/mcs/class/referencesource/System/InternalApis/Clr/inc/LocalAppContext.cs @@ -4,6 +4,14 @@ // // ==--== +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + // NOTE: This file should not be included in mscorlib. This should only be included in FX libraries that need to provide switches using System; using System.Collections.Generic; @@ -126,3 +134,5 @@ namespace System } } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/System/InternalApis/NDP_Common/inc/PinnableBufferCache.cs b/mcs/class/referencesource/System/InternalApis/NDP_Common/inc/PinnableBufferCache.cs index 872cfa80dd5..19ec1053a3a 100644 --- a/mcs/class/referencesource/System/InternalApis/NDP_Common/inc/PinnableBufferCache.cs +++ b/mcs/class/referencesource/System/InternalApis/NDP_Common/inc/PinnableBufferCache.cs @@ -155,7 +155,14 @@ namespace System if (PinnableBufferCacheEventSource.Log.IsEnabled()) PinnableBufferCacheEventSource.Log.FreeBuffer(m_CacheName, PinnableBufferCacheEventSource.AddressOf(buffer), buffer.GetHashCode(), m_FreeList.Count); - + if(buffer == null) + { + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + PinnableBufferCacheEventSource.Log.FreeBufferNull(m_CacheName, m_FreeList.Count); + + return; + } + // After we've done 3 gen1 GCs, assume that all buffers have aged into gen2 on the free path. if ((m_gen1CountAtLastRestock + 3) > GC.CollectionCount(GC.MaxGeneration - 1)) { @@ -567,6 +574,7 @@ namespace System public void AllocateBufferAged(string cacheName, int agedCount) {} public void AllocateBufferFreeListEmpty(string cacheName, int notGen2CountBefore) {} public void FreeBuffer(string cacheName, ulong objectId, int objectHash, int freeCountBefore) {} + public void FreeBufferNull(string cacheName, int freeCountBefore) { } public void FreeBufferStillTooYoung(string cacheName, int notGen2CountBefore) {} public void TrimCheck(string cacheName, int totalBuffs, bool neededMoreThanFreeList, int deltaMSec) {} public void TrimFree(string cacheName, int totalBuffs, int freeListCount, int toBeFreed) {} @@ -643,6 +651,8 @@ namespace System public void AgePendingBuffersResults(string cacheName, int promotedToFreeListCount, int heldBackCount) { if (IsEnabled()) WriteEvent(20, cacheName, promotedToFreeListCount, heldBackCount); } [Event(21)] public void WalkFreeListResult(string cacheName, int freeListCount, int gen0BuffersInFreeList) { if (IsEnabled()) WriteEvent(21, cacheName, freeListCount, gen0BuffersInFreeList); } + [Event(22)] + public void FreeBufferNull(string cacheName, int freeCountBefore) { if(IsEnabled()) WriteEvent(22, cacheName, freeCountBefore); } static internal ulong AddressOf(object obj) diff --git a/mcs/class/referencesource/System/compmod/microsoft/win32/UnsafeNativeMethods.cs b/mcs/class/referencesource/System/compmod/microsoft/win32/UnsafeNativeMethods.cs index a1911293b0d..95874022970 100644 --- a/mcs/class/referencesource/System/compmod/microsoft/win32/UnsafeNativeMethods.cs +++ b/mcs/class/referencesource/System/compmod/microsoft/win32/UnsafeNativeMethods.cs @@ -169,6 +169,23 @@ namespace Microsoft.Win32 { [ResourceExposure(ResourceScope.None)] public static extern bool WTSUnRegisterSessionNotification(HandleRef hWnd); + private static IntPtr GetCurrentProcessToken() { return new IntPtr(-4); } + + private const int ERROR_SUCCESS = 0; + + enum AppPolicyClrCompat + { + AppPolicyClrCompat_Others = 0, + AppPolicyClrCompat_ClassicDesktop = 1, + AppPolicyClrCompat_Universal = 2, + AppPolicyClrCompat_PackagedDesktop = 3 + }; + + [DllImport(ExternDll.Kernel32, CharSet = CharSet.None, EntryPoint = "AppPolicyGetClrCompat")] + [System.Security.SecuritySafeCritical] + [return: MarshalAs(UnmanagedType.I4)] + private static extern Int32 _AppPolicyGetClrCompat(IntPtr processToken, out AppPolicyClrCompat appPolicyClrCompat); + private const int ERROR_INSUFFICIENT_BUFFER = 0x007A; private const int ERROR_NO_PACKAGE_IDENTITY = 0x3d54; @@ -204,8 +221,20 @@ namespace Microsoft.Win32 { [System.Security.SecuritySafeCritical] private static bool _IsPackagedProcess() { + Version windows8Version = new Version(6, 2, 0, 0); OperatingSystem os = Environment.OSVersion; - if(os.Platform == PlatformID.Win32NT && os.Version >= new Version(6,2,0,0) && DoesWin32MethodExist(ExternDll.Kernel32, "GetCurrentPackageId")) + bool osSupportsPackagedProcesses = os.Platform == PlatformID.Win32NT && os.Version >= windows8Version; + + if (osSupportsPackagedProcesses && DoesWin32MethodExist(ExternDll.Kernel32, "AppPolicyGetClrCompat")) + { + // Use AppPolicyGetClrCompat if it is available. Return true if and only if this is a UWA which means if + // this is packaged desktop app this method will return false. This may cause some confusion however + // this is necessary to make the behavior of packaged desktop apps identical to desktop apps. + AppPolicyClrCompat appPolicyClrCompat; + return _AppPolicyGetClrCompat(GetCurrentProcessToken(), out appPolicyClrCompat) == ERROR_SUCCESS && + appPolicyClrCompat == AppPolicyClrCompat.AppPolicyClrCompat_Universal; + } + else if(osSupportsPackagedProcesses && DoesWin32MethodExist(ExternDll.Kernel32, "GetCurrentPackageId")) { Int32 bufLen = 0; // Will return ERROR_INSUFFICIENT_BUFFER when running within a packaged application, diff --git a/mcs/class/referencesource/System/compmod/system/componentmodel/MemberDescriptor.cs b/mcs/class/referencesource/System/compmod/system/componentmodel/MemberDescriptor.cs index c16486800a9..ebc36a83d4d 100644 --- a/mcs/class/referencesource/System/compmod/system/componentmodel/MemberDescriptor.cs +++ b/mcs/class/referencesource/System/compmod/system/componentmodel/MemberDescriptor.cs @@ -326,9 +326,19 @@ namespace System.ComponentModel { return false; } - if ((mdObj.description == null) != (description == null) || - (description != null && !mdObj.category.Equals(description))) { - return false; + // VSO 149471 - Technically fixing this could cause a behavior change, so we are + // adding a quirk in case anyone is bit by this and needs the old, buggy behavior. + if (!LocalAppContextSwitches.MemberDescriptorEqualsReturnsFalseIfEquivalent) { + if ((mdObj.description == null) != (description == null) || + (description != null && !mdObj.description.Equals(description))) { + return false; + } + } + else { + if ((mdObj.description == null) != (description == null) || + (description != null && !mdObj.category.Equals(description))) { + return false; + } } if ((mdObj.attributes == null) != (attributes == null)) { diff --git a/mcs/class/referencesource/System/net/System/Net/HttpListenerRequest.cs b/mcs/class/referencesource/System/net/System/Net/HttpListenerRequest.cs index 320e1d69ff4..a789a6ea2be 100644 --- a/mcs/class/referencesource/System/net/System/Net/HttpListenerRequest.cs +++ b/mcs/class/referencesource/System/net/System/Net/HttpListenerRequest.cs @@ -300,6 +300,9 @@ namespace System.Net { } } + // Note: RequestBuffer may get moved in memory. If you dereference a pointer from inside the RequestBuffer, + // you must use 'OriginalBlobAddress' below to adjust the location of the pointer to match the location of + // RequestBuffer. internal byte[] RequestBuffer { get @@ -1061,7 +1064,7 @@ namespace System.Net { m_TokenBindings = new List(); - UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO* pTokenBindingInfo = GetTlsTokenBindingRequestInfo(); + UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO* pTokenBindingInfo = UnsafeNclNativeMethods.HttpApi.GetTlsTokenBindingRequestInfo(RequestBuffer, OriginalBlobAddress); if (pTokenBindingInfo == null) { @@ -1116,23 +1119,6 @@ namespace System.Net { } } - private UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO* GetTlsTokenBindingRequestInfo() { - fixed (byte* pMemoryBlob = RequestBuffer) - { - UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2* request = (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_V2*)pMemoryBlob; - - for (int i = 0; i < request->RequestInfoCount; i++) - { - UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO* pThisInfo = &request->pRequestInfo[i]; - if (pThisInfo != null && pThisInfo->InfoType == UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeSslTokenBinding) - { - return (UnsafeNclNativeMethods.HttpApi.HTTP_REQUEST_TOKEN_BINDING_INFO*)pThisInfo->pInfo; - } - } - } - return null; - } - internal void CheckDisposed() { if (m_IsDisposed) { throw new ObjectDisposedException(this.GetType().FullName); diff --git a/mcs/class/referencesource/System/net/System/Net/Internal.cs b/mcs/class/referencesource/System/net/System/Net/Internal.cs index d04932e503f..05732c28d36 100644 --- a/mcs/class/referencesource/System/net/System/Net/Internal.cs +++ b/mcs/class/referencesource/System/net/System/Net/Internal.cs @@ -1406,6 +1406,7 @@ typedef struct _SCHANNEL_CRED ValidateManual = 0x08, NoDefaultCred = 0x10, ValidateAuto = 0x20, + SendAuxRecord = 0x00200000, UseStrongCrypto = 0x00400000, } diff --git a/mcs/class/referencesource/System/net/System/Net/SecureProtocols/_SslState.cs b/mcs/class/referencesource/System/net/System/Net/SecureProtocols/_SslState.cs index 01776e420de..b5488d4a299 100644 --- a/mcs/class/referencesource/System/net/System/Net/SecureProtocols/_SslState.cs +++ b/mcs/class/referencesource/System/net/System/Net/SecureProtocols/_SslState.cs @@ -592,9 +592,17 @@ namespace System.Net.Security { KeyExchangeStrength)); } } + catch (Exception) + { + // If an exception emerges synchronously, the asynchronous operation was not + // initiated, so no operation is in progress. + _NestedAuth = 0; + + throw; + } finally { - if (lazyResult == null || _Exception != null) + if (lazyResult == null) { _NestedAuth = 0; } diff --git a/mcs/class/referencesource/System/net/System/Net/ServicePointManager.cs b/mcs/class/referencesource/System/net/System/Net/ServicePointManager.cs index 48bb45802f0..3de63c914d6 100644 --- a/mcs/class/referencesource/System/net/System/Net/ServicePointManager.cs +++ b/mcs/class/referencesource/System/net/System/Net/ServicePointManager.cs @@ -247,12 +247,15 @@ namespace System.Net { private static volatile CertPolicyValidationCallback s_CertPolicyValidationCallback = new CertPolicyValidationCallback(); private static volatile ServerCertValidationCallback s_ServerCertValidationCallback = null; + private const string sendAuxRecordValueName = "SchSendAuxRecord"; + private const string sendAuxRecordAppSetting = "System.Net.ServicePointManager.SchSendAuxRecord"; private const string strongCryptoValueName = "SchUseStrongCrypto"; private const string secureProtocolAppSetting = "System.Net.ServicePointManager.SecurityProtocol"; - private static object disableStrongCryptoLock = new object(); - private static volatile bool disableStrongCryptoInitialized = false; + private static object configurationLoadedLock = new object(); + private static volatile bool configurationLoaded = false; private static bool disableStrongCrypto = false; + private static bool disableSendAuxRecord = false; private static SecurityProtocolType s_SecurityProtocolType = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3; @@ -427,11 +430,11 @@ namespace System.Net { [SuppressMessage("Microsoft.Concurrency", "CA8001", Justification = "Reviewed for thread-safety")] public static SecurityProtocolType SecurityProtocol { get { - EnsureStrongCryptoSettingsInitialized(); + EnsureConfigurationLoaded(); return s_SecurityProtocolType; } set { - EnsureStrongCryptoSettingsInitialized(); + EnsureConfigurationLoaded(); ValidateSecurityProtocol(value); s_SecurityProtocolType = value; } @@ -640,77 +643,118 @@ namespace System.Net { internal static bool DisableStrongCrypto { get { - EnsureStrongCryptoSettingsInitialized(); - return (bool)disableStrongCrypto; + EnsureConfigurationLoaded(); + return disableStrongCrypto; } } - private static void EnsureStrongCryptoSettingsInitialized() { - - if (disableStrongCryptoInitialized) { + internal static bool DisableSendAuxRecord { + get { + EnsureConfigurationLoaded(); + return disableSendAuxRecord; + } + } + + private static void EnsureConfigurationLoaded() { + if (configurationLoaded) { return; } - lock (disableStrongCryptoLock) { - if (disableStrongCryptoInitialized) { + lock (configurationLoadedLock) { + if (configurationLoaded) { return; } - try { - bool disableStrongCryptoInternal = false; - int schUseStrongCryptoKeyValue = 0; + LoadDisableStrongCryptoConfiguration(); + LoadDisableSendAuxRecordConfiguration(); - if (LocalAppContextSwitches.DontEnableSchUseStrongCrypto) - { - //.Net 4.5.2 and below will default to false unless the registry key is specifically set to 1. - schUseStrongCryptoKeyValue = - RegistryConfiguration.GlobalConfigReadInt(strongCryptoValueName, 0); + configurationLoaded = true; + } + } - disableStrongCryptoInternal = schUseStrongCryptoKeyValue != 1; - } - else - { - // .Net 4.6 and above will default to true unless the registry key is specifically set to 0. - schUseStrongCryptoKeyValue = - RegistryConfiguration.GlobalConfigReadInt(strongCryptoValueName, 1); + private static void LoadDisableStrongCryptoConfiguration() { + try { + bool disableStrongCryptoInternal = false; + int schUseStrongCryptoKeyValue = 0; - disableStrongCryptoInternal = schUseStrongCryptoKeyValue == 0; - } - - if (disableStrongCryptoInternal) { - // Revert the SecurityProtocol selection to the legacy combination. - s_SecurityProtocolType = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3; - } - else { - s_SecurityProtocolType = - SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; + if (LocalAppContextSwitches.DontEnableSchUseStrongCrypto) { + //.Net 4.5.2 and below will default to false unless the registry key is specifically set to 1. + schUseStrongCryptoKeyValue = + RegistryConfiguration.GlobalConfigReadInt(strongCryptoValueName, 0); - string appSetting = RegistryConfiguration.AppConfigReadString(secureProtocolAppSetting, null); + disableStrongCryptoInternal = schUseStrongCryptoKeyValue != 1; + } + else { + // .Net 4.6 and above will default to true unless the registry key is specifically set to 0. + schUseStrongCryptoKeyValue = + RegistryConfiguration.GlobalConfigReadInt(strongCryptoValueName, 1); - SecurityProtocolType value; - try { - value = (SecurityProtocolType)Enum.Parse(typeof(SecurityProtocolType), appSetting); - ValidateSecurityProtocol(value); - s_SecurityProtocolType = value; - } - // Ignore all potential exceptions caused by Enum.Parse. - catch (ArgumentNullException) { } - catch (ArgumentException) { } - catch (NotSupportedException) { } - catch (OverflowException) { } - } + disableStrongCryptoInternal = schUseStrongCryptoKeyValue == 0; + } - disableStrongCrypto = disableStrongCryptoInternal; - disableStrongCryptoInitialized = true; + if (disableStrongCryptoInternal) { + // Revert the SecurityProtocol selection to the legacy combination. + s_SecurityProtocolType = SecurityProtocolType.Tls | SecurityProtocolType.Ssl3; } - catch (Exception e) { - if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) { - throw; + else { + s_SecurityProtocolType = + SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls; + + string appSetting = RegistryConfiguration.AppConfigReadString(secureProtocolAppSetting, null); + + SecurityProtocolType value; + try { + value = (SecurityProtocolType)Enum.Parse(typeof(SecurityProtocolType), appSetting); + ValidateSecurityProtocol(value); + s_SecurityProtocolType = value; } + // Ignore all potential exceptions caused by Enum.Parse. + catch (ArgumentNullException) { } + catch (ArgumentException) { } + catch (NotSupportedException) { } + catch (OverflowException) { } + } + + disableStrongCrypto = disableStrongCryptoInternal; + } + catch (Exception e) + { + if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) + { + throw; } } } - + + private static void LoadDisableSendAuxRecordConfiguration() { + try { + if (LocalAppContextSwitches.DontEnableSchSendAuxRecord) { + disableSendAuxRecord = true; + return; + } + + int schSendAuxRecordKeyValue = 1; + schSendAuxRecordKeyValue = RegistryConfiguration.AppConfigReadInt(sendAuxRecordAppSetting, 1); + if (schSendAuxRecordKeyValue == 0) { + disableSendAuxRecord = true; + return; + } + + schSendAuxRecordKeyValue = RegistryConfiguration.GlobalConfigReadInt(sendAuxRecordValueName, 1); + if (schSendAuxRecordKeyValue == 0) { + disableSendAuxRecord = true; + return; + } + } + catch (Exception e) + { + if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) + { + throw; + } + } + } + public static bool ReusePort { get { EnsureReusePortSettingsInitialized(); diff --git a/mcs/class/referencesource/System/net/System/Net/UnsafeNativeMethods.cs b/mcs/class/referencesource/System/net/System/Net/UnsafeNativeMethods.cs index 7cf970ed013..680ea981396 100644 --- a/mcs/class/referencesource/System/net/System/Net/UnsafeNativeMethods.cs +++ b/mcs/class/referencesource/System/net/System/Net/UnsafeNativeMethods.cs @@ -1482,7 +1482,7 @@ namespace System.Net { [Out] out int bytesTransferred, [In] SafeHandle overlapped, [In] IntPtr completionRoutine - ); + ); [DllImport(WS2_32,SetLastError=true)] internal static extern SocketError WSAEnumNetworkEvents( @@ -3147,6 +3147,25 @@ namespace System.Net { GlobalLog.Leave("HttpApi::GetLocalEndPoint()"); return endpoint; } + + internal static HTTP_REQUEST_TOKEN_BINDING_INFO* GetTlsTokenBindingRequestInfo(byte[] memoryBlob, IntPtr originalAddress){ + + fixed (byte* pMemoryBlob = memoryBlob) + { + HTTP_REQUEST_V2* request = (HTTP_REQUEST_V2*)pMemoryBlob; + long fixup = pMemoryBlob - (byte*) originalAddress; + + for (int i = 0; i < request->RequestInfoCount; i++) + { + HTTP_REQUEST_INFO* pThisInfo = (HTTP_REQUEST_INFO*)(fixup + (byte*)&request->pRequestInfo[i]); + if (pThisInfo != null && pThisInfo->InfoType == HTTP_REQUEST_INFO_TYPE.HttpRequestInfoTypeSslTokenBinding) + { + return (HTTP_REQUEST_TOKEN_BINDING_INFO*)pThisInfo->pInfo; + } + } + } + return null; + } [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] private static void CopyOutAddress(IntPtr address, ref SocketAddress v4address, ref SocketAddress v6address) diff --git a/mcs/class/referencesource/System/net/System/Net/_SecureChannel.cs b/mcs/class/referencesource/System/net/System/Net/_SecureChannel.cs index 9f04a33e0b7..58400b2b26f 100644 --- a/mcs/class/referencesource/System/net/System/Net/_SecureChannel.cs +++ b/mcs/class/referencesource/System/net/System/Net/_SecureChannel.cs @@ -393,7 +393,7 @@ namespace System.Net.Security { if (store != null) { collectionEx = store.Certificates.Find(X509FindType.FindByThumbprint, certHash, false); - if (collectionEx.Count > 0 && collectionEx[0].PrivateKey != null) + if (collectionEx.Count > 0 && collectionEx[0].HasPrivateKey) { if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_found_cert_in_store, (m_ServerMode ? "LocalMachine" : "CurrentUser"))); return collectionEx[0]; @@ -404,7 +404,7 @@ namespace System.Net.Security { if (store != null) { collectionEx = store.Certificates.Find(X509FindType.FindByThumbprint, certHash, false); - if (collectionEx.Count > 0 && collectionEx[0].PrivateKey != null) + if (collectionEx.Count > 0 && collectionEx[0].HasPrivateKey) { if (Logging.On) Logging.PrintInfo(Logging.Web, this, SR.GetString(SR.net_log_found_cert_in_store, (m_ServerMode ? "CurrentUser" : "LocalMachine"))); return collectionEx[0]; @@ -791,6 +791,12 @@ namespace System.Net.Security { else { SecureCredential.Flags flags = SecureCredential.Flags.ValidateManual | SecureCredential.Flags.NoDefaultCred; + + if (!ServicePointManager.DisableSendAuxRecord) + { + flags |= SecureCredential.Flags.SendAuxRecord; + } + if (!ServicePointManager.DisableStrongCrypto && ((m_ProtocolFlags & (SchProtocols.Tls10 | SchProtocols.Tls11 | SchProtocols.Tls12)) != 0) && (m_EncryptionPolicy != EncryptionPolicy.AllowNoEncryption) && (m_EncryptionPolicy != EncryptionPolicy.NoEncryption)) @@ -876,7 +882,14 @@ namespace System.Net.Security { } else { - SecureCredential secureCredential = new SecureCredential(SecureCredential.CurrentVersion, selectedCert, SecureCredential.Flags.Zero, m_ProtocolFlags, m_EncryptionPolicy); + SecureCredential.Flags flags = SecureCredential.Flags.Zero; + + if (!ServicePointManager.DisableSendAuxRecord) + { + flags |= SecureCredential.Flags.SendAuxRecord; + } + + SecureCredential secureCredential = new SecureCredential(SecureCredential.CurrentVersion, selectedCert, flags, m_ProtocolFlags, m_EncryptionPolicy); m_CredentialsHandle = AcquireCredentialsHandle(CredentialUse.Inbound, ref secureCredential); thumbPrint = guessedThumbPrint; m_ServerCertificate = localCertificate; diff --git a/mcs/class/referencesource/System/services/io/system/io/FileSystemWatcher.cs b/mcs/class/referencesource/System/services/io/system/io/FileSystemWatcher.cs index ed0965d382f..500280aed33 100644 --- a/mcs/class/referencesource/System/services/io/system/io/FileSystemWatcher.cs +++ b/mcs/class/referencesource/System/services/io/system/io/FileSystemWatcher.cs @@ -586,9 +586,6 @@ namespace System.IO { } else { if (oldName != null) { - Debug.Assert(false, "FileSystemWatcher: FILE_ACTION_RENAMED_OLD_NAME with no" + - "new name! [" + oldName + "]"); - NotifyRenameEventArgs(WatcherChangeTypes.Renamed, null, oldName); oldName = null; } diff --git a/mcs/class/referencesource/System/sys/AppContextDefaultValues.Defaults.cs b/mcs/class/referencesource/System/sys/AppContextDefaultValues.Defaults.cs index a084bb5dc8e..da13e193026 100644 --- a/mcs/class/referencesource/System/sys/AppContextDefaultValues.Defaults.cs +++ b/mcs/class/referencesource/System/sys/AppContextDefaultValues.Defaults.cs @@ -27,6 +27,11 @@ namespace System { LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.DontEnableSchUseStrongCryptoName, true); } + + if (version <= 40601) + { + LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.MemberDescriptorEqualsReturnsFalseIfEquivalentName, true); + } break; } case "WindowsPhone": @@ -34,7 +39,7 @@ namespace System { if (version <= 80100) { - LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.DontEnableSchUseStrongCryptoName, true); + LocalAppContext.DefineSwitchDefault(LocalAppContextSwitches.DontEnableSchUseStrongCryptoName, true); } break; } diff --git a/mcs/class/referencesource/System/sys/LocalAppContextSwitches.cs b/mcs/class/referencesource/System/sys/LocalAppContextSwitches.cs index 50f2bac56df..0d28af1593f 100644 --- a/mcs/class/referencesource/System/sys/LocalAppContextSwitches.cs +++ b/mcs/class/referencesource/System/sys/LocalAppContextSwitches.cs @@ -11,7 +11,21 @@ namespace System internal static class LocalAppContextSwitches { -#region System.Net quirks + #region System quirks + private static int _memberDescriptorEqualsReturnsFalseIfEquivalent; + internal const string MemberDescriptorEqualsReturnsFalseIfEquivalentName = @"Switch.System.MemberDescriptorEqualsReturnsFalseIfEquivalent"; + + public static bool MemberDescriptorEqualsReturnsFalseIfEquivalent + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(MemberDescriptorEqualsReturnsFalseIfEquivalentName, ref _memberDescriptorEqualsReturnsFalseIfEquivalent); + } + } + #endregion + + #region System.Net quirks private static int _dontEnableSchUseStrongCrypto; internal const string DontEnableSchUseStrongCryptoName = @"Switch.System.Net.DontEnableSchUseStrongCrypto"; @@ -23,9 +37,7 @@ namespace System return LocalAppContext.GetCachedSwitchValue(DontEnableSchUseStrongCryptoName, ref _dontEnableSchUseStrongCrypto); } } -#endregion -#region System.Net.WebSockets.HttpListenerAsyncEventArgs private static int _allocateOverlappedOnDemand; internal const string AllocateOverlappedOnDemandName = @"Switch.System.Net.WebSockets.HttpListenerAsyncEventArgs.AllocateOverlappedOnDemand"; @@ -37,7 +49,18 @@ namespace System return LocalAppContext.GetCachedSwitchValue(AllocateOverlappedOnDemandName, ref _allocateOverlappedOnDemand); } } -#endregion + private static int _dontEnableSchSendAuxRecord; + internal const string DontEnableSchSendAuxRecordName = @"Switch.System.Net.DontEnableSchSendAuxRecord"; + + public static bool DontEnableSchSendAuxRecord + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return LocalAppContext.GetCachedSwitchValue(DontEnableSchSendAuxRecordName, ref _dontEnableSchSendAuxRecord); + } + } + #endregion } } diff --git a/mcs/class/referencesource/XamlBuildTask/Microsoft/Build/Tasks/Xaml/PartialClassGenerationTask.cs b/mcs/class/referencesource/XamlBuildTask/Microsoft/Build/Tasks/Xaml/PartialClassGenerationTask.cs index 30a681e707b..fb57cc3cbaa 100644 --- a/mcs/class/referencesource/XamlBuildTask/Microsoft/Build/Tasks/Xaml/PartialClassGenerationTask.cs +++ b/mcs/class/referencesource/XamlBuildTask/Microsoft/Build/Tasks/Xaml/PartialClassGenerationTask.cs @@ -198,8 +198,11 @@ namespace Microsoft.Build.Tasks.Xaml } else { - AppDomain.Unload(inProcessAppDomain); - inProcessAppDomain = null; + if (inProcessAppDomain != null) + { + AppDomain.Unload(inProcessAppDomain); + inProcessAppDomain = null; + } return GetAppDomainAndExecute(); } } diff --git a/mcs/class/referencesource/XamlBuildTask/Microsoft/Build/Tasks/Xaml/XamlBuildTaskServices.cs b/mcs/class/referencesource/XamlBuildTask/Microsoft/Build/Tasks/Xaml/XamlBuildTaskServices.cs index 03a90fba66a..a21ac391e5e 100644 --- a/mcs/class/referencesource/XamlBuildTask/Microsoft/Build/Tasks/Xaml/XamlBuildTaskServices.cs +++ b/mcs/class/referencesource/XamlBuildTask/Microsoft/Build/Tasks/Xaml/XamlBuildTaskServices.cs @@ -215,6 +215,12 @@ namespace Microsoft.Build.Tasks.Xaml appDomainSetup.ApplicationBase = buildTaskPath; appDomainSetup.LoaderOptimization = LoaderOptimization.MultiDomainHost; + // Set the AppDomainManager class name and assembly name to the empty string. We don't want the AppDomain to try to load the + // Microsoft.VisualStudio.Platform.AppDomainManager.dll because it is no longer in the GAC, so it won't be found + // by the AppDomain that is created for the in-process build to support Intellisense in Visual Studio. + appDomainSetup.AppDomainManagerType = ""; + appDomainSetup.AppDomainManagerAssembly = ""; + // Create appdomain with fulltrust. return AppDomain.CreateDomain( friendlyName, diff --git a/mcs/class/referencesource/mscorlib/InternalApis/NDP_Common/inc/PinnableBufferCache.cs b/mcs/class/referencesource/mscorlib/InternalApis/NDP_Common/inc/PinnableBufferCache.cs index 872cfa80dd5..19ec1053a3a 100644 --- a/mcs/class/referencesource/mscorlib/InternalApis/NDP_Common/inc/PinnableBufferCache.cs +++ b/mcs/class/referencesource/mscorlib/InternalApis/NDP_Common/inc/PinnableBufferCache.cs @@ -155,7 +155,14 @@ namespace System if (PinnableBufferCacheEventSource.Log.IsEnabled()) PinnableBufferCacheEventSource.Log.FreeBuffer(m_CacheName, PinnableBufferCacheEventSource.AddressOf(buffer), buffer.GetHashCode(), m_FreeList.Count); - + if(buffer == null) + { + if (PinnableBufferCacheEventSource.Log.IsEnabled()) + PinnableBufferCacheEventSource.Log.FreeBufferNull(m_CacheName, m_FreeList.Count); + + return; + } + // After we've done 3 gen1 GCs, assume that all buffers have aged into gen2 on the free path. if ((m_gen1CountAtLastRestock + 3) > GC.CollectionCount(GC.MaxGeneration - 1)) { @@ -567,6 +574,7 @@ namespace System public void AllocateBufferAged(string cacheName, int agedCount) {} public void AllocateBufferFreeListEmpty(string cacheName, int notGen2CountBefore) {} public void FreeBuffer(string cacheName, ulong objectId, int objectHash, int freeCountBefore) {} + public void FreeBufferNull(string cacheName, int freeCountBefore) { } public void FreeBufferStillTooYoung(string cacheName, int notGen2CountBefore) {} public void TrimCheck(string cacheName, int totalBuffs, bool neededMoreThanFreeList, int deltaMSec) {} public void TrimFree(string cacheName, int totalBuffs, int freeListCount, int toBeFreed) {} @@ -643,6 +651,8 @@ namespace System public void AgePendingBuffersResults(string cacheName, int promotedToFreeListCount, int heldBackCount) { if (IsEnabled()) WriteEvent(20, cacheName, promotedToFreeListCount, heldBackCount); } [Event(21)] public void WalkFreeListResult(string cacheName, int freeListCount, int gen0BuffersInFreeList) { if (IsEnabled()) WriteEvent(21, cacheName, freeListCount, gen0BuffersInFreeList); } + [Event(22)] + public void FreeBufferNull(string cacheName, int freeCountBefore) { if(IsEnabled()) WriteEvent(22, cacheName, freeCountBefore); } static internal ulong AddressOf(object obj) diff --git a/mcs/class/referencesource/mscorlib/microsoft/win32/win32native.cs b/mcs/class/referencesource/mscorlib/microsoft/win32/win32native.cs index 9c2df18a2da..1bf3586fe47 100644 --- a/mcs/class/referencesource/mscorlib/microsoft/win32/win32native.cs +++ b/mcs/class/referencesource/mscorlib/microsoft/win32/win32native.cs @@ -937,6 +937,10 @@ namespace Microsoft.Win32 { [ResourceExposure(ResourceScope.Machine)] internal unsafe static extern int GetFullPathName(char* path, int numBufferChars, char* buffer, IntPtr mustBeZero); + [DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] + [ResourceExposure(ResourceScope.Machine)] + internal unsafe static extern uint GetFullPathNameW(char* path, uint numBufferChars, SafeHandle buffer, IntPtr mustBeZero); + [DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)] [ResourceExposure(ResourceScope.Machine)] internal unsafe static extern int GetFullPathName(String path, int numBufferChars, [Out]StringBuilder buffer, IntPtr mustBeZero); @@ -949,6 +953,14 @@ namespace Microsoft.Win32 { [ResourceExposure(ResourceScope.Machine)] internal static extern int GetLongPathName(String path, [Out]StringBuilder longPathBuffer, int bufferLength); + [DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] + [ResourceExposure(ResourceScope.Machine)] + internal static extern uint GetLongPathNameW(SafeHandle lpszShortPath, SafeHandle lpszLongPath, uint cchBuffer); + + [DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] + [ResourceExposure(ResourceScope.Machine)] + internal static extern uint GetLongPathNameW(string lpszShortPath, SafeHandle lpszLongPath, uint cchBuffer); + // Disallow access to all non-file devices from methods that take // a String. This disallows DOS devices like "con:", "com1:", // "lpt1:", etc. Use this to avoid security problems, like allowing @@ -1397,6 +1409,10 @@ namespace Microsoft.Win32 { int nBufferLength, [Out]StringBuilder lpBuffer); + [DllImport(KERNEL32, SetLastError = true, CharSet = CharSet.Unicode, BestFitMapping = false, ExactSpelling = true)] + [ResourceExposure(ResourceScope.Machine)] + internal static extern uint GetCurrentDirectoryW(uint nBufferLength, SafeHandle lpBuffer); + [DllImport(KERNEL32, SetLastError=true, CharSet=CharSet.Auto, BestFitMapping=false)] [ResourceExposure(ResourceScope.None)] internal static extern bool GetFileAttributesEx(String name, int fileInfoLevel, ref WIN32_FILE_ATTRIBUTE_DATA lpFileInformation); diff --git a/mcs/class/referencesource/mscorlib/system/AppContext/AppContext.cs b/mcs/class/referencesource/mscorlib/system/AppContext/AppContext.cs index 0b00ff21821..fe0253ba38c 100644 --- a/mcs/class/referencesource/mscorlib/system/AppContext/AppContext.cs +++ b/mcs/class/referencesource/mscorlib/system/AppContext/AppContext.cs @@ -18,8 +18,7 @@ namespace System HasLookedForOverride = 0x4, UnknownValue = 0x8 // Has no default and could not find an override } - private static Dictionary s_switchMap = new Dictionary(); - private static readonly object s_syncLock = new object(); + private static readonly Dictionary s_switchMap = new Dictionary(); public static string BaseDirectory { @@ -151,11 +150,12 @@ namespace System if (switchName.Length == 0) throw new ArgumentException(Environment.GetResourceString("Argument_EmptyName"), "switchName"); - lock (s_syncLock) + SwitchValueState switchValue = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue) + | SwitchValueState.HasLookedForOverride; + lock (s_switchMap) { // Store the new value and the fact that we checked in the dictionary - s_switchMap[switchName] = (isEnabled ? SwitchValueState.HasTrueValue : SwitchValueState.HasFalseValue) - | SwitchValueState.HasLookedForOverride; + s_switchMap[switchName] = switchValue; } } diff --git a/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.Defaults.cs b/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.Defaults.cs index bc1f347abb0..d934f6ac188 100644 --- a/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.Defaults.cs +++ b/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.Defaults.cs @@ -1,4 +1,4 @@ -// ==++== +// ==++== // // Copyright (c) Microsoft Corporation. All rights reserved. // @@ -13,8 +13,11 @@ namespace System internal static readonly string SwitchNoAsyncCurrentCulture = "Switch.System.Globalization.NoAsyncCurrentCulture"; internal static readonly string SwitchThrowExceptionIfDisposedCancellationTokenSource = "Switch.System.Threading.ThrowExceptionIfDisposedCancellationTokenSource"; internal static readonly string SwitchPreserveEventListnerObjectIdentity = "Switch.System.Diagnostics.EventSource.PreserveEventListnerObjectIdentity"; + internal static readonly string SwitchUseLegacyPathHandling = "Switch.System.IO.UseLegacyPathHandling"; + internal static readonly string SwitchBlockLongPaths = "Switch.System.IO.BlockLongPaths"; + internal static readonly string SwitchSetActorAsReferenceWhenCopyingClaimsIdentity = "Switch.System.Security.ClaimsIdentity.SetActorAsReferenceWhenCopyingClaimsIdentity"; + - // This is a partial method. Platforms can provide an implementation of it that will set override values // from whatever mechanism is available on that platform. If no implementation is provided, the compiler is going to remove the calls // to it from the code @@ -41,6 +44,14 @@ namespace System AppContext.DefineSwitchDefault(SwitchNoAsyncCurrentCulture, true); AppContext.DefineSwitchDefault(SwitchThrowExceptionIfDisposedCancellationTokenSource, true); } + + if (version <= 40601) + { + AppContext.DefineSwitchDefault(SwitchUseLegacyPathHandling, true); + AppContext.DefineSwitchDefault(SwitchBlockLongPaths, true); + AppContext.DefineSwitchDefault(SwitchSetActorAsReferenceWhenCopyingClaimsIdentity, true); + } + break; } case "WindowsPhone": @@ -50,6 +61,8 @@ namespace System { AppContext.DefineSwitchDefault(SwitchNoAsyncCurrentCulture, true); AppContext.DefineSwitchDefault(SwitchThrowExceptionIfDisposedCancellationTokenSource, true); + AppContext.DefineSwitchDefault(SwitchUseLegacyPathHandling, true); + AppContext.DefineSwitchDefault(SwitchBlockLongPaths, true); } break; } diff --git a/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.cs b/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.cs index 8a130a0f342..9224bf8b8fb 100644 --- a/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.cs +++ b/mcs/class/referencesource/mscorlib/system/AppContext/AppContextDefaultValues.cs @@ -3,6 +3,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // // ==--== + +// There are cases where we have multiple assemblies that are going to import this file and +// if they are going to also have InternalsVisibleTo between them, there will be a compiler warning +// that the type is found both in the source and in a referenced assembly. The compiler will prefer +// the version of the type defined in the source +// +// In order to disable the warning for this type we are disabling this warning for this entire file. +#pragma warning disable 436 + using System; using System.Collections.Generic; @@ -167,3 +176,5 @@ namespace System static partial void PopulateDefaultValuesPartial(string platformIdentifier, string profile, int version); } } + +#pragma warning restore 436 diff --git a/mcs/class/referencesource/mscorlib/system/AppContext/AppContextSwitches.cs b/mcs/class/referencesource/mscorlib/system/AppContext/AppContextSwitches.cs index 539e877016d..72eb1cccb11 100644 --- a/mcs/class/referencesource/mscorlib/system/AppContext/AppContextSwitches.cs +++ b/mcs/class/referencesource/mscorlib/system/AppContext/AppContextSwitches.cs @@ -41,6 +41,48 @@ namespace System } } + private static int _useLegacyPathHandling; + + /// + /// Use legacy path normalization logic and blocking of extended syntax. + /// + public static bool UseLegacyPathHandling + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return GetCachedSwitchValue(AppContextDefaultValues.SwitchUseLegacyPathHandling, ref _useLegacyPathHandling); + } + } + + private static int _blockLongPaths; + + /// + /// Throw PathTooLongException for paths greater than MAX_PATH or directories greater than 248 (as per CreateDirectory Win32 limitations) + /// + public static bool BlockLongPaths + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return GetCachedSwitchValue(AppContextDefaultValues.SwitchBlockLongPaths, ref _blockLongPaths); + } + } + + private static int _cloneActor; + + /// + /// When copying a ClaimsIdentity.Actor this switch controls whether ClaimsIdentity.Actor should be set as a reference or the result of Actor.Clone() + /// + public static bool SetActorAsReferenceWhenCopyingClaimsIdentity + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get + { + return GetCachedSwitchValue(AppContextDefaultValues.SwitchSetActorAsReferenceWhenCopyingClaimsIdentity, ref _cloneActor); + } + } + // // Implementation details // diff --git a/mcs/class/referencesource/mscorlib/system/AppDomainSetup.cs b/mcs/class/referencesource/mscorlib/system/AppDomainSetup.cs index fb850445ce3..5509b402503 100644 --- a/mcs/class/referencesource/mscorlib/system/AppDomainSetup.cs +++ b/mcs/class/referencesource/mscorlib/system/AppDomainSetup.cs @@ -318,17 +318,23 @@ namespace System { } } - [ResourceExposure(ResourceScope.Machine)] - [ResourceConsumption(ResourceScope.Machine)] - private String NormalizePath(String path, bool useAppBase) + [System.Security.SecuritySafeCritical] + private string NormalizePath(string path, bool useAppBase) { if(path == null) return null; // If we add very long file name support ("\\?\") to the Path class then this is unnecesary, // but we do not plan on doing this for now. + + // Long path checks can be quirked, and as loading default quirks too early in the setup of an AppDomain is risky + // we'll avoid checking path lengths- we'll still fail at MAX_PATH later if we're !useAppBase when we call Path's + // NormalizePath. if (!useAppBase) - path = System.Security.Util.URLString.PreProcessForExtendedPathRemoval(path, false); + path = System.Security.Util.URLString.PreProcessForExtendedPathRemoval( + checkPathLength: false, + url: path, + isFileUrl: false); int len = path.Length; if (len == 0) @@ -417,10 +423,10 @@ namespace System { if (localPath) { - if (useAppBase && - ( (len == 1) || (path[1] != ':') )) { - String appBase = Value[(int) LoaderInformation.ApplicationBaseValue]; + ((len == 1) || (path[1] != ':'))) + { + String appBase = Value[(int)LoaderInformation.ApplicationBaseValue]; if ((appBase == null) || (appBase.Length == 0)) throw new MemberAccessException(Environment.GetResourceString("AppDomain_AppBaseNotSet")); @@ -429,7 +435,9 @@ namespace System { bool slash = false; if ((path[0] == '/') || (path[0] == '\\')) { - String pathRoot = Path.GetPathRoot(appBase); + // Emulate Path.GetPathRoot without hitting code paths that check quirks + string pathRoot = AppDomain.NormalizePath(appBase, fullCheck: false); + pathRoot = pathRoot.Substring(0, System.IO.PathInternal.GetRootLength(pathRoot)); if (pathRoot.Length == 0) { // URL int index = appBase.IndexOf(":/", StringComparison.Ordinal); if (index == -1) @@ -439,11 +447,11 @@ namespace System { int urlLen = appBase.Length; for (index += 1; (index < urlLen) && ((appBase[index] == '/') || (appBase[index] == '\\')); - index++); + index++) ; // Now find the next slash to get domain name - for(; (index < urlLen) && (appBase[index] != '/') && (appBase[index] != '\\'); - index++); + for (; (index < urlLen) && (appBase[index] != '/') && (appBase[index] != '\\'); + index++) ; pathRoot = appBase.Substring(0, index); } @@ -472,7 +480,9 @@ namespace System { path = StringBuilderCache.GetStringAndRelease(result); } else - path = Path.GetFullPathInternal(path); + { + path = AppDomain.NormalizePath(path, fullCheck: true); + } } return path; @@ -792,20 +802,32 @@ namespace System { [ResourceConsumption(ResourceScope.Machine)] private String VerifyDir(String dir, bool normalize) { - if (dir != null) { + if (dir != null) + { if (dir.Length == 0) + { dir = null; - else { + } + else + { if (normalize) dir = NormalizePath(dir, true); - // The only way AppDomainSetup is exposed in coreclr is through the AppDomainManager - // and the AppDomainManager is a SecurityCritical type. Also, all callers of callstacks - // leading from VerifyDir are SecurityCritical. So we can remove the Demand because - // we have validated that all callers are SecurityCritical + // The only way AppDomainSetup is exposed in coreclr is through the AppDomainManager + // and the AppDomainManager is a SecurityCritical type. Also, all callers of callstacks + // leading from VerifyDir are SecurityCritical. So we can remove the Demand because + // we have validated that all callers are SecurityCritical #if !FEATURE_CORECLR if (IsFilePath(dir)) - new FileIOPermission( FileIOPermissionAccess.PathDiscovery, dir ).Demand(); + { + // If we've already normalized we don't need to do it again, and can avoid hitting + // quirks in FileIOPermission. + new FileIOPermission( + access: FileIOPermissionAccess.PathDiscovery, + pathList: new string[] { dir }, + checkForDuplicates: false, + needFullPath: false).Demand(); + } #endif // !FEATURE_CORECLR } } diff --git a/mcs/class/referencesource/mscorlib/system/appdomain.cs b/mcs/class/referencesource/mscorlib/system/appdomain.cs index 0d7719d224a..2a704e83006 100644 --- a/mcs/class/referencesource/mscorlib/system/appdomain.cs +++ b/mcs/class/referencesource/mscorlib/system/appdomain.cs @@ -2712,7 +2712,7 @@ namespace System { get { String dyndir = GetDynamicDir(); if (dyndir != null) - new FileIOPermission( FileIOPermissionAccess.PathDiscovery, dyndir ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, dyndir); return dyndir; } @@ -3726,7 +3726,7 @@ namespace System { AppDomainInitializerInfo initializerInfo = (AppDomainInitializerInfo)args[5]; string sandboxName = (string)args[6]; string[] propertyNames = (string[])args[7]; // can contain null elements - string[] propertyValues = (string[])args[8]; // can contain null elements + string[] propertyValues = (string[])args[8]; // can contain null elements // extract evidence Evidence providedSecurityInfo = null; Evidence creatorsSecurityInfo = null; @@ -3748,18 +3748,17 @@ namespace System { if (Path.IsRelative(propertyValues[i])) throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) ); - newSetup.ApplicationBase=Path.NormalizePath(propertyValues[i],true); - + newSetup.ApplicationBase = NormalizePath(propertyValues[i], fullCheck: true); } #if FEATURE_CAS_POLICY else if(propertyNames[i]=="LOCATION_URI" && providedSecurityInfo==null) { providedSecurityInfo=new Evidence(); providedSecurityInfo.AddHostEvidence(new Url(propertyValues[i])); - ad.SetDataHelper(propertyNames[i],propertyValues[i],null); + ad.SetDataHelper(propertyNames[i],propertyValues[i],null); } #endif // FEATURE_CAS_POLICY -#if FEATURE_LOADER_OPTIMIZATION +#if FEATURE_LOADER_OPTIMIZATION else if(propertyNames[i]=="LOADER_OPTIMIZATION") { @@ -3775,8 +3774,8 @@ namespace System { default: throw new ArgumentException(Environment.GetResourceString("Argument_UnrecognizedLoaderOptimization"), "LOADER_OPTIMIZATION"); } } -#endif // FEATURE_LOADER_OPTIMIZATION -#if FEATURE_CORECLR +#endif // FEATURE_LOADER_OPTIMIZATION +#if FEATURE_CORECLR else if(propertyNames[i]=="NATIVE_DLL_SEARCH_DIRECTORIES") { @@ -3804,7 +3803,8 @@ namespace System { if (Path.IsRelative(path)) throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) ); - string appPath=Path.NormalizePath(path,true); + string appPath = NormalizePath(path, fullCheck: true); + normalisedAppPathList.Append(appPath); normalisedAppPathList.Append(Path.PathSeparator); } @@ -3813,7 +3813,7 @@ namespace System { { normalisedAppPathList.Remove(normalisedAppPathList.Length - 1, 1); } - ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly + ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly } else if(propertyNames[i]=="PLATFORM_RESOURCE_ROOTS") @@ -3831,7 +3831,8 @@ namespace System { if (Path.IsRelative(path)) throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) ); - string appPath=Path.NormalizePath(path,true); + string appPath = NormalizePath(path, fullCheck: true); + normalisedAppPathList.Append(appPath); normalisedAppPathList.Append(Path.PathSeparator); } @@ -3840,7 +3841,7 @@ namespace System { { normalisedAppPathList.Remove(normalisedAppPathList.Length - 1, 1); } - ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly + ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly } else if(propertyNames[i]=="APP_PATHS") @@ -3858,7 +3859,8 @@ namespace System { if (Path.IsRelative(path)) throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) ); - string appPath=Path.NormalizePath(path,true); + string appPath = NormalizePath(path, fullCheck: true); + normalisedAppPathList.Append(appPath); normalisedAppPathList.Append(Path.PathSeparator); } @@ -3867,7 +3869,7 @@ namespace System { { normalisedAppPathList.Remove(normalisedAppPathList.Length - 1, 1); } - ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly + ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly } else if(propertyNames[i]=="APP_NI_PATHS") @@ -3885,7 +3887,8 @@ namespace System { if (Path.IsRelative(path)) throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) ); - string appPath=Path.NormalizePath(path,true); + string appPath = NormalizePath(path, fullCheck: true); + normalisedAppPathList.Append(appPath); normalisedAppPathList.Append(Path.PathSeparator); } @@ -3894,12 +3897,12 @@ namespace System { { normalisedAppPathList.Remove(normalisedAppPathList.Length - 1, 1); } - ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly + ad.SetDataHelper(propertyNames[i],normalisedAppPathList.ToString(),null); // not supported by fusion, so set explicitly } else if(propertyNames[i]!= null) { - ad.SetDataHelper(propertyNames[i],propertyValues[i],null); // just propagate + ad.SetDataHelper(propertyNames[i],propertyValues[i],null); // just propagate } #endif @@ -3993,6 +3996,19 @@ namespace System { #endif // FEATURE_CLICKONCE } + [SecuritySafeCritical] + internal static string NormalizePath(string path, bool fullCheck) + { + // We have to directly hit LegacyNormalizePath to avoid loading quirks for + // the AppDomain. (Once we have runtime support for long paths we can + // use the new normalization in path, but we still need to go in directly + // to avoid quirks.) + return Path.LegacyNormalizePath( + path: path, + fullCheck: fullCheck, + maxPathLength: PathInternal.MaxShortPath, + expandShortPaths: true); + } #if FEATURE_APTCA // Called from DomainAssembly in Conditional APTCA cases @@ -4654,7 +4670,7 @@ namespace System { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [MethodImplAttribute(MethodImplOptions.InternalCall)] - [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] + [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] internal extern Int32 GetId(); internal const Int32 DefaultADID = 1; @@ -4675,6 +4691,7 @@ namespace System { Contract.Assert(i != -1, "invalid image location"); AppDomainSetup info = new AppDomainSetup(); + info.ApplicationBase = imageLocation.Substring(0, i+1); StringBuilder config = new StringBuilder(imageLocation.Substring(i+1)); @@ -4685,7 +4702,7 @@ namespace System { } // Used by the validator for testing but not executing an assembly -#if FEATURE_REMOTING +#if FEATURE_REMOTING [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] private static AppDomain InternalCreateDomain(String imageLocation) diff --git a/mcs/class/referencesource/mscorlib/system/bitconverter.cs b/mcs/class/referencesource/mscorlib/system/bitconverter.cs index a8a864ac12a..49d20cd6697 100644 --- a/mcs/class/referencesource/mscorlib/system/bitconverter.cs +++ b/mcs/class/referencesource/mscorlib/system/bitconverter.cs @@ -372,7 +372,7 @@ namespace System { // Converts an array of bytes into a String. public static String ToString (byte[] value, int startIndex, int length) { if (value == null) { - throw new ArgumentNullException("byteArray"); + throw new ArgumentNullException("value"); } if (startIndex < 0 || startIndex >= value.Length && startIndex > 0) { // Don't throw for a 0 length array. diff --git a/mcs/class/referencesource/mscorlib/system/deployment/cmsutils.cs b/mcs/class/referencesource/mscorlib/system/deployment/cmsutils.cs index 1c0fb31377f..247c7dfe287 100644 --- a/mcs/class/referencesource/mscorlib/system/deployment/cmsutils.cs +++ b/mcs/class/referencesource/mscorlib/system/deployment/cmsutils.cs @@ -79,18 +79,18 @@ namespace System.Deployment.Internal.Isolation.Manifest { [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - internal static string GetEntryPointFullPath (ActivationContext activationContext) { + internal static string GetEntryPointFullPath (ActivationContext activationContext) + { string file, parameters; GetEntryPoint(activationContext, out file, out parameters); - if (!String.IsNullOrEmpty(file)) { + if (!string.IsNullOrEmpty(file)) + { string directoryName = activationContext.ApplicationDirectory; - if (directoryName == null || directoryName.Length == 0) { + if (directoryName == null || directoryName.Length == 0) + { // If we were passed a relative path, assume the app base is the current working directory - StringBuilder sb = new StringBuilder(Path.MAX_PATH + 1); - if (Win32Native.GetCurrentDirectory(sb.Capacity, sb) == 0) - System.IO.__Error.WinIOError(); - directoryName = sb.ToString(); + directoryName = Directory.UnsafeGetCurrentDirectory(); } file = Path.Combine(directoryName, file); diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/SimpleTypeInfos.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/SimpleTypeInfos.cs index cd70bfb23e3..08844d397a4 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/SimpleTypeInfos.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/SimpleTypeInfos.cs @@ -833,6 +833,15 @@ namespace System.Diagnostics.Tracing { collector.AddBinary(value); } + + public override object GetData(object value) + { + object val = base.GetData(value); + if (null == val) + val = ""; + + return val; + } } /// diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingEventSource.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingEventSource.cs index d620ff96357..ae38d4fde59 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingEventSource.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingEventSource.cs @@ -460,6 +460,7 @@ namespace System.Diagnostics.Tracing } this.WriteEventRaw( + eventName, ref descriptor, activityID, childActivityID, @@ -564,6 +565,7 @@ namespace System.Diagnostics.Tracing } this.WriteEventRaw( + eventName, ref descriptor, activityID, childActivityID, @@ -646,6 +648,7 @@ namespace System.Diagnostics.Tracing eventTypes.typeInfo.WriteData(TraceLoggingDataCollector.Instance, ref data); this.WriteEventRaw( + eventName, ref descriptor, pActivityId, pRelatedActivityId, @@ -665,7 +668,7 @@ namespace System.Diagnostics.Tracing if (ex is EventSourceException) throw; else - ThrowEventSourceException(ex); + ThrowEventSourceException(eventName, ex); } finally { @@ -679,7 +682,7 @@ namespace System.Diagnostics.Tracing if (ex is EventSourceException) throw; else - ThrowEventSourceException(ex); + ThrowEventSourceException(eventName, ex); } } @@ -703,7 +706,7 @@ namespace System.Diagnostics.Tracing eventCallbackArgs.PayloadNames = new ReadOnlyCollection((IList)payload.Keys); } - DisptachToAllListeners(-1, pActivityId, eventCallbackArgs); + DispatchToAllListeners(-1, pActivityId, eventCallbackArgs); } #if !ES_BUILD_PCL diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingMetadataCollector.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingMetadataCollector.cs index 1d1f1e708fe..ed5ffeca906 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingMetadataCollector.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/TraceLogging/TraceLoggingMetadataCollector.cs @@ -99,7 +99,7 @@ namespace System.Diagnostics.Tracing var newGroup = new FieldMetadata( name, TraceLoggingDataType.Struct, - 0, + this.Tags, this.BeginningBufferedArray); this.AddField(newGroup); result = new TraceLoggingMetadataCollector(this, newGroup); diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/activitytracker.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/activitytracker.cs index 633183d941a..bdfa364fe10 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/activitytracker.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/activitytracker.cs @@ -1,8 +1,6 @@ using System; using System.Diagnostics; using System.Threading; -using System.Threading.Tasks; - #if !ES_BUILD_AGAINST_DOTNET_V35 using Contract = System.Diagnostics.Contracts.Contract; #else @@ -11,15 +9,16 @@ using Contract = Microsoft.Diagnostics.Contracts.Internal.Contract; #if ES_BUILD_STANDALONE namespace Microsoft.Diagnostics.Tracing -#else +#else +using System.Threading.Tasks; namespace System.Diagnostics.Tracing #endif { /// - /// Tracks activities. This is meant to be a singledon (accessed by the ActivityTracer.Instance static property) + /// Tracks activities. This is meant to be a singleton (accessed by the ActivityTracer.Instance static property) /// /// Logically this is simply holds the m_current variable that holds the async local that holds the current ActivityInfo - /// An ActivityInfo is represents a actvity (which knows its creator and thus knows its path). + /// An ActivityInfo is represents a activity (which knows its creator and thus knows its path). /// /// Most of the magic is in the async local (it gets copied to new tasks) /// @@ -39,7 +38,7 @@ namespace System.Diagnostics.Tracing /// On any normal event log the event with activityTracker.CurrentActivityId /// internal class ActivityTracker - { + { /// /// Called on work item begins. The activity name = providerName + activityName without 'Start' suffix. @@ -55,15 +54,32 @@ namespace System.Diagnostics.Tracing public void OnStart(string providerName, string activityName, int task, ref Guid activityId, ref Guid relatedActivityId, EventActivityOptions options) { if (m_current == null) // We are not enabled - return; + { + // We used to rely on the TPL provider turning us on, but that has the disadvantage that you don't get Start-Stop tracking + // until you use Tasks for the first time (which you may never do). Thus we change it to pull rather tan push for whether + // we are enabled. + if (m_checkedForEnable) + return; + m_checkedForEnable = true; +#if ES_BUILD_STANDALONE + Enable(); // Enable it unconditionally. +#else + if (System.Threading.Tasks.TplEtwProvider.Log.IsEnabled(EventLevel.Informational, System.Threading.Tasks.TplEtwProvider.Keywords.TasksFlowActivityIds)) + Enable(); +#endif + if(m_current == null) + { + return; + } + } Contract.Assert((options & EventActivityOptions.Disable) == 0); var currentActivity = m_current.Value; var fullActivityName = NormalizeActivityName(providerName, activityName, task); - + var etwLog = TplEtwProvider.Log; - if (etwLog.Debug) + if (etwLog.Debug) { etwLog.DebugFacilityMessage("OnStartEnter", fullActivityName); etwLog.DebugFacilityMessage("OnStartEnterActivityState", ActivityInfo.LiveActivities(currentActivity)); @@ -100,17 +116,17 @@ namespace System.Diagnostics.Tracing else id = Interlocked.Increment(ref currentActivity.m_lastChildID); - // Remember the previous ID so we can log it - relatedActivityId = currentActivity != null ? currentActivity.ActivityId : Guid.Empty; + // The previous ID is my 'causer' and becomes my related activity ID + relatedActivityId = EventSource.CurrentThreadActivityId; // Add to the list of started but not stopped activities. - ActivityInfo newActivity = new ActivityInfo(fullActivityName, id, currentActivity, options); + ActivityInfo newActivity = new ActivityInfo(fullActivityName, id, currentActivity, relatedActivityId, options); m_current.Value = newActivity; // Remember the current ID so we can log it activityId = newActivity.ActivityId; - if (etwLog.Debug) + if (etwLog.Debug) { etwLog.DebugFacilityMessage("OnStartRetActivityState", ActivityInfo.LiveActivities(newActivity)); etwLog.DebugFacilityMessage1("OnStartRet", activityId.ToString(), relatedActivityId.ToString()); @@ -119,7 +135,7 @@ namespace System.Diagnostics.Tracing /// /// Called when a work item stops. The activity name = providerName + activityName without 'Stop' suffix. - /// It updates CurrentActivityId to track this fact. The Stop event associated with stop should log the ActivityID associated with the event. + /// It updates m_current variable to track this fact. The Stop event associated with stop should log the ActivityID associated with the event. /// /// If activity tracing is not on, then activityId and relatedActivityId are not set /// @@ -131,13 +147,13 @@ namespace System.Diagnostics.Tracing var fullActivityName = NormalizeActivityName(providerName, activityName, task); var etwLog = TplEtwProvider.Log; - if (etwLog.Debug) + if (etwLog.Debug) { etwLog.DebugFacilityMessage("OnStopEnter", fullActivityName); etwLog.DebugFacilityMessage("OnStopEnterActivityState", ActivityInfo.LiveActivities(m_current.Value)); } - for (; ;) // This is a retry loop. + for (; ; ) // This is a retry loop. { ActivityInfo currentActivity = m_current.Value; ActivityInfo newCurrentActivity = null; // if we have seen any live activities (orphans), at he first one we have seen. @@ -193,7 +209,7 @@ namespace System.Diagnostics.Tracing m_current.Value = newCurrentActivity; - if (etwLog.Debug) + if (etwLog.Debug) { etwLog.DebugFacilityMessage("OnStopRetActivityState", ActivityInfo.LiveActivities(newCurrentActivity)); etwLog.DebugFacilityMessage("OnStopRet", activityId.ToString()); @@ -210,12 +226,12 @@ namespace System.Diagnostics.Tracing [System.Security.SecuritySafeCritical] public void Enable() { - if (m_current == null) + if (m_current == null) { m_current = new AsyncLocal(ActivityChanging); } } - + /// /// An activity tracker is a singleton, this is how you get the one and only instance. /// @@ -263,24 +279,25 @@ namespace System.Diagnostics.Tracing // ******************************************************************************* /// - /// An ActivityInfo repesents a particular activity. It is almost read-only the only + /// An ActivityInfo represents a particular activity. It is almost read-only. The only /// fields that change after creation are /// m_lastChildID - used to generate unique IDs for the children activities and for the most part can be ignored. /// m_stopped - indicates that this activity is dead - /// This read-only ness is important because an activity's m_creator chain forms the + /// This read-only-ness is important because an activity's m_creator chain forms the /// 'Path of creation' for the activity (which is also its unique ID) but is also used as /// the 'list of live parents' which indicate of those ancestors, which are alive (if they /// are not marked dead they are alive). /// private class ActivityInfo { - public ActivityInfo(string name, long uniqueId, ActivityInfo creator, EventActivityOptions options) + public ActivityInfo(string name, long uniqueId, ActivityInfo creator, Guid activityIDToRestore, EventActivityOptions options) { m_name = name; m_eventOptions = options; m_creator = creator; m_uniqueId = uniqueId; m_level = creator != null ? creator.m_level + 1 : 0; + m_activityIdToRestore = activityIDToRestore; // Create a nice GUID that encodes the chain of activities that started this one. CreateActivityPathGuid(out m_guid, out m_activityPathGuidOffset); @@ -294,19 +311,19 @@ namespace System.Diagnostics.Tracing } } - public static string Path(ActivityInfo activityInfo) + public static string Path(ActivityInfo activityInfo) { if (activityInfo == null) - return(""); + return (""); return Path(activityInfo.m_creator) + "/" + activityInfo.m_uniqueId; } - public override string ToString() + public override string ToString() { string dead = ""; if (m_stopped != 0) - dead = ",DEAD"; - return m_name + "(" + Path(this) + dead + ")"; + dead = ",DEAD"; + return m_name + "(" + Path(this) + dead + ")"; } public static string LiveActivities(ActivityInfo list) @@ -331,10 +348,10 @@ namespace System.Diagnostics.Tracing /// (rooted in an activity that predates activity tracking. /// /// We wish to encode this path in the Guid to the extent that we can. Many of the paths have - /// many small numbers in them and we take advatage of this in the encoding to output as long + /// many small numbers in them and we take advantage of this in the encoding to output as long /// a path in the GUID as possible. /// - /// Because of the possiblility of GUID collistion, we only use 96 of the 128 bits of the GUID + /// Because of the possibility of GUID collision, we only use 96 of the 128 bits of the GUID /// for encoding the path. The last 32 bits are a simple checksum (and random number) that /// identifies this as using the convention defined here. /// @@ -347,7 +364,7 @@ namespace System.Diagnostics.Tracing [System.Security.SecuritySafeCritical] private unsafe void CreateActivityPathGuid(out Guid idRet, out int activityPathGuidOffset) { - fixed (Guid* outPtr = &idRet) + fixed (Guid* outPtr = &idRet) { int activityPathGuidOffsetStart = 0; if (m_creator != null) @@ -355,13 +372,18 @@ namespace System.Diagnostics.Tracing activityPathGuidOffsetStart = m_creator.m_activityPathGuidOffset; idRet = m_creator.m_guid; } - else + else { - // We start with the appdomain number to make this unique among appdomains. - activityPathGuidOffsetStart = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint) System.Threading.Thread.GetDomainID()); + // + int appDomainID = 0; +#if !ES_BUILD_PCL + appDomainID = System.Threading.Thread.GetDomainID(); +#endif + // We start with the appdomain number to make this unique among appdomains. + activityPathGuidOffsetStart = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)appDomainID); } - activityPathGuidOffset = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint) m_uniqueId); + activityPathGuidOffset = AddIdToGuid(outPtr, activityPathGuidOffsetStart, (uint)m_uniqueId); // If the path does not fit, Make a GUID by incrementing rather than as a path, keeping as much of the path as possible @@ -372,19 +394,19 @@ namespace System.Diagnostics.Tracing /// /// If we can't fit the activity Path into the GUID we come here. What we do is simply - /// generate a 4 byte number (s_nextOverflowId). Then look for an anscesor that has + /// generate a 4 byte number (s_nextOverflowId). Then look for an ancestor that has /// sufficient space for this ID. By doing this, we preserve the fact that this activity /// is a child (of unknown depth) from that ancestor. /// [System.Security.SecurityCritical] private unsafe void CreateOverflowGuid(Guid* outPtr) { - // Seach backwards for an ancestor that has sufficient space to put the ID. - for(ActivityInfo ancestor = m_creator; ancestor != null; ancestor = ancestor.m_creator) + // Search backwards for an ancestor that has sufficient space to put the ID. + for (ActivityInfo ancestor = m_creator; ancestor != null; ancestor = ancestor.m_creator) { if (ancestor.m_activityPathGuidOffset <= 10) // we need at least 2 bytes. { - uint id = (uint) Interlocked.Increment(ref ancestor.m_lastChildID); // Get a unique ID + uint id = unchecked((uint)Interlocked.Increment(ref ancestor.m_lastChildID)); // Get a unique ID // Try to put the ID into the GUID *outPtr = ancestor.m_guid; int endId = AddIdToGuid(outPtr, ancestor.m_activityPathGuidOffset, id, true); @@ -397,8 +419,8 @@ namespace System.Diagnostics.Tracing } /// - /// The encoding for a list of numbers used to make Activity Guids. Basically - /// we operate on nibbles (which are nice becase they show up as hex digits). The + /// The encoding for a list of numbers used to make Activity GUIDs. Basically + /// we operate on nibbles (which are nice because they show up as hex digits). The /// list is ended with a end nibble (0) and depending on the nibble value (Below) /// the value is either encoded into nibble itself or it can spill over into the /// bytes that follow. @@ -409,18 +431,18 @@ namespace System.Diagnostics.Tracing LastImmediateValue = 0xA, PrefixCode = 0xB, // all the 'long' encodings go here. If the next nibble is MultiByte1-4 - // than this is a 'overflow' id. Unlike the hierarchitcal IDs these are - // allocated densly but don't tell you anything about nesting. we use - // these when we run out of space in the GUID to store the path. + // than this is a 'overflow' id. Unlike the hierarchical IDs these are + // allocated densely but don't tell you anything about nesting. we use + // these when we run out of space in the GUID to store the path. MultiByte1 = 0xC, // 1 byte follows. If this Nibble is in the high bits, it the high bits of the number are stored in the low nibble. // commented out because the code does not explicitly reference the names (but they are logically defined). - // MultiByte2 = 0xD, // 2 bytes follow (we don't bother with the nibble optimzation) - // MultiByte3 = 0xE, // 3 bytes follow (we don't bother with the nibble optimzation) - // MultiByte4 = 0xF, // 4 bytes follow (we don't bother with the nibble optimzation) + // MultiByte2 = 0xD, // 2 bytes follow (we don't bother with the nibble optimization) + // MultiByte3 = 0xE, // 3 bytes follow (we don't bother with the nibble optimization) + // MultiByte4 = 0xF, // 4 bytes follow (we don't bother with the nibble optimization) } - /// Add the acivity id 'id' to the output Guid 'outPtr' starting at the offset 'whereToAddId' + /// Add the activity id 'id' to the output Guid 'outPtr' starting at the offset 'whereToAddId' /// Thus if this number is 6 that is where 'id' will be added. This will return 13 (12 /// is the maximum number of bytes that fit in a GUID) if the path did not fit. /// If 'overflow' is true, then the number is encoded as an 'overflow number (which has a @@ -450,9 +472,9 @@ namespace System.Diagnostics.Tracing { if (endPtr <= ptr + 2) // I need at least 2 bytes return 13; - + // Write out the prefix code nibble and the length nibble - WriteNibble(ref ptr, endPtr, (uint) NumberListCodes.PrefixCode); + WriteNibble(ref ptr, endPtr, (uint)NumberListCodes.PrefixCode); } // The rest is the same for overflow and non-overflow case WriteNibble(ref ptr, endPtr, (uint)NumberListCodes.MultiByte1 + (len - 1)); @@ -460,7 +482,7 @@ namespace System.Diagnostics.Tracing // Do we have an odd nibble? If so flush it or use it for the 12 byte case. if (ptr < endPtr && *ptr != 0) { - // If the value < 4096 we can use the nibble we are otherwise just outputing as padding. + // If the value < 4096 we can use the nibble we are otherwise just outputting as padding. if (id < 4096) { // Indicate this is a 1 byte multicode with 4 high order bits in the lower nibble. @@ -471,7 +493,7 @@ namespace System.Diagnostics.Tracing } // Write out the bytes. - while(0 < len) + while (0 < len) { if (endPtr <= ptr) { @@ -514,14 +536,15 @@ namespace System.Diagnostics.Tracing #endregion // CreateGuidForActivityPath readonly internal string m_name; // The name used in the 'start' and 'stop' APIs to help match up - readonly long m_uniqueId; // a small number that makes this activity unique among its siblings - internal readonly Guid m_guid; // Activity Guid, it is bascially an encoding of the Path() (see CreateActivityPathGuid) + readonly long m_uniqueId; // a small number that makes this activity unique among its siblings + internal readonly Guid m_guid; // Activity Guid, it is basically an encoding of the Path() (see CreateActivityPathGuid) internal readonly int m_activityPathGuidOffset; // Keeps track of where in m_guid the causality path stops (used to generated child GUIDs) internal readonly int m_level; // current depth of the Path() of the activity (used to keep recursion under control) readonly internal EventActivityOptions m_eventOptions; // Options passed to start. internal long m_lastChildID; // used to create a unique ID for my children activities internal int m_stopped; // This work item has stopped readonly internal ActivityInfo m_creator; // My parent (creator). Forms the Path() for the activity. + readonly internal Guid m_activityIdToRestore; // The Guid to restore after a stop. #endregion } @@ -530,26 +553,50 @@ namespace System.Diagnostics.Tracing // with m_current.ActivityID void ActivityChanging(AsyncLocalValueChangedArgs args) { - if (args.PreviousValue == args.CurrentValue) - return; + ActivityInfo cur = args.CurrentValue; + ActivityInfo prev = args.PreviousValue; - if (args.CurrentValue != null) + // Are we popping off a value? (we have a prev, and it creator is cur) + // Then check if we should use the GUID at the time of the start event + if (prev != null && prev.m_creator == cur) { - // Allow subsequent activities inside this thread to automatically get the current activity ID. - EventSource.SetCurrentThreadActivityId(args.CurrentValue.ActivityId); + // If the saved activity ID is not the same as the creator activity + // that takes precedence (it means someone explicitly did a SetActivityID) + // Set it to that and get out + if (cur == null || prev.m_activityIdToRestore != cur.ActivityId) + { + EventSource.SetCurrentThreadActivityId(prev.m_activityIdToRestore); + return; + } } - else - EventSource.SetCurrentThreadActivityId(Guid.Empty); + + // OK we did not have an explicit SetActivityID set. Then we should be + // setting the activity to current ActivityInfo. However that activity + // might be dead, in which case we should skip it, so we never set + // the ID to dead things. + while(cur != null) + { + // We found a live activity (typically the first time), set it to that. + if (cur.m_stopped == 0) + { + EventSource.SetCurrentThreadActivityId(cur.ActivityId); + return; + } + cur = cur.m_creator; + } + // we can get here if there is no information on our activity stack (everything is dead) + // currently we do nothing, as that seems better than setting to Guid.Emtpy. } /// - /// Async local variables have the propery that the are automatically copied whenever a task is created and used + /// Async local variables have the properly that the are automatically copied whenever a task is created and used /// while that task is running. Thus m_current 'flows' to any task that is caused by the current thread that /// last set it. /// /// This variable points a a linked list that represents all Activities that have started but have not stopped. /// AsyncLocal m_current; + bool m_checkedForEnable; // Singleton private static ActivityTracker s_activityTrackerInstance = new ActivityTracker(); @@ -557,8 +604,74 @@ namespace System.Diagnostics.Tracing // Used to create unique IDs at the top level. Not used for nested Ids (each activity has its own id generator) static long m_nextId = 0; private const ushort MAX_ACTIVITY_DEPTH = 100; // Limit maximum depth of activities to be tracked at 100. - // This will avoid leaking memory in case of activities that are never stopped. + // This will avoid leaking memory in case of activities that are never stopped. #endregion } + +#if ES_BUILD_STANDALONE + /******************************** SUPPORT *****************************/ + /// + /// This is supplied by the framework. It is has the semantics that the value is copied to any new Tasks that is created + /// by the current task. Thus all causally related code gets this value. Note that reads and writes to this VARIABLE + /// (not what it points it) to this does not need to be protected by locks because it is inherently thread local (you always + /// only get your thread local copy which means that you never have ----s. + /// + /// + [EventSource(Name="Microsoft.Tasks.Nuget")] + internal class TplEtwProvider : EventSource + { + public class Keywords + { + public const EventKeywords Debug = (EventKeywords) 1; + } + + public static TplEtwProvider Log = new TplEtwProvider(); + public bool Debug { get { return IsEnabled(EventLevel.Verbose, Keywords.Debug); } } + + public void DebugFacilityMessage(string Facility, string Message) { WriteEvent(1, Facility, Message); } + public void DebugFacilityMessage1(string Facility, string Message, string Arg) { WriteEvent(2, Facility, Message, Arg); } + public void SetActivityId(Guid Id) { WriteEvent(3, Id); } + } +#endif + +#if ES_BUILD_AGAINST_DOTNET_V35 || ES_BUILD_PCL || NO_ASYNC_LOCAL + + internal sealed class AsyncLocalValueChangedArgs + { + public AsyncLocalValueChangedArgs() + { + } + + public T PreviousValue { get { return default(T); } } + public T CurrentValue { get { return default(T); } } + + } + + internal sealed class AsyncLocal + { + public AsyncLocal() + { + } + + public AsyncLocal(Action> valueChangedHandler) + { + + } + + public T Value + { + get + { + object obj = null; // + return (obj == null) ? default(T) : (T)obj; + } + set + { + // + } + } + } +#endif + } diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventprovider.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventprovider.cs index 8a3fec6e6f4..939d15ee520 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventprovider.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventprovider.cs @@ -91,7 +91,7 @@ namespace System.Diagnostics.Tracing private static WriteEventErrorCode s_returnCode; // The last return code private const int s_basicTypeAllocationBufferSize = 16; - private const int s_etwMaxNumberArguments = 32; + private const int s_etwMaxNumberArguments = 128; private const int s_etwAPIMaxRefObjCount = 8; private const int s_maxEventDataDescriptors = 128; private const int s_traceEventMaximumSize = 65482; diff --git a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventsource.cs b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventsource.cs index a1b51851218..9ae56693725 100644 --- a/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventsource.cs +++ b/mcs/class/referencesource/mscorlib/system/diagnostics/eventing/eventsource.cs @@ -1,5 +1,4 @@ -// Copyright (c) Microsoft Corporation. All rights reserved -// Copyright (c) Microsoft Corporation. All rights reserved +// Copyright (c) Microsoft Corporation. All rights reserved // This program uses code hyperlinks available as part of the HyperAddin Visual Studio plug-in. // It is available from http://www.codeplex.com/hyperAddin #define FEATURE_MANAGED_ETW @@ -13,7 +12,7 @@ // #define FEATURE_ADVANCED_MANAGED_ETW_CHANNELS #endif -/* DESIGN NOTES DESIGN NOTES DESIGN NOTES DESIGN NOTES */ +/* DESIGN NOTES DESIGN NOTES DESIGN NOTES DESIGN NOTES */ // DESIGN NOTES // Over the years EventSource has become more complex and so it is important to understand // the basic structure of the code to insure that it does not grow more complex. @@ -169,6 +168,7 @@ using System; +using System.Runtime.CompilerServices; #if FEATURE_ACTIVITYSAMPLING using System.Collections.Concurrent; #endif @@ -531,6 +531,7 @@ namespace System.Diagnostics.Tracing #if FEATURE_ACTIVITYSAMPLING Guid newId = activityId; #endif // FEATURE_ACTIVITYSAMPLING + // We ignore errors to keep with the convention that EventSources do not throw errors. // Note we can't access m_throwOnWrites because this is a static method. if (UnsafeNativeMethods.ManifestEtw.EventActivityIdControl( @@ -594,7 +595,7 @@ namespace System.Diagnostics.Tracing /// public static Guid CurrentThreadActivityId { - [System.Security.SecurityCritical] + [System.Security.SecuritySafeCritical] get { // We ignore errors to keep with the convention that EventSources do not throw @@ -680,6 +681,30 @@ namespace System.Diagnostics.Tracing /// public override string ToString() { return Environment.GetResourceString("EventSource_ToString", Name, Guid); } + /// + /// Fires when a Command (e.g. Enable) comes from a an EventListener. + /// + public event EventHandler EventCommandExecuted + { + add + { + m_eventCommandExecuted += value; + + // If we have an EventHandler attached to the EventSource before the first command arrives + // It should get a chance to handle the deferred commands. + EventCommandEventArgs deferredCommands = m_deferredCommands; + while (deferredCommands != null) + { + value(this, deferredCommands); + deferredCommands = deferredCommands.nextCommand; + } + } + remove + { + m_eventCommandExecuted -= value; + } + } + #region protected /// /// This is the constructor that most users will use to create their eventSource. It takes @@ -1152,7 +1177,7 @@ namespace System.Diagnostics.Tracing { Contract.Assert(m_eventData != null); // You must have initialized this if you enabled the source. if (relatedActivityId != null) - ValidateEventOpcodeForTransfer(ref m_eventData[eventId]); + ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name); #if FEATURE_MANAGED_ETW if (m_eventData[eventId].EnabledForETW) @@ -1202,7 +1227,7 @@ namespace System.Diagnostics.Tracing // mask set to 0x0f so, when all ETW sessions want the event we don't need to // synthesize a new one if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } else { @@ -1222,7 +1247,7 @@ namespace System.Diagnostics.Tracing unchecked((long)etwSessions.ToEventKeywords() | origKwd)); if (!m_provider.WriteEvent(ref desc, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } } else @@ -1252,7 +1277,7 @@ namespace System.Diagnostics.Tracing if (!SelfDescribingEvents) { if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, relatedActivityId, eventDataCount, (IntPtr)data)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } else { @@ -1286,7 +1311,7 @@ namespace System.Diagnostics.Tracing if (ex is EventSourceException) throw; else - ThrowEventSourceException(ex); + ThrowEventSourceException(m_eventData[eventId].Name, ex); } } } @@ -1402,6 +1427,7 @@ namespace System.Diagnostics.Tracing #endif [SecurityCritical] private unsafe void WriteEventRaw( + string eventName, ref EventDescriptor eventDescriptor, Guid* activityID, Guid* relatedActivityID, @@ -1410,12 +1436,12 @@ namespace System.Diagnostics.Tracing { if (m_provider == null) { - ThrowEventSourceException(); + ThrowEventSourceException(eventName); } else { if (!m_provider.WriteEventRaw(ref eventDescriptor, activityID, relatedActivityID, dataCount, data)) - ThrowEventSourceException(); + ThrowEventSourceException(eventName); } } @@ -1516,10 +1542,13 @@ namespace System.Diagnostics.Tracing { // If there are any deferred commands, we can do them now. // This is the most likely place for exceptions to happen. - while (m_deferredCommands != null) + // Note that we are NOT resetting m_deferredCommands to NULL here, + // We are giving for EventHandler that will be attached later + EventCommandEventArgs deferredCommands = m_deferredCommands; + while (deferredCommands != null) { - DoCommand(m_deferredCommands); // This can never throw, it catches them and reports the errors. - m_deferredCommands = m_deferredCommands.nextCommand; + DoCommand(deferredCommands); // This can never throw, it catches them and reports the errors. + deferredCommands = deferredCommands.nextCommand; } } } @@ -1817,7 +1846,7 @@ namespace System.Diagnostics.Tracing dataPointer = data->DataPointer; data++; for (int i = 0; i < cbSize; ++i) - blob[i] = *((byte*)dataPointer); + blob[i] = *((byte*)dataPointer + i); return blob; } else if (dataType == typeof(byte*)) @@ -1863,8 +1892,24 @@ namespace System.Diagnostics.Tracing { Contract.Assert(m_eventData != null); // You must have initialized this if you enabled the source. if (childActivityID != null) - ValidateEventOpcodeForTransfer(ref m_eventData[eventId]); - + { + ValidateEventOpcodeForTransfer(ref m_eventData[eventId], m_eventData[eventId].Name); + + // If you use WriteEventWithRelatedActivityID you MUST declare the first argument to be a GUID + // with the name 'relatedActivityID, and NOT pass this argument to the WriteEvent method. + // During manifest creation we modify the ParameterInfo[] that we store to strip out any + // first parameter that is of type Guid and named "relatedActivityId." Thus, if you call + // WriteEventWithRelatedActivityID from a method that doesn't name its first parameter correctly + // we can end up in a state where the ParameterInfo[] doesn't have its first parameter stripped, + // and this leads to a mismatch between the number of arguments and the number of ParameterInfos, + // which would cause a cryptic IndexOutOfRangeException later if we don't catch it here. + if (!m_eventData[eventId].HasRelatedActivityID) + { + throw new ArgumentException(Environment.GetResourceString("EventSource_NoRelatedActivityId")); + } + } + + LogEventArgsMismatches(m_eventData[eventId].Parameters, args); #if FEATURE_MANAGED_ETW if (m_eventData[eventId].EnabledForETW) { @@ -1909,7 +1954,7 @@ namespace System.Diagnostics.Tracing // mask set to 0x0f so, when all ETW sessions want the event we don't need to // synthesize a new one if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } else { @@ -1926,7 +1971,7 @@ namespace System.Diagnostics.Tracing unchecked((long)(ulong)etwSessions | origKwd)); if (!m_provider.WriteEvent(ref desc, pActivityId, childActivityID, args)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } } else @@ -1956,7 +2001,7 @@ namespace System.Diagnostics.Tracing if (!SelfDescribingEvents) { if (!m_provider.WriteEvent(ref m_eventData[eventId].Descriptor, pActivityId, childActivityID, args)) - ThrowEventSourceException(); + ThrowEventSourceException(m_eventData[eventId].Name); } else { @@ -2003,7 +2048,7 @@ namespace System.Diagnostics.Tracing if (ex is EventSourceException) throw; else - ThrowEventSourceException(ex); + ThrowEventSourceException(m_eventData[eventId].Name, ex); } } } @@ -2027,11 +2072,71 @@ namespace System.Diagnostics.Tracing return eventData; } + /// + /// We expect that the arguments to the Event method and the arguments to WriteEvent match. This function + /// checks that they in fact match and logs a warning to the debugger if they don't. + /// + /// + /// + private void LogEventArgsMismatches(ParameterInfo[] infos, object[] args) + { + // It would be nice to have this on PCL builds, but it would be pointless since there isn't support for + // writing to the debugger log on PCL. + bool typesMatch = args.Length == infos.Length; + + int i = 0; + while (typesMatch && i < args.Length) + { + Type pType = infos[i].ParameterType; + + // Checking to see if the Parameter types (from the Event method) match the supplied argument types. + // Fail if one of two things hold : either the argument type is not equal to the parameter type, or the + // argument is null and the parameter type is non-nullable. + if ((args[i] != null && (args[i].GetType() != pType)) + || (args[i] == null && (!(pType.IsGenericType && pType.GetGenericTypeDefinition() == typeof(Nullable<>)))) + ) + { + typesMatch = false; + break; + } + + ++i; + } + + if (!typesMatch) + { + System.Diagnostics.Debugger.Log(0, null, Environment.GetResourceString("EventSource_VarArgsParameterMismatch") + "\r\n"); + } + } + + private int GetParamLengthIncludingByteArray(ParameterInfo[] parameters) + { + int sum = 0; + foreach(ParameterInfo info in parameters) + { + if(info.ParameterType == typeof(byte[])) + { + sum += 2; + } + else + { + sum++; + } + } + + return sum; + } + [SecurityCritical] unsafe private void WriteToAllListeners(int eventId, Guid* childActivityID, int eventDataCount, EventSource.EventData* data) { + // We represent a byte[] as a integer denoting the length and then a blob of bytes in the data pointer. This causes a spurious + // warning because eventDataCount is off by one for the byte[] case since a byte[] has 2 items associated it. So we want to check + // that the number of parameters is correct against the byte[] case, but also we the args array would be one too long if + // we just used the modifiedParamCount here -- so we need both. int paramCount = m_eventData[eventId].Parameters.Length; - if (eventDataCount != paramCount) + int modifiedParamCount = GetParamLengthIncludingByteArray(m_eventData[eventId].Parameters); + if (eventDataCount != modifiedParamCount) { ReportOutOfBandMessage(Environment.GetResourceString("EventSource_EventParametersMismatch", eventId, eventDataCount, paramCount), true); paramCount = Math.Min(paramCount, eventDataCount); @@ -2057,11 +2162,11 @@ namespace System.Diagnostics.Tracing eventCallbackArgs.Message = m_eventData[eventId].Message; eventCallbackArgs.Payload = new ReadOnlyCollection(args); - DisptachToAllListeners(eventId, childActivityID, eventCallbackArgs); + DispatchToAllListeners(eventId, childActivityID, eventCallbackArgs); } [SecurityCritical] - private unsafe void DisptachToAllListeners(int eventId, Guid* childActivityID, EventWrittenEventArgs eventCallbackArgs) + private unsafe void DispatchToAllListeners(int eventId, Guid* childActivityID, EventWrittenEventArgs eventCallbackArgs) { Exception lastThrownException = null; for (EventDispatcher dispatcher = m_Dispatchers; dispatcher != null; dispatcher = dispatcher.m_Next) @@ -2304,9 +2409,9 @@ namespace System.Diagnostics.Tracing } [System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)] - private void ThrowEventSourceException(Exception innerEx = null) + private void ThrowEventSourceException(string eventName, Exception innerEx = null) { - // If we fail during ouf of band logging we may end up trying + // If we fail during out of band logging we may end up trying // to throw another EventSourceException, thus hitting a StackOverflowException. // Avoid StackOverflow by making sure we do not recursively call this method. if (m_EventSourceExceptionRecurenceCount > 0) @@ -2315,30 +2420,36 @@ namespace System.Diagnostics.Tracing { m_EventSourceExceptionRecurenceCount++; + string errorPrefix = "EventSourceException"; + if(eventName != null) + { + errorPrefix += " while processing event \"" + eventName + "\""; + } + // switch (EventProvider.GetLastWriteEventError()) { case EventProvider.WriteEventErrorCode.EventTooBig: - ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_EventTooBig"), true); + ReportOutOfBandMessage(errorPrefix + ": " + Environment.GetResourceString("EventSource_EventTooBig"), true); if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_EventTooBig"), innerEx); break; case EventProvider.WriteEventErrorCode.NoFreeBuffers: - ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_NoFreeBuffers"), true); + ReportOutOfBandMessage(errorPrefix + ": " + Environment.GetResourceString("EventSource_NoFreeBuffers"), true); if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_NoFreeBuffers"), innerEx); break; case EventProvider.WriteEventErrorCode.NullInput: - ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_NullInput"), true); + ReportOutOfBandMessage(errorPrefix + ": " + Environment.GetResourceString("EventSource_NullInput"), true); if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_NullInput"), innerEx); break; case EventProvider.WriteEventErrorCode.TooManyArgs: - ReportOutOfBandMessage("EventSourceException: " + Environment.GetResourceString("EventSource_TooManyArgs"), true); + ReportOutOfBandMessage(errorPrefix + ": " + Environment.GetResourceString("EventSource_TooManyArgs"), true); if (ThrowOnEventWriteErrors) throw new EventSourceException(Environment.GetResourceString("EventSource_TooManyArgs"), innerEx); break; default: if (innerEx != null) - ReportOutOfBandMessage("EventSourceException: " + innerEx.GetType() + ":" + innerEx.Message, true); + ReportOutOfBandMessage(errorPrefix + ": " + innerEx.GetType() + ":" + innerEx.Message, true); else - ReportOutOfBandMessage("EventSourceException", true); + ReportOutOfBandMessage(errorPrefix, true); if (ThrowOnEventWriteErrors) throw new EventSourceException(innerEx); break; } @@ -2349,18 +2460,20 @@ namespace System.Diagnostics.Tracing } } - private void ValidateEventOpcodeForTransfer(ref EventMetadata eventData) + private void ValidateEventOpcodeForTransfer(ref EventMetadata eventData, string eventName) { if ((EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Send && - (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Receive) + (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Receive && + (EventOpcode)eventData.Descriptor.Opcode != EventOpcode.Start) + { - ThrowEventSourceException(); + ThrowEventSourceException(eventName); } } internal static EventOpcode GetOpcodeWithDefault(EventOpcode opcode, string eventName) { - if (opcode == EventOpcode.Info) + if (opcode == EventOpcode.Info && eventName != null) { if (eventName.EndsWith(s_ActivityStartSuffix)) { @@ -2408,6 +2521,8 @@ namespace System.Diagnostics.Tracing public EventTags Tags; public bool EnabledForAnyListener; // true if any dispatcher has this event turned on public bool EnabledForETW; // is this event on for the OS ETW data dispatcher? + + public bool HasRelatedActivityID; // Set if the event method's first parameter is a Guid named 'relatedActivityId' #if !FEATURE_ACTIVITYSAMPLING #pragma warning disable 0649 #endif @@ -2457,8 +2572,13 @@ namespace System.Diagnostics.Tracing var commandArgs = new EventCommandEventArgs(command, commandArguments, this, listener, perEventSourceSessionId, etwSessionId, enable, level, matchAnyKeyword); lock (EventListener.EventListenersLock) { - if (m_completelyInited) // We are fully initialized, do the command + if (m_completelyInited) + { + // After the first command arrive after construction, we are ready to get rid of the deferred commands + this.m_deferredCommands = null; + // We are fully initialized, do the command DoCommand(commandArgs); + } else { // We can't do the command, simply remember it and we do it when we are fully constructed. @@ -2603,9 +2723,12 @@ namespace System.Diagnostics.Tracing Contract.Assert(m_eventData != null); m_eventSourceEnabled = true; } - + this.OnEventCommand(commandArgs); - + var eventCommandCallback = this.m_eventCommandExecuted; + if (eventCommandCallback != null) + eventCommandCallback(this, commandArgs); + #if FEATURE_ACTIVITYSAMPLING if (commandArgs.listener == null && !bSessionEnable && commandArgs.perEventSourceSessionId != -1) { @@ -2688,8 +2811,11 @@ namespace System.Diagnostics.Tracing // Contract.Assert(enable == true); // Contract.Assert(level == EventLevel.LogAlways); // Contract.Assert(matchAnyKeyword == EventKeywords.None); - + this.OnEventCommand(commandArgs); + var eventCommandCallback = m_eventCommandExecuted; + if (eventCommandCallback != null) + eventCommandCallback(this, commandArgs); } #if FEATURE_ACTIVITYSAMPLING @@ -2976,7 +3102,7 @@ namespace System.Diagnostics.Tracing } success = false; if (ThrowOnEventWriteErrors) - ThrowEventSourceException(); + ThrowEventSourceException("SendManifest"); break; } } @@ -3213,7 +3339,7 @@ namespace System.Diagnostics.Tracing manifest.AddKeyword("Session0", (long)0x8000 << 32); } - if (eventSourceType.Name != "EventSource") + if (eventSourceType != typeof(EventSource)) { for (int i = 0; i < methods.Length; i++) { @@ -3222,6 +3348,20 @@ namespace System.Diagnostics.Tracing // Get the EventDescriptor (from the Custom attributes) EventAttribute eventAttribute = (EventAttribute)GetCustomAttributeHelper(method, typeof(EventAttribute), flags); + + // Visual Studio online bug #222067 - we can't add a dependency in System.Web on EventSource features that + // didn't exist in 4.5. We have to manually set the disable flag here since the ActivityOptions + // falls in to that category. + // + // The check for <= 3 is to only disable Activity tracking for the RequestStarted and RequestCompleted + // events. + if (eventAttribute != null + && source != null + && eventAttribute.EventId <= 3 + && source.Guid.Equals(AspNetEventSourceGuid)) + { + eventAttribute.ActivityOptions |= EventActivityOptions.Disable; + } // Compat: until v4.5.1 we ignored any non-void returning methods as well as virtual methods for // the only reason of limiting the number of methods considered to be events. This broke a common @@ -3273,15 +3413,17 @@ namespace System.Diagnostics.Tracing eventId++; string eventName = method.Name; - if (!eventAttribute.IsOpcodeSet) + if (eventAttribute.Opcode == EventOpcode.Info) // We are still using the default opcode. { // By default pick a task ID derived from the EventID, starting with the highest task number and working back bool noTask = (eventAttribute.Task == EventTask.None); - if (eventAttribute.Task == EventTask.None) + if (noTask) eventAttribute.Task = (EventTask)(0xFFFE - eventAttribute.EventId); - // pick a default opcode (either Info or start or stop if the name ends with that suffix. - eventAttribute.Opcode = GetOpcodeWithDefault(EventOpcode.Info, eventName); + // Unless we explicitly set the opcode to Info (to override the auto-generate of Start or Stop opcodes, + // pick a default opcode based on the event name (either Info or start or stop if the name ends with that suffix). + if (!eventAttribute.IsOpcodeSet) + eventAttribute.Opcode = GetOpcodeWithDefault(EventOpcode.Info, eventName); // Make the stop opcode have the same task as the start opcode. if (noTask) @@ -3299,7 +3441,7 @@ namespace System.Diagnostics.Tracing } else if (eventAttribute.Opcode == EventOpcode.Stop) { - // Find the start associated with this stop event. We require start to be immediately before the stop + // Find the start associated with this stop event. We requre start to be immediately before the stop int startEventId = eventAttribute.EventId - 1; if (eventData != null && startEventId < eventData.Length) { @@ -3325,7 +3467,7 @@ namespace System.Diagnostics.Tracing } } - RemoveFirstArgIfRelatedActivityId(ref args); + bool hasRelatedActivityID = RemoveFirstArgIfRelatedActivityId(ref args); if (!(source != null && source.SelfDescribingEvents)) { manifest.StartEvent(eventName, eventAttribute); @@ -3339,7 +3481,7 @@ namespace System.Diagnostics.Tracing if (source != null || (flags & EventManifestOptions.Strict) != 0) { // Do checking for user errors (optional, but not a big deal so we do it). - DebugCheckEvent(ref eventsByName, eventData, method, eventAttribute, manifest); + DebugCheckEvent(ref eventsByName, eventData, method, eventAttribute, manifest, flags); #if FEATURE_MANAGED_ETW_CHANNELS // add the channel keyword for Event Viewer channel based filters. This is added for creating the EventDescriptors only @@ -3357,7 +3499,7 @@ namespace System.Diagnostics.Tracing // overwrite inline message with the localized message if (msg != null) eventAttribute.Message = msg; - AddEventDescriptor(ref eventData, eventName, eventAttribute, args); + AddEventDescriptor(ref eventData, eventName, eventAttribute, args, hasRelatedActivityID); } } } @@ -3379,7 +3521,7 @@ namespace System.Diagnostics.Tracing { bNeedsManifest = (flags & EventManifestOptions.OnlyIfNeededForRegistration) == 0 #if FEATURE_MANAGED_ETW_CHANNELS - || manifest.GetChannelData().Length > 0 + || manifest.GetChannelData().Length > 0 #endif ; @@ -3422,7 +3564,7 @@ namespace System.Diagnostics.Tracing return bNeedsManifest ? res : null; } - private static void RemoveFirstArgIfRelatedActivityId(ref ParameterInfo[] args) + private static bool RemoveFirstArgIfRelatedActivityId(ref ParameterInfo[] args) { // If the first parameter is (case insensitive) 'relatedActivityId' then skip it. if (args.Length > 0 && args[0].ParameterType == typeof(Guid) && @@ -3431,7 +3573,11 @@ namespace System.Diagnostics.Tracing var newargs = new ParameterInfo[args.Length - 1]; Array.Copy(args, 1, newargs, 0, args.Length - 1); args = newargs; + + return true; } + + return false; } // adds a enumeration (keyword, opcode, task or channel) represented by 'staticField' @@ -3475,7 +3621,8 @@ namespace System.Diagnostics.Tracing // with the code:EventAttribute 'eventAttribute'. resourceManger may be null in which case we populate it // it is populated if we need to look up message resources private static void AddEventDescriptor(ref EventMetadata[] eventData, string eventName, - EventAttribute eventAttribute, ParameterInfo[] eventParameters) + EventAttribute eventAttribute, ParameterInfo[] eventParameters, + bool hasRelatedActivityID) { if (eventData == null || eventData.Length <= eventAttribute.EventId) { @@ -3488,7 +3635,7 @@ namespace System.Diagnostics.Tracing eventAttribute.EventId, eventAttribute.Version, #if FEATURE_MANAGED_ETW_CHANNELS - (byte)eventAttribute.Channel, + (byte)eventAttribute.Channel, #else (byte)0, #endif @@ -3502,6 +3649,7 @@ namespace System.Diagnostics.Tracing eventData[eventAttribute.EventId].Parameters = eventParameters; eventData[eventAttribute.EventId].Message = eventAttribute.Message; eventData[eventAttribute.EventId].ActivityOptions = eventAttribute.ActivityOptions; + eventData[eventAttribute.EventId].HasRelatedActivityID = hasRelatedActivityID; } // Helper used by code:CreateManifestAndDescriptors that trims the m_eventData array to the correct @@ -3541,7 +3689,7 @@ namespace System.Diagnostics.Tracing // index for two distinct events etc. Throws exceptions when it finds something wrong. private static void DebugCheckEvent(ref Dictionary eventsByName, EventMetadata[] eventData, MethodInfo method, EventAttribute eventAttribute, - ManifestBuilder manifest) + ManifestBuilder manifest, EventManifestOptions options) { int evtId = eventAttribute.EventId; string evtName = method.Name; @@ -3568,14 +3716,30 @@ namespace System.Diagnostics.Tracing { manifest.ManifestError(Environment.GetResourceString("EventSource_TaskOpcodePairReused", evtName, evtId, eventData[idx].Name, idx)); + + // If we are not strict stop on first error. We have had problems with really large providers taking forever. because of many errors. + if ((options & EventManifestOptions.Strict) == 0) + break; } } // for non-default event opcodes the user must define a task! - if (eventAttribute.Opcode != EventOpcode.Info && - (eventAttribute.Task == EventTask.None || eventAttribute.Task == (EventTask)(0xFFFE - evtId))) + if (eventAttribute.Opcode != EventOpcode.Info) { - manifest.ManifestError(Environment.GetResourceString("EventSource_EventMustHaveTaskIfNonDefaultOpcode", evtName, evtId)); + bool failure = false; + if (eventAttribute.Task == EventTask.None) + failure = true; + else + { + // If you have the auto-assigned Task, then you did not explicitly set one. + // This is OK for Start events because we have special logic to assign the task to a prefix derived from the event name + // But all other cases we want to catch the omission. + var autoAssignedTask = (EventTask)(0xFFFE - evtId); + if ((eventAttribute.Opcode != EventOpcode.Start && eventAttribute.Opcode != EventOpcode.Stop) && eventAttribute.Task == autoAssignedTask) + failure = true; + } + if (failure) + manifest.ManifestError(Environment.GetResourceString("EventSource_EventMustHaveTaskIfNonDefaultOpcode", evtName, evtId)); } // If we ever want to enforce the rule: MethodName = TaskName + OpcodeName here's how: @@ -3591,7 +3755,7 @@ namespace System.Diagnostics.Tracing eventsByName = new Dictionary(); if (eventsByName.ContainsKey(evtName)) - manifest.ManifestError(Environment.GetResourceString("EventSource_EventNameReused", evtName)); + manifest.ManifestError(Environment.GetResourceString("EventSource_EventNameReused", evtName), true); eventsByName[evtName] = evtName; } @@ -3759,13 +3923,13 @@ namespace System.Diagnostics.Tracing #endif // Send it to all listeners. - if (m_outOfBandMessageCount < 254) // Note this is only if size byte + if (m_outOfBandMessageCount < 16-1) // Note this is only if size byte m_outOfBandMessageCount++; else { - if (m_outOfBandMessageCount == 255) + if (m_outOfBandMessageCount == 16) return; - m_outOfBandMessageCount = 255; // Mark that we hit the limit. Notify them that this is the case. + m_outOfBandMessageCount = 16; // Mark that we hit the limit. Notify them that this is the case. msg = "Reached message limit. End of EventSource error messages."; } @@ -3870,6 +4034,8 @@ namespace System.Diagnostics.Tracing internal volatile EventMetadata[] m_eventData; // None per-event data private volatile byte[] m_rawManifest; // Bytes to send out representing the event schema + private EventHandler m_eventCommandExecuted; + private EventSourceSettings m_config; // configuration information // Enabling bits @@ -3919,6 +4085,10 @@ namespace System.Diagnostics.Tracing 0x87, 0xF8, 0x1A, 0x15, 0xBF, 0xC1, 0x30, 0xFB, }; + // Visual Studio Online 222067 - This is only needed for a compatibility hack. We need to check to see + // if an EventSource is the AspNetEventSource to override the ActivityTracking for it. + private static readonly Guid AspNetEventSourceGuid = new Guid("ee799f41-cfa5-550b-bf2c-344747c1c668"); + #endregion } @@ -3990,52 +4160,60 @@ namespace System.Diagnostics.Tracing /// created. /// /// - public abstract class EventListener : IDisposable + public class EventListener : IDisposable { + private static readonly object s_EventSourceCreatedLock = new object(); + + private event EventHandler _EventSourceCreated; + /// - /// Create a new EventListener in which all events start off turned off (use EnableEvents to turn - /// them on). + /// This event is raised whenever a new eventSource is 'attached' to the dispatcher. + /// This can happen for all existing EventSources when the EventListener is created + /// as well as for any EventSources that come into existence after the EventListener + /// has been created. + /// + /// These 'catch up' events are called during the construction of the EventListener. + /// Subclasses need to be prepared for that. + /// + /// In a multi-threaded environment, it is possible that 'EventSourceEventWrittenCallback' + /// events for a particular eventSource to occur BEFORE the EventSourceCreatedCallback is issued. /// - protected EventListener() - { - lock (EventListenersLock) + public event EventHandler EventSourceCreated + { + add { - // Disallow creating EventListener reentrancy. - if (s_CreatingListener) - throw new InvalidOperationException(Environment.GetResourceString("EventSource_ListenerCreatedInsideCallback")); - - try + lock (s_EventSourceCreatedLock) { - s_CreatingListener = true; - - // Add to list of listeners in the system, do this BEFORE firing the 'OnEventSourceCreated' so that - // Those added sources see this listener. - this.m_Next = s_Listeners; - s_Listeners = this; - - // Find all existing eventSources call OnEventSourceCreated to 'catchup' - // Note that we DO have reentrancy here because 'AddListener' calls out to user code (via OnEventSourceCreated callback) - // We tolerate this by iterating over a copy of the list here. New event sources will take care of adding listeners themselves - // EventSources are not guaranteed to be added at the end of the s_EventSource list -- We re-use slots when a new source - // is created. - WeakReference[] eventSourcesSnapshot = s_EventSources.ToArray(); - - for (int i = 0; i < eventSourcesSnapshot.Length; i++) - { - WeakReference eventSourceRef = eventSourcesSnapshot[i]; - EventSource eventSource = eventSourceRef.Target as EventSource; - if (eventSource != null) - eventSource.AddListener(this); // This will cause the OnEventSourceCreated callback to fire. - } + CallBackForExistingEventSources(false, value); - Validate(); + this._EventSourceCreated = (EventHandler)Delegate.Combine(_EventSourceCreated, value); } - finally + } + remove + { + lock (s_EventSourceCreatedLock) { - s_CreatingListener = false; + this._EventSourceCreated = (EventHandler)Delegate.Remove(_EventSourceCreated, value); } } } + + /// + /// This event is raised whenever an event has been written by a EventSource for which + /// the EventListener has enabled events. + /// + public event EventHandler EventWritten; + + /// + /// Create a new EventListener in which all events start off turned off (use EnableEvents to turn + /// them on). + /// + public EventListener() + { + // This will cause the OnEventSourceCreated callback to fire. + CallBackForExistingEventSources(true, (obj, args) => args.EventSource.AddListener(this) ); + } + /// /// Dispose should be called when the EventListener no longer desires 'OnEvent*' callbacks. Because /// there is an internal list of strong references to all EventListeners, calling 'Dispose' directly @@ -4164,12 +4342,31 @@ namespace System.Diagnostics.Tracing /// for a particular eventSource to occur BEFORE the OnEventSourceCreated is issued. /// /// - internal protected virtual void OnEventSourceCreated(EventSource eventSource) { } + internal protected virtual void OnEventSourceCreated(EventSource eventSource) + { + EventHandler callBack = this._EventSourceCreated; + if(callBack != null) + { + EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs(); + args.EventSource = eventSource; + callBack(this, args); + } + } + /// /// This method is called whenever an event has been written by a EventSource for which /// the EventListener has enabled events. /// - internal protected abstract void OnEventWritten(EventWrittenEventArgs eventData); + /// + internal protected virtual void OnEventWritten(EventWrittenEventArgs eventData) + { + EventHandler callBack = this.EventWritten; + if (callBack != null) + { + callBack(this, eventData); + } + } + /// /// EventSourceIndex is small non-negative integer (suitable for indexing in an array) /// identifying EventSource. It is unique per-appdomain. Some EventListeners might find @@ -4251,11 +4448,14 @@ namespace System.Diagnostics.Tracing // See bug 724140 for more private static void DisposeOnShutdown(object sender, EventArgs e) { - foreach (var esRef in s_EventSources) + lock(EventListenersLock) { - EventSource es = esRef.Target as EventSource; - if (es != null) - es.Dispose(); + foreach (var esRef in s_EventSources) + { + EventSource es = esRef.Target as EventSource; + if (es != null) + es.Dispose(); + } } } @@ -4267,6 +4467,9 @@ namespace System.Diagnostics.Tracing /// private static void RemoveReferencesToListenerInEventSources(EventListener listenerToRemove) { +#if !ES_BUILD_STANDALONE + Contract.Assert(Monitor.IsEntered(EventListener.EventListenersLock)); +#endif // Foreach existing EventSource in the appdomain foreach (WeakReference eventSourceRef in s_EventSources) { @@ -4365,6 +4568,55 @@ namespace System.Diagnostics.Tracing return s_EventSources; } } + + private void CallBackForExistingEventSources(bool addToListenersList, EventHandler callback) + { + lock (EventListenersLock) + { + // Disallow creating EventListener reentrancy. + if (s_CreatingListener) + throw new InvalidOperationException(Environment.GetResourceString("EventSource_ListenerCreatedInsideCallback")); + + try + { + s_CreatingListener = true; + + if (addToListenersList) + { + // Add to list of listeners in the system, do this BEFORE firing the 'OnEventSourceCreated' so that + // Those added sources see this listener. + this.m_Next = s_Listeners; + s_Listeners = this; + } + + // Find all existing eventSources call OnEventSourceCreated to 'catchup' + // Note that we DO have reentrancy here because 'AddListener' calls out to user code (via OnEventSourceCreated callback) + // We tolerate this by iterating over a copy of the list here. New event sources will take care of adding listeners themselves + // EventSources are not guaranteed to be added at the end of the s_EventSource list -- We re-use slots when a new source + // is created. + WeakReference[] eventSourcesSnapshot = s_EventSources.ToArray(); + + for (int i = 0; i < eventSourcesSnapshot.Length; i++) + { + WeakReference eventSourceRef = eventSourcesSnapshot[i]; + EventSource eventSource = eventSourceRef.Target as EventSource; + if (eventSource != null) + { + EventSourceCreatedEventArgs args = new EventSourceCreatedEventArgs(); + args.EventSource = eventSource; + callback(this, args); + } + } + + Validate(); + } + finally + { + s_CreatingListener = false; + } + } + + } // Instance fields internal volatile EventListener m_Next; // These form a linked list in s_Listeners @@ -4469,6 +4721,21 @@ namespace System.Diagnostics.Tracing #endregion } + /// + /// EventSourceCreatedEventArgs is passed to + /// + public class EventSourceCreatedEventArgs : EventArgs + { + /// + /// The EventSource that is attaching to the listener. + /// + public EventSource EventSource + { + get; + internal set; + } + } + /// /// EventWrittenEventArgs is passed to the user-provided override for /// when an event is fired. @@ -5291,7 +5558,7 @@ namespace System.Diagnostics.Tracing } } - #region private + #region private /// /// Creates a new ActivityFilter that is triggered by 'eventId' from 'source' ever @@ -5460,7 +5727,7 @@ namespace System.Diagnostics.Tracing ActivityFilter m_next; // We create a linked list of these Action m_myActivityDelegate; - #endregion + #endregion }; @@ -6212,8 +6479,8 @@ namespace System.Diagnostics.Tracing cultures.Add(CultureInfo.CurrentUICulture); } #if ES_BUILD_STANDALONE - var sortedStrings = new List(stringTab.Keys); - sortedStrings.Sort(); + var sortedStrings = new List(stringTab.Keys); + sortedStrings.Sort(); #else // DD 947936 var sortedStrings = new string[stringTab.Keys.Count]; @@ -6264,10 +6531,13 @@ namespace System.Diagnostics.Tracing stringBuilder.Append(" message=\"$(string.").Append(key).Append(")\""); string prevValue; - if (stringTab.TryGetValue(key, out prevValue)) + if (stringTab.TryGetValue(key, out prevValue) && !prevValue.Equals(value)) + { ManifestError(Environment.GetResourceString("EventSource_DuplicateStringKey", key), true); - else - stringTab.Add(key, value); + return; + } + + stringTab[key] = value; } internal string GetLocalizedMessage(string key, CultureInfo ci, bool etwFormat) { @@ -6331,7 +6601,7 @@ namespace System.Diagnostics.Tracing // rest get names Channel. This allows users to modify the Manifest if they want more advanced features. if (channelTab == null) channelTab = new Dictionary(4); - + string channelName = channel.ToString(); // For well know channels this is a nice name, otherwise a number if (EventChannel.Debug < channel) channelName = "Channel" + channelName; // Add a 'Channel' prefix for numbers. diff --git a/mcs/class/referencesource/mscorlib/system/environment.cs b/mcs/class/referencesource/mscorlib/system/environment.cs index 5e9b986bd7b..d5feefac388 100644 --- a/mcs/class/referencesource/mscorlib/system/environment.cs +++ b/mcs/class/referencesource/mscorlib/system/environment.cs @@ -416,7 +416,7 @@ namespace System { #if !FEATURE_CORECLR // Do security check - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, path).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, path); #endif return path; diff --git a/mcs/class/referencesource/mscorlib/system/globalization/taiwancalendar.cs b/mcs/class/referencesource/mscorlib/system/globalization/taiwancalendar.cs index 45b0322f8ce..e2f2f3055e5 100644 --- a/mcs/class/referencesource/mscorlib/system/globalization/taiwancalendar.cs +++ b/mcs/class/referencesource/mscorlib/system/globalization/taiwancalendar.cs @@ -21,7 +21,7 @@ namespace System.Globalization { ** Gregorian 1912/01/01 9999/12/31 ** Taiwan 01/01/01 8088/12/31 ============================================================================*/ - + [System.Runtime.InteropServices.ComVisible(true)] [Serializable] public class TaiwanCalendar: Calendar { diff --git a/mcs/class/referencesource/mscorlib/system/io/__error.cs b/mcs/class/referencesource/mscorlib/system/io/__error.cs index e318533937a..a7a35c642dd 100644 --- a/mcs/class/referencesource/mscorlib/system/io/__error.cs +++ b/mcs/class/referencesource/mscorlib/system/io/__error.cs @@ -79,29 +79,21 @@ namespace System.IO { [System.Security.SecurityCritical] // auto-generated internal static String GetDisplayablePath(String path, bool isInvalidPath) { - if (String.IsNullOrEmpty(path)) return String.Empty; - // Is it a fully qualified path? - bool isFullyQualified = false; if (path.Length < 2) return path; - if (Path.IsDirectorySeparator(path[0]) && Path.IsDirectorySeparator(path[1])) - isFullyQualified = true; - else if (path[1] == Path.VolumeSeparatorChar) { - isFullyQualified = true; - } - if (!isFullyQualified && !isInvalidPath) + // Return the path as is if we're relative (not fully qualified) and not a bad path + if (PathInternal.IsPartiallyQualified(path) && !isInvalidPath) return path; -#if FEATURE_MONO_CAS bool safeToReturn = false; try { if (!isInvalidPath) { -#if !FEATURE_CORECLR - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { path }, false, false).Demand(); +#if !FEATURE_CORECLR && FEATURE_MONO_CAS + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, path, false, false); #endif safeToReturn = true; } @@ -117,9 +109,7 @@ namespace System.IO { // from Security.Util.StringExpressionSet.CanonicalizePath when ':' is found in the path // beyond string index position 1. } -#else - bool safeToReturn = !isInvalidPath; -#endif // FEATURE_MONO_CAS + if (!safeToReturn) { if (Path.IsDirectorySeparator(path[path.Length - 1])) path = Environment.GetResourceString("IO.IO_NoPermissionToDirectoryName"); diff --git a/mcs/class/referencesource/mscorlib/system/io/binaryreader.cs b/mcs/class/referencesource/mscorlib/system/io/binaryreader.cs index 409b35c3772..33575892786 100644 --- a/mcs/class/referencesource/mscorlib/system/io/binaryreader.cs +++ b/mcs/class/referencesource/mscorlib/system/io/binaryreader.cs @@ -382,10 +382,23 @@ namespace System.IO { } Contract.Assert(byteBuffer != null, "expected byteBuffer to be non-null"); - unsafe { - fixed (byte* pBytes = byteBuffer) - fixed (char* pChars = buffer) { - charsRead = m_decoder.GetChars(pBytes + position, numBytes, pChars + index, charsRemaining, false); + + checked { + + if (position < 0 || numBytes < 0 || position + numBytes > byteBuffer.Length) { + throw new ArgumentOutOfRangeException("byteCount"); + } + + if (index < 0 || charsRemaining < 0 || index + charsRemaining > buffer.Length) { + throw new ArgumentOutOfRangeException("charsRemaining"); + } + + unsafe { + fixed (byte* pBytes = byteBuffer) { + fixed (char* pChars = buffer) { + charsRead = m_decoder.GetChars(pBytes + position, numBytes, pChars + index, charsRemaining, false); + } + } } } diff --git a/mcs/class/referencesource/mscorlib/system/io/binarywriter.cs b/mcs/class/referencesource/mscorlib/system/io/binarywriter.cs index ad11daa8bdf..c6f81955e43 100644 --- a/mcs/class/referencesource/mscorlib/system/io/binarywriter.cs +++ b/mcs/class/referencesource/mscorlib/system/io/binarywriter.cs @@ -196,7 +196,7 @@ namespace System.IO { Contract.Assert(_encoding.GetMaxByteCount(1) <= 16, "_encoding.GetMaxByteCount(1) <= 16)"); int numBytes = 0; fixed(byte * pBytes = _buffer) { - numBytes = _encoder.GetBytes(&ch, 1, pBytes, 16, true); + numBytes = _encoder.GetBytes(&ch, 1, pBytes, _buffer.Length, true); } OutStream.Write(_buffer, 0, numBytes); } @@ -371,10 +371,10 @@ namespace System.IO { if (_largeByteBuffer == null) { _largeByteBuffer = new byte[LargeByteBufferSize]; - _maxChars = LargeByteBufferSize / _encoding.GetMaxByteCount(1); + _maxChars = _largeByteBuffer.Length / _encoding.GetMaxByteCount(1); } - if (len <= LargeByteBufferSize) { + if (len <= _largeByteBuffer.Length) { //Contract.Assert(len == _encoding.GetBytes(chars, 0, chars.Length, _largeByteBuffer, 0), "encoding's GetByteCount & GetBytes gave different answers! encoding type: "+_encoding.GetType().Name); _encoding.GetBytes(value, 0, value.Length, _largeByteBuffer, 0); OutStream.Write(_largeByteBuffer, 0, len); @@ -393,14 +393,21 @@ namespace System.IO { // Figure out how many chars to process this round. int charCount = (numLeft > _maxChars) ? _maxChars : numLeft; int byteLen; - fixed(char* pChars = value) { - fixed(byte* pBytes = _largeByteBuffer) { - byteLen = _encoder.GetBytes(pChars + charStart, charCount, pBytes, LargeByteBufferSize, charCount == numLeft); + + checked { + if (charStart < 0 || charCount < 0 || charStart + charCount > value.Length) { + throw new ArgumentOutOfRangeException("charCount"); + } + + fixed(char* pChars = value) { + fixed(byte* pBytes = _largeByteBuffer) { + byteLen = _encoder.GetBytes(pChars + charStart, charCount, pBytes, _largeByteBuffer.Length, charCount == numLeft); + } } } #if _DEBUG totalBytes += byteLen; - Contract.Assert (totalBytes <= len && byteLen <= LargeByteBufferSize, "BinaryWriter::Write(String) - More bytes encoded than expected!"); + Contract.Assert (totalBytes <= len && byteLen <= _largeByteBuffer.Length, "BinaryWriter::Write(String) - More bytes encoded than expected!"); #endif OutStream.Write(_largeByteBuffer, 0, byteLen); charStart += charCount; diff --git a/mcs/class/referencesource/mscorlib/system/io/directory.cs b/mcs/class/referencesource/mscorlib/system/io/directory.cs index da6f5ab57e4..943e8ff52b9 100644 --- a/mcs/class/referencesource/mscorlib/system/io/directory.cs +++ b/mcs/class/referencesource/mscorlib/system/io/directory.cs @@ -248,17 +248,25 @@ namespace System.IO { int count = stackDir.Count; - if (stackDir.Count != 0) + if (stackDir.Count != 0 +#if FEATURE_CAS_POLICY + // All demands in full trust domains are no-ops, so skip + // + // The full path went through validity checks by being passed through FileIOPermissions already. + // As a sub string of the full path can't fail the checks if the full path passes. + && !CodeAccessSecurityEngine.QuickCheckForAllDemands() +#endif + ) { - String [] securityList = new String[stackDir.Count]; + String[] securityList = new String[stackDir.Count]; stackDir.CopyTo(securityList, 0); for (int j = 0 ; j < securityList.Length; j++) securityList[j] += "\\."; // leaf will never have a slash at the end // Security check for all directories not present only. -#if !FEATURE_PAL && FEATURE_MACL +#if !FEATURE_PAL && FEATURE_MACL AccessControlActions control = (dirSecurity == null) ? AccessControlActions.None : AccessControlActions.Change; - new FileIOPermission(FileIOPermissionAccess.Write, control, securityList, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, control, securityList, false, false); #else #if FEATURE_CORECLR if (checkHost) @@ -270,7 +278,7 @@ namespace System.IO { } } #else - new FileIOPermission(FileIOPermissionAccess.Write, securityList, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, securityList, false, false ); #endif #endif //!FEATURE_PAL && FEATURE_MACL } @@ -298,8 +306,9 @@ namespace System.IO { while (stackDir.Count > 0) { String name = stackDir[stackDir.Count - 1]; stackDir.RemoveAt(stackDir.Count - 1); - if (name.Length >= Path.MAX_DIRECTORY_PATH) + if (PathInternal.IsDirectoryTooLong(name)) throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); + r = Win32Native.CreateDirectory(name, secAttrs); if (!r && (firstError == 0)) { int currentError = Marshal.GetLastWin32Error(); @@ -326,7 +335,7 @@ namespace System.IO { state.EnsureState(); } #else - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, GetDemandDir(name, true)).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, GetDemandDir(name, true)); #endif // FEATURE_CORECLR errorString = name; } @@ -1085,49 +1094,88 @@ namespace System.IO { return InternalGetCurrentDirectory(false); } + [System.Security.SecuritySafeCritical] + [ResourceExposure(ResourceScope.Machine)] + [ResourceConsumption(ResourceScope.Machine)] + private static string InternalGetCurrentDirectory(bool checkHost) + { + string currentDirectory = AppContextSwitches.UseLegacyPathHandling ? LegacyGetCurrentDirectory() : NewGetCurrentDirectory(); + string demandPath = GetDemandDir(currentDirectory, true); + +#if FEATURE_CORECLR + if (checkHost) + { + FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPath); + state.EnsureState(); + } +#else + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPath, false, false); +#endif + return currentDirectory; + } + [System.Security.SecurityCritical] [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - private static String InternalGetCurrentDirectory(bool checkHost) + private static string LegacyGetCurrentDirectory() { - StringBuilder sb = StringBuilderCache.Acquire(Path.MAX_PATH + 1); + StringBuilder sb = StringBuilderCache.Acquire(PathInternal.MaxShortPath + 1); if (Win32Native.GetCurrentDirectory(sb.Capacity, sb) == 0) __Error.WinIOError(); - String currentDirectory = sb.ToString(); + string currentDirectory = sb.ToString(); // Note that if we have somehow put our command prompt into short // file name mode (ie, by running edlin or a DOS grep, etc), then // this will return a short file name. - if (currentDirectory.IndexOf('~') >= 0) { + if (currentDirectory.IndexOf('~') >= 0) + { int r = Win32Native.GetLongPathName(currentDirectory, sb, sb.Capacity); - if (r == 0 || r >= Path.MAX_PATH) { + if (r == 0 || r >= PathInternal.MaxShortPath) + { int errorCode = Marshal.GetLastWin32Error(); - if (r >= Path.MAX_PATH) + if (r >= PathInternal.MaxShortPath) errorCode = Win32Native.ERROR_FILENAME_EXCED_RANGE; if (errorCode != Win32Native.ERROR_FILE_NOT_FOUND && errorCode != Win32Native.ERROR_PATH_NOT_FOUND && errorCode != Win32Native.ERROR_INVALID_FUNCTION && // by design - enough said. errorCode != Win32Native.ERROR_ACCESS_DENIED) - __Error.WinIOError(errorCode, String.Empty); + __Error.WinIOError(errorCode, string.Empty); } currentDirectory = sb.ToString(); } StringBuilderCache.Release(sb); - String demandPath = GetDemandDir(currentDirectory, true); + return currentDirectory; + } - -#if FEATURE_CORECLR - if (checkHost) + [System.Security.SecurityCritical] + [ResourceExposure(ResourceScope.Machine)] + [ResourceConsumption(ResourceScope.Machine)] + private static string NewGetCurrentDirectory() + { + using (StringBuffer buffer = new StringBuffer(PathInternal.MaxShortPath)) { - FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPath); - state.EnsureState(); + uint result = 0; + while ((result = Win32Native.GetCurrentDirectoryW(buffer.CharCapacity, buffer.GetHandle())) > buffer.CharCapacity) + { + // Reported size is greater than the buffer size. Increase the capacity. + // The size returned includes the null only if more space is needed (this case). + buffer.EnsureCharCapacity(result); + } + + if (result == 0) + { + __Error.WinIOError(); + } + + buffer.Length = result; + if (buffer.Contains('~')) + { + return LongPathHelper.GetLongPathName(buffer); + } + + return buffer.ToString(); } -#else - new FileIOPermission( FileIOPermissionAccess.PathDiscovery, new String[] { demandPath }, false, false ).Demand(); -#endif - return currentDirectory; } - #if FEATURE_CORECLR [System.Security.SecurityCritical] // auto-generated #else @@ -1136,15 +1184,16 @@ namespace System.IO { [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] public static void SetCurrentDirectory(String path) - { + { if (path==null) throw new ArgumentNullException("value"); if (path.Length==0) throw new ArgumentException(Environment.GetResourceString("Argument_PathEmpty")); Contract.EndContractBlock(); - if (path.Length >= Path.MAX_PATH) + + if (PathInternal.IsPathTooLong(path)) throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - + // This will have some large effects on the rest of the runtime // and other appdomains in this process. Demand unmanaged code. #pragma warning disable 618 @@ -1174,19 +1223,19 @@ namespace System.IO { [System.Security.SecurityCritical] [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - internal static void UnsafeMove(String sourceDirName,String destDirName) { + internal static void UnsafeMove(String sourceDirName, String destDirName) { InternalMove(sourceDirName, destDirName, false); } [System.Security.SecurityCritical] [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - private static void InternalMove(String sourceDirName,String destDirName,bool checkHost) { + private static void InternalMove(String sourceDirName, String destDirName, bool checkHost) { if (sourceDirName==null) throw new ArgumentNullException("sourceDirName"); if (sourceDirName.Length==0) throw new ArgumentException(Environment.GetResourceString("Argument_EmptyFileName"), "sourceDirName"); - + if (destDirName==null) throw new ArgumentNullException("destDirName"); if (destDirName.Length==0) @@ -1195,16 +1244,16 @@ namespace System.IO { String fullsourceDirName = Path.GetFullPathInternal(sourceDirName); String sourcePath = GetDemandDir(fullsourceDirName, false); - - if (sourcePath.Length >= Path.MAX_DIRECTORY_PATH) + + if (PathInternal.IsDirectoryTooLong(sourcePath)) throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); String fulldestDirName = Path.GetFullPathInternal(destDirName); String destPath = GetDemandDir(fulldestDirName, false); - if (destPath.Length >= Path.MAX_DIRECTORY_PATH) + if (PathInternal.IsDirectoryTooLong(sourcePath)) throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - + #if FEATURE_CORECLR if (checkHost) { FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.Write | FileSecurityStateAccess.Read, sourceDirName, sourcePath); @@ -1288,7 +1337,7 @@ namespace System.IO { } #else // Make sure we have write permission to this directory - new FileIOPermission(FileIOPermissionAccess.Write, new String[] { demandPath }, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, demandPath, false, false); #endif // Do not recursively delete through reparse points. Perhaps in a diff --git a/mcs/class/referencesource/mscorlib/system/io/directoryinfo.cs b/mcs/class/referencesource/mscorlib/system/io/directoryinfo.cs index 5d88346dd31..4a5d733a5fc 100644 --- a/mcs/class/referencesource/mscorlib/system/io/directoryinfo.cs +++ b/mcs/class/referencesource/mscorlib/system/io/directoryinfo.cs @@ -102,7 +102,7 @@ namespace System.IO { state.EnsureState(); } #else - new FileIOPermission(FileIOPermissionAccess.Read, demandDir, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandDir, false, false); #endif FullPath = fullPath; @@ -130,7 +130,7 @@ namespace System.IO { { #if !FEATURE_CORECLR demandDir = new String[] {Directory.GetDemandDir(FullPath, true)}; - new FileIOPermission(FileIOPermissionAccess.Read, demandDir, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandDir, false, false ); #endif DisplayPath = GetDisplayName(OriginalPath, FullPath); } @@ -169,7 +169,7 @@ namespace System.IO { FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.PathDiscovery | FileSecurityStateAccess.Read, String.Empty, dir.demandDir[0]); state.EnsureState(); #else - new FileIOPermission(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, dir.demandDir, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery | FileIOPermissionAccess.Read, dir.demandDir, false, false); #endif return dir; } @@ -234,7 +234,7 @@ namespace System.IO { FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Write, OriginalPath, demandDirForCreation); state.EnsureState(); #else - new FileIOPermission(FileIOPermissionAccess.Write, new String[] { demandDirForCreation }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, demandDirForCreation, false, false); #endif Directory.InternalCreateDirectory(fullPath, path, directorySecurity); @@ -609,7 +609,7 @@ namespace System.IO { FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandPath); sourceState.EnsureState(); #else - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { demandPath }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPath, false, false); #endif return new DirectoryInfo(rootPath); } @@ -629,7 +629,7 @@ namespace System.IO { FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.Write | FileSecurityStateAccess.Read, DisplayPath, Directory.GetDemandDir(FullPath, true)); sourceState.EnsureState(); #else - new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, demandDir, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, demandDir, false, false); #endif String fullDestDirName = Path.GetFullPathInternal(destDirName); String demandPath; @@ -648,9 +648,9 @@ namespace System.IO { FileSecurityState destState = new FileSecurityState(FileSecurityStateAccess.Write, destDirName, demandPath); destState.EnsureState(); #else - new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, demandPath).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, demandPath); #endif - + String fullSourcePath; if (FullPath.EndsWith(Path.DirectorySeparatorChar)) fullSourcePath = FullPath; diff --git a/mcs/class/referencesource/mscorlib/system/io/file.cs b/mcs/class/referencesource/mscorlib/system/io/file.cs index d8a7146e01a..8a36be7ee78 100644 --- a/mcs/class/referencesource/mscorlib/system/io/file.cs +++ b/mcs/class/referencesource/mscorlib/system/io/file.cs @@ -1322,10 +1322,23 @@ namespace System.IO { destState.EnsureState(); backupState.EnsureState(); #else - FileIOPermission perm = new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.Write, new String[] { fullSrcPath, fullDestPath}); - if (destinationBackupFileName != null) - perm.AddPathList(FileIOPermissionAccess.Write, fullBackupPath); - perm.Demand(); +#if FEATURE_CAS_POLICY + // All demands in full trust domains are no-ops, just do additional checks + if (CodeAccessSecurityEngine.QuickCheckForAllDemands()) + { + FileIOPermission.EmulateFileIOPermissionChecks(fullSrcPath); + FileIOPermission.EmulateFileIOPermissionChecks(fullDestPath); + if (fullBackupPath != null) + FileIOPermission.EmulateFileIOPermissionChecks(fullBackupPath); + } + else +#endif + { + FileIOPermission perm = new FileIOPermission(FileIOPermissionAccess.Read | FileIOPermissionAccess.Write, new String[] { fullSrcPath, fullDestPath }); + if (fullBackupPath != null) + perm.AddPathList(FileIOPermissionAccess.Write, fullBackupPath); + perm.Demand(); + } #endif int flags = Win32Native.REPLACEFILE_WRITE_THROUGH; diff --git a/mcs/class/referencesource/mscorlib/system/io/fileinfo.cs b/mcs/class/referencesource/mscorlib/system/io/fileinfo.cs index f3da2cbd414..2402d9d2bde 100644 --- a/mcs/class/referencesource/mscorlib/system/io/fileinfo.cs +++ b/mcs/class/referencesource/mscorlib/system/io/fileinfo.cs @@ -132,7 +132,7 @@ namespace System.IO { { #if FEATURE_MONO_CAS #if !FEATURE_CORECLR - new FileIOPermission(FileIOPermissionAccess.Read, new String[] { FullPath }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, FullPath, false, false); #endif #endif _name = Path.GetFileName(OriginalPath); @@ -192,7 +192,7 @@ namespace System.IO { FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, DisplayPath, FullPath); state.EnsureState(); #else - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { directoryName }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, directoryName, false, false); #endif #endif } @@ -344,7 +344,7 @@ namespace System.IO { state.EnsureState(); #else // For security check, path should be resolved to an absolute path. - new FileIOPermission(FileIOPermissionAccess.Write, new String[] { FullPath }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, FullPath, false, false); #endif #endif @@ -483,7 +483,7 @@ namespace System.IO { sourceState.EnsureState(); destState.EnsureState(); #else - new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new String[] { FullPath }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, FullPath, false, false); FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, fullDestFileName, false, false); #endif #endif diff --git a/mcs/class/referencesource/mscorlib/system/io/filestream.cs b/mcs/class/referencesource/mscorlib/system/io/filestream.cs index 38b86735241..7e47b8bedec 100644 --- a/mcs/class/referencesource/mscorlib/system/io/filestream.cs +++ b/mcs/class/referencesource/mscorlib/system/io/filestream.cs @@ -708,29 +708,26 @@ namespace System.IO { // Get absolute path - Security needs this to prevent something // like trying to create a file in c:\tmp with the name // "..\WinNT\System32\ntoskrnl.exe". Store it for user convenience. - int maxPath = useLongPath ? Path.MaxLongPath : Path.MaxPath; - String filePath = Path.NormalizePath(path, true, maxPath); + int maxPath = useLongPath + ? PathInternal.MaxLongPath + : AppContextSwitches.BlockLongPaths ? PathInternal.MaxShortPath : PathInternal.MaxLongPath; + + string filePath = Path.NormalizePath(path, true, maxPath); _fileName = filePath; // Prevent access to your disk drives as raw block devices. - if (filePath.StartsWith("\\\\.\\", StringComparison.Ordinal)) + // + // We'll allow if in full trust and not in legacy mode. You can also get device access via \\?\ and \??\ so there isn't + // much point in making users jump through these hoops. Blocking is pointless in full trust as well. + if ( +#if FEATURE_CAS_POLICY + (!CodeAccessSecurityEngine.QuickCheckForAllDemands() || AppContextSwitches.UseLegacyPathHandling) + && +#endif + filePath.StartsWith("\\\\.\\", StringComparison.Ordinal)) throw new ArgumentException(Environment.GetResourceString("Arg_DevicesNotSupported")); - // In 4.0, we always construct a FileIOPermission object below. - // If filePath contained a ':', we would throw a NotSupportedException in - // System.Security.Util.StringExpressionSet.CanonicalizePath. - // If filePath contained other illegal characters, we would throw an ArgumentException in - // FileIOPermission.CheckIllegalCharacters. - // In 4.5 we on longer construct the FileIOPermission object in full trust. - // To preserve the 4.0 behavior we do an explicit check for ':' here and also call Path.CheckInvalidPathChars. - // Note that we need to call CheckInvalidPathChars before checking for ':' because that is what FileIOPermission does. - - Path.CheckInvalidPathChars(filePath, true); - - if (filePath.IndexOf( ':', 2 ) != -1) - throw new NotSupportedException( Environment.GetResourceString( "Argument_PathFormatNotSupported" ) ); - bool read = false; #if FEATURE_MACL @@ -747,7 +744,12 @@ namespace System.IO { // All demands in full trust domains are no-ops, so skip #if FEATURE_CAS_POLICY - if (!CodeAccessSecurityEngine.QuickCheckForAllDemands()) + if (CodeAccessSecurityEngine.QuickCheckForAllDemands()) + { + // Need to throw the same exceptions that are thrown if we actually called QuickDemand() below. + FileIOPermission.EmulateFileIOPermissionChecks(filePath); + } + else #endif // FEATURE_CAS_POLICY { // Build up security permissions required, as well as validate we @@ -796,7 +798,7 @@ namespace System.IO { } AccessControlActions control = specifiedAcl ? AccessControlActions.Change : AccessControlActions.None; - new FileIOPermission(secAccess, control, new String[] { filePath }, false, false).Demand(); + FileIOPermission.QuickDemand(secAccess, control, new String[] { filePath }, false, false); #else #if FEATURE_CORECLR if (checkHost) { @@ -804,7 +806,7 @@ namespace System.IO { state.EnsureState(); } #else - new FileIOPermission(secAccess, new String[] { filePath }, false, false).Demand(); + FileIOPermission.QuickDemand(secAccess, filePath, false, false); #endif // FEATURE_CORECLR #endif } @@ -867,7 +869,7 @@ namespace System.IO { { try { #if !FEATURE_CORECLR - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, _fileName, false, false); #endif canGiveFullPath = true; } @@ -1202,7 +1204,7 @@ namespace System.IO { FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, _fileName); sourceState.EnsureState(); #else - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { _fileName }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, _fileName, false, false); #endif return _fileName; } diff --git a/mcs/class/referencesource/mscorlib/system/io/filesystemenumerable.cs b/mcs/class/referencesource/mscorlib/system/io/filesystemenumerable.cs index ec69c33afb7..5acaf13e86d 100644 --- a/mcs/class/referencesource/mscorlib/system/io/filesystemenumerable.cs +++ b/mcs/class/referencesource/mscorlib/system/io/filesystemenumerable.cs @@ -234,7 +234,7 @@ namespace System.IO state2.EnsureState(); } #else - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false); #endif // normalize search criteria @@ -340,7 +340,7 @@ namespace System.IO state2.EnsureState(); } #else - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false); #endif searchData = new Directory.SearchData(normalizedSearchPath, userPath, searchOption); CommonInit(); @@ -591,8 +591,7 @@ namespace System.IO } #else String demandDir = Directory.GetDemandDir(fullPathToDemand, true); - String[] demandPaths = new String[] { demandDir }; - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandPaths, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandDir, false, false); #endif } @@ -706,8 +705,7 @@ namespace System.IO FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, name); state.EnsureState(); #else - String[] names = new String[] { name }; - new FileIOPermission(FileIOPermissionAccess.Read, names, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, name, false, false); #endif FileInfo fi = new FileInfo(name, false); fi.InitializeFrom(result.FindData); @@ -733,8 +731,7 @@ namespace System.IO FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, permissionName); state.EnsureState(); #else - String[] permissionNames = new String[] { permissionName }; - new FileIOPermission(FileIOPermissionAccess.Read, permissionNames, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, permissionName, false, false); #endif DirectoryInfo di = new DirectoryInfo(name, false); di.InitializeFrom(result.FindData); @@ -770,8 +767,7 @@ namespace System.IO FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, permissionName); state.EnsureState(); #else - String[] permissionNames = new String[] { permissionName }; - new FileIOPermission(FileIOPermissionAccess.Read, permissionNames, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, permissionName, false, false); #endif DirectoryInfo di = new DirectoryInfo(name, false); di.InitializeFrom(result.FindData); @@ -786,8 +782,7 @@ namespace System.IO FileSecurityState state = new FileSecurityState(FileSecurityStateAccess.Read, String.Empty, name); state.EnsureState(); #else - String[] names = new String[] { name }; - new FileIOPermission(FileIOPermissionAccess.Read, names, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, name, false, false); #endif FileInfo fi = new FileInfo(name, false); fi.InitializeFrom(result.FindData); diff --git a/mcs/class/referencesource/mscorlib/system/io/filesysteminfo.cs b/mcs/class/referencesource/mscorlib/system/io/filesysteminfo.cs index c551e66159a..cf65efb2cf0 100644 --- a/mcs/class/referencesource/mscorlib/system/io/filesysteminfo.cs +++ b/mcs/class/referencesource/mscorlib/system/io/filesysteminfo.cs @@ -107,7 +107,7 @@ namespace System.IO { FileSecurityState sourceState = new FileSecurityState(FileSecurityStateAccess.PathDiscovery, String.Empty, demandDir); sourceState.EnsureState(); #else - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandDir).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandDir); #endif #endif return FullPath; @@ -126,7 +126,7 @@ namespace System.IO { demandDir = FullPath; #if FEATURE_MONO_CAS #if !FEATURE_CORECLR - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, demandDir).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, demandDir); #endif #endif return FullPath; @@ -353,7 +353,7 @@ namespace System.IO { set { #if FEATURE_MONO_CAS #if !FEATURE_CORECLR - new FileIOPermission(FileIOPermissionAccess.Write, FullPath).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, FullPath); #endif #endif #if MONO @@ -386,7 +386,7 @@ namespace System.IO { { #if FEATURE_MONO_CAS #if !FEATURE_CORECLR - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, FullPath).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, FullPath); #endif #endif diff --git a/mcs/class/referencesource/mscorlib/system/io/longpath.cs b/mcs/class/referencesource/mscorlib/system/io/longpath.cs index 2240ba9e1ab..7b863b95c8d 100644 --- a/mcs/class/referencesource/mscorlib/system/io/longpath.cs +++ b/mcs/class/referencesource/mscorlib/system/io/longpath.cs @@ -195,9 +195,9 @@ namespace System.IO { Contract.Requires(destFileName.Length > 0); String fullSourceFileName = LongPath.NormalizePath(sourceFileName); - new FileIOPermission(FileIOPermissionAccess.Read, new String[] { fullSourceFileName }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, fullSourceFileName, false, false); String fullDestFileName = LongPath.NormalizePath(destFileName); - new FileIOPermission(FileIOPermissionAccess.Write, new String[] { fullDestFileName }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, fullDestFileName, false, false); InternalCopy(fullSourceFileName, fullDestFileName, sourceFileName, destFileName, overwrite); } @@ -258,7 +258,7 @@ namespace System.IO { String fullPath = LongPath.NormalizePath(path); // For security check, path should be resolved to an absolute path. - new FileIOPermission(FileIOPermissionAccess.Write, new String[] { fullPath }, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, fullPath, false, false); String tempPath = Path.AddLongPathPrefix(fullPath); bool r = Win32Native.DeleteFile(tempPath); @@ -297,8 +297,8 @@ namespace System.IO { if (path.Length > 0 && Path.IsDirectorySeparator(path[path.Length - 1])) { return false; } - - new FileIOPermission(FileIOPermissionAccess.Read, new String[] { path }, false, false ).Demand(); + + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, path, false, false ); return InternalExists(path); } @@ -326,7 +326,7 @@ namespace System.IO { Contract.Requires(path != null); String fullPath = LongPath.NormalizePath(path); - new FileIOPermission(FileIOPermissionAccess.Read, new String[] { fullPath }, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, fullPath, false, false); String tempPath = Path.AddLongPathPrefix(fullPath); @@ -348,7 +348,7 @@ namespace System.IO { Contract.Requires(path != null); String fullPath = LongPath.NormalizePath(path); - new FileIOPermission(FileIOPermissionAccess.Read, new String[] { fullPath }, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, fullPath, false, false); String tempPath = Path.AddLongPathPrefix(fullPath); Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA(); @@ -369,7 +369,7 @@ namespace System.IO { Contract.Requires(path != null); String fullPath = LongPath.NormalizePath(path); - new FileIOPermission(FileIOPermissionAccess.Read, new String[] { fullPath }, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, fullPath, false, false); String tempPath = Path.AddLongPathPrefix(fullPath); Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA(); @@ -400,9 +400,9 @@ namespace System.IO { Contract.Requires(destFileName.Length > 0); String fullSourceFileName = LongPath.NormalizePath(sourceFileName); - new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new String[] { fullSourceFileName }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, fullSourceFileName, false, false); String fullDestFileName = LongPath.NormalizePath(destFileName); - new FileIOPermission(FileIOPermissionAccess.Write, new String[] { fullDestFileName }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, fullDestFileName, false, false); if (!LongPathFile.InternalExists(fullSourceFileName)) __Error.WinIOError(Win32Native.ERROR_FILE_NOT_FOUND, fullSourceFileName); @@ -423,7 +423,7 @@ namespace System.IO { Contract.Requires(path != null); String fullPath = LongPath.NormalizePath(path); - new FileIOPermission(FileIOPermissionAccess.Read, new String[] { fullPath }, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, fullPath, false, false); String tempPath = Path.AddLongPathPrefix(fullPath); Win32Native.WIN32_FILE_ATTRIBUTE_DATA data = new Win32Native.WIN32_FILE_ATTRIBUTE_DATA(); @@ -435,7 +435,6 @@ namespace System.IO { __Error.WinIOError(Win32Native.ERROR_FILE_NOT_FOUND, path); return ((long)data.fileSizeHigh) << 32 | ((long)data.fileSizeLow & 0xFFFFFFFFL); - } // Defined in WinError.h @@ -460,7 +459,7 @@ namespace System.IO { // We attempt to create directories only after all the security checks have passed. This is avoid doing // a demand at every level. String demandDir = GetDemandDir(fullPath, true); - new FileIOPermission(FileIOPermissionAccess.Read, new String[] { demandDir }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandDir, false, false); InternalCreateDirectory(fullPath, path, null); } @@ -514,7 +513,15 @@ namespace System.IO { int count = stackDir.Count; - if (stackDir.Count != 0) + if (stackDir.Count != 0 +#if FEATURE_CAS_POLICY + // All demands in full trust domains are no-ops, so skip + // + // The full path went through validity checks by being passed through FileIOPermissions already. + // As a sub string of the full path can't fail the checks if the full path passes. + && !CodeAccessSecurityEngine.QuickCheckForAllDemands() +#endif + ) { String[] securityList = new String[stackDir.Count]; stackDir.CopyTo(securityList, 0); @@ -524,9 +531,9 @@ namespace System.IO { // Security check for all directories not present only. #if !FEATURE_PAL && FEATURE_MACL AccessControlActions control = (dirSecurity == null) ? AccessControlActions.None : AccessControlActions.Change; - new FileIOPermission(FileIOPermissionAccess.Write, control, securityList, false, false ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, control, securityList, false, false); #else - new FileIOPermission(FileIOPermissionAccess.Write, securityList, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, securityList, false, false); #endif } @@ -554,9 +561,11 @@ namespace System.IO { { String name = stackDir[stackDir.Count - 1]; stackDir.RemoveAt(stackDir.Count - 1); + if (name.Length >= Path.MaxLongPath) throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - r = Win32Native.CreateDirectory(Path.AddLongPathPrefix(name), secAttrs); + + r = Win32Native.CreateDirectory(PathInternal.EnsureExtendedPrefix(name), secAttrs); if (!r && (firstError == 0)) { int currentError = Marshal.GetLastWin32Error(); @@ -579,7 +588,7 @@ namespace System.IO { // Give the user a nice error message, but don't leak path information. try { - new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new String[] { GetDemandDir(name, true) }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.PathDiscovery, GetDemandDir(name, true), false, false); errorString = name; } catch (SecurityException) { } @@ -631,8 +640,8 @@ namespace System.IO { if (destPath.Length >= Path.MaxLongPath) throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - new FileIOPermission(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, new String[] { sourcePath }, false, false).Demand(); - new FileIOPermission(FileIOPermissionAccess.Write, new String[] { destPath }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write | FileIOPermissionAccess.Read, sourcePath, false, false); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, destPath, false, false); if (String.Compare(sourcePath, destPath, StringComparison.OrdinalIgnoreCase) == 0) throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustBeDifferent")); @@ -643,8 +652,8 @@ namespace System.IO { throw new IOException(Environment.GetResourceString("IO.IO_SourceDestMustHaveSameRoot")); - String tempSourceDirName = Path.AddLongPathPrefix(sourceDirName); - String tempDestDirName = Path.AddLongPathPrefix(destDirName); + String tempSourceDirName = PathInternal.EnsureExtendedPrefix(sourceDirName); + String tempDestDirName = PathInternal.EnsureExtendedPrefix(destDirName); if (!Win32Native.MoveFile(tempSourceDirName, tempDestDirName)) { @@ -683,7 +692,7 @@ namespace System.IO { demandPath = GetDemandDir(fullPath, !recursive); // Make sure we have write permission to this directory - new FileIOPermission(FileIOPermissionAccess.Write, new String[] { demandPath }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, demandPath, false, false); String longPath = Path.AddLongPathPrefix(fullPath); // Do not recursively delete through reparse points. Perhaps in a @@ -904,7 +913,7 @@ namespace System.IO { String fullPath = LongPath.NormalizePath(path); String demandPath = GetDemandDir(fullPath, true); - new FileIOPermission(FileIOPermissionAccess.Read, new String[] { demandPath }, false, false).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Read, demandPath, false, false); return InternalExists(fullPath); } diff --git a/mcs/class/referencesource/mscorlib/system/io/path.cs b/mcs/class/referencesource/mscorlib/system/io/path.cs index b4cb0ab7e36..3927d52da07 100644 --- a/mcs/class/referencesource/mscorlib/system/io/path.cs +++ b/mcs/class/referencesource/mscorlib/system/io/path.cs @@ -55,19 +55,19 @@ namespace System.IO { // public static readonly char DirectorySeparatorChar = '\\'; internal const string DirectorySeparatorCharAsString = "\\"; - + // Platform specific alternate directory separator character. // This is backslash ('\') on Unix, and slash ('/') on Windows // and MacOS. // public static readonly char AltDirectorySeparatorChar = '/'; - + // Platform specific volume separator character. This is colon (':') // on Windows and MacOS, and slash ('/') on Unix. This is mostly - // useful for parsing paths like "c:\windows" or "MacVolume:System Folder". + // useful for parsing paths like "c:\windows" or "MacVolume:System Folder". // public static readonly char VolumeSeparatorChar = ':'; - + // Platform specific invalid list of characters in a path. // See the "Naming a File" MSDN conceptual docs for more details on // what is valid in a file name (which is slightly different from what @@ -77,10 +77,10 @@ namespace System.IO { public static readonly char[] InvalidPathChars = { '\"', '<', '>', '|', '\0', (Char)1, (Char)2, (Char)3, (Char)4, (Char)5, (Char)6, (Char)7, (Char)8, (Char)9, (Char)10, (Char)11, (Char)12, (Char)13, (Char)14, (Char)15, (Char)16, (Char)17, (Char)18, (Char)19, (Char)20, (Char)21, (Char)22, (Char)23, (Char)24, (Char)25, (Char)26, (Char)27, (Char)28, (Char)29, (Char)30, (Char)31 }; // Trim trailing white spaces, tabs etc but don't be aggressive in removing everything that has UnicodeCategory of trailing space. - // String.WhitespaceChars will trim aggressively than what the underlying FS does (for ex, NTFS, FAT). - internal static readonly char[] TrimEndChars = { (char) 0x9, (char) 0xA, (char) 0xB, (char) 0xC, (char) 0xD, (char) 0x20, (char) 0x85, (char) 0xA0}; - - private static readonly char[] RealInvalidPathChars = { '\"', '<', '>', '|', '\0', (Char)1, (Char)2, (Char)3, (Char)4, (Char)5, (Char)6, (Char)7, (Char)8, (Char)9, (Char)10, (Char)11, (Char)12, (Char)13, (Char)14, (Char)15, (Char)16, (Char)17, (Char)18, (Char)19, (Char)20, (Char)21, (Char)22, (Char)23, (Char)24, (Char)25, (Char)26, (Char)27, (Char)28, (Char)29, (Char)30, (Char)31 }; + // String.WhitespaceChars will trim aggressively than what the underlying FS does (for ex, NTFS, FAT). + internal static readonly char[] TrimEndChars = LongPathHelper.s_trimEndChars; + + private static readonly char[] RealInvalidPathChars = PathInternal.InvalidPathChars; // This is used by HasIllegalCharacters private static readonly char[] InvalidPathCharsWithAdditionalChecks = { '\"', '<', '>', '|', '\0', (Char)1, (Char)2, (Char)3, (Char)4, (Char)5, (Char)6, (Char)7, (Char)8, (Char)9, (Char)10, (Char)11, (Char)12, (Char)13, (Char)14, (Char)15, (Char)16, (Char)17, (Char)18, (Char)19, (Char)20, (Char)21, (Char)22, (Char)23, (Char)24, (Char)25, (Char)26, (Char)27, (Char)28, (Char)29, (Char)30, (Char)31, '*', '?' }; @@ -89,16 +89,15 @@ namespace System.IO { public static readonly char PathSeparator = ';'; - // Make this public sometime. // The max total path is 260, and the max individual component length is 255. // For example, D:\<256 char file name> isn't legal, even though it's under 260 chars. - internal static readonly int MaxPath = 260; - private static readonly int MaxDirectoryLength = 255; + internal static readonly int MaxPath = PathInternal.MaxShortPath; + private static readonly int MaxDirectoryLength = PathInternal.MaxComponentLength; // Windows API definitions - internal const int MAX_PATH = 260; // From WinDef.h - internal const int MAX_DIRECTORY_PATH = 248; // cannot create directories greater than 248 characters + internal const int MAX_PATH = PathInternal.MaxShortPath; // From WinDef.h + internal const int MAX_DIRECTORY_PATH = PathInternal.MaxShortDirectoryPath; // cannot create directories greater than 248 characters // Changes the extension of a file path. The path parameter // specifies a file path, and the extension parameter @@ -136,7 +135,6 @@ namespace System.IO { return null; } - // Returns the directory path of a file path. This method effectively // removes the last element of the given file path, i.e. it returns a // string consisting of all characters up to but not including the last @@ -146,7 +144,17 @@ namespace System.IO { // [ResourceExposure(ResourceScope.None)] [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] - public static String GetDirectoryName(String path) { + public static string GetDirectoryName(string path) + { + return InternalGetDirectoryName(path); + } + + [ResourceExposure(ResourceScope.None)] + [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)] + [System.Security.SecuritySafeCritical] + + private static string InternalGetDirectoryName(string path) + { if (path != null) { CheckInvalidPathChars(path); @@ -154,16 +162,29 @@ namespace System.IO { if (!CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) { #endif - string normalizedPath = NormalizePath(path, false); + // Expanding short paths is dangerous in this case as the results will change with the current directory. + // + // Suppose you have a path called "PICTUR~1\Foo". Now suppose you have two folders on disk "C:\Mine\Pictures Of Me" + // and "C:\Yours\Pictures of You". If the current directory is neither you'll get back "PICTUR~1". If it is "C:\Mine" + // get back "Pictures Of Me". "C:\Yours" would give back "Pictures of You". + // + // Because of this and as it isn't documented that short paths are expanded we will not expand short names unless + // we're in legacy mode. + string normalizedPath = NormalizePath(path, fullCheck: false, expandShortPaths: AppContextSwitches.UseLegacyPathHandling); // If there are no permissions for PathDiscovery to this path, we should NOT expand the short paths // as this would leak information about paths to which the user would not have access to. - if (path.Length > 0) + if (path.Length > 0 +#if FEATURE_CAS_POLICY + // Only do the extra logic if we're not in full trust + && !CodeAccessSecurityEngine.QuickCheckForAllDemands() +#endif + ) { try { // If we were passed in a path with \\?\ we need to remove it as FileIOPermission does not like it. - string tempPath = Path.RemoveLongPathPrefix(path); + string tempPath = RemoveLongPathPrefix(path); // FileIOPermission cannot handle paths that contain ? or * // So we only pass to FileIOPermission the text up to them. @@ -176,14 +197,14 @@ namespace System.IO { // While we don't use the result of this call we are using it as a consistent way of // doing the security checks. if (pos > 0) - Path.GetFullPath(tempPath.Substring(0, pos)); + GetFullPath(tempPath.Substring(0, pos)); } catch (SecurityException) { // If the user did not have permissions to the path, make sure that we don't leak expanded short paths // Only re-normalize if the original path had a ~ in it. if (path.IndexOf("~", StringComparison.Ordinal) != -1) { - normalizedPath = NormalizePath(path, /*fullCheck*/ false, /*expandShortPaths*/ false); + normalizedPath = NormalizePath(path, fullCheck: false, expandShortPaths: false); } } catch (PathTooLongException) { } @@ -203,13 +224,13 @@ namespace System.IO { if (i > root) { i = path.Length; if (i == root) return null; - while (i > root && path[--i] != DirectorySeparatorChar && path[i] != AltDirectorySeparatorChar); + while (i > root && path[--i] != DirectorySeparatorChar && path[i] != AltDirectorySeparatorChar); String dir = path.Substring(0, i); #if FEATURE_LEGACYNETCF - if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) { + if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8) { if (dir.Length >= MAX_PATH - 1) throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); - } + } #endif return dir; } @@ -220,9 +241,22 @@ namespace System.IO { // Gets the length of the root DirectoryInfo or whatever DirectoryInfo markers // are specified for the first part of the DirectoryInfo name. // - internal static int GetRootLength(String path) { + internal static int GetRootLength(string path) + { CheckInvalidPathChars(path); - + + if (AppContextSwitches.UseLegacyPathHandling) + { + return LegacyGetRootLength(path); + } + else + { + return PathInternal.GetRootLength(path); + } + } + + private static int LegacyGetRootLength(string path) + { int i = 0; int length = path.Length; @@ -247,7 +281,6 @@ namespace System.IO { return (c==DirectorySeparatorChar || c == AltDirectorySeparatorChar); } - public static char[] GetInvalidPathChars() { return (char[]) RealInvalidPathChars.Clone(); @@ -330,7 +363,7 @@ namespace System.IO { throw new ArgumentNullException("path"); Contract.EndContractBlock(); - String newPath = NormalizePath(path, true); + string newPath = NormalizePath(path, fullCheck: true); return newPath; } @@ -338,8 +371,9 @@ namespace System.IO { [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - internal unsafe static String NormalizePath(String path, bool fullCheck) { - return NormalizePath(path, fullCheck, MaxPath); + internal unsafe static String NormalizePath(String path, bool fullCheck) + { + return NormalizePath(path, fullCheck, AppContextSwitches.BlockLongPaths ? PathInternal.MaxShortPath : PathInternal.MaxLongPath); } [System.Security.SecuritySafeCritical] // auto-generated @@ -347,31 +381,127 @@ namespace System.IO { [ResourceConsumption(ResourceScope.Machine)] internal unsafe static String NormalizePath(String path, bool fullCheck, bool expandShortPaths) { - return NormalizePath(path, fullCheck, MaxPath, expandShortPaths); + return NormalizePath(path, fullCheck, MaxPath, expandShortPaths: expandShortPaths); } [System.Security.SecuritySafeCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] internal unsafe static String NormalizePath(String path, bool fullCheck, int maxPathLength) { - return NormalizePath(path, fullCheck, maxPathLength, true); + return NormalizePath(path, fullCheck, maxPathLength, expandShortPaths: true); } - [System.Security.SecurityCritical] // auto-generated + [System.Security.SecuritySafeCritical] [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - internal unsafe static String NormalizePath(String path, bool fullCheck, int maxPathLength, bool expandShortPaths) { + internal static string NormalizePath(string path, bool fullCheck, int maxPathLength, bool expandShortPaths) + { + if (AppContextSwitches.UseLegacyPathHandling) + { + return LegacyNormalizePath(path, fullCheck, maxPathLength, expandShortPaths); + } + else + { + if (PathInternal.IsExtended(path)) + { + // We can't really know what is valid for all cases of extended paths. + // + // - object names can include other characters as well (':', '/', etc.) + // - even file objects have different rules (pipe names can contain most characters) + // + // As such we will do no further analysis of extended paths to avoid blocking known and unknown + // scenarios as well as minimizing compat breaks should we block now and need to unblock later. + return path; + } + + string normalizedPath = null; + if (fullCheck == false) + { + // Disabled fullCheck is only called by GetDirectoryName and GetPathRoot. + // Avoid adding addtional callers and try going direct to lighter weight NormalizeDirectorySeparators. + normalizedPath = NewNormalizePathLimitedChecks(path, maxPathLength, expandShortPaths); + } + else + { + normalizedPath = NewNormalizePath(path, maxPathLength, expandShortPaths: true); + } + + if (string.IsNullOrWhiteSpace(normalizedPath)) + throw new ArgumentException(Environment.GetResourceString("Arg_PathIllegal")); + return normalizedPath; + } + } + + [System.Security.SecuritySafeCritical] + private static string NewNormalizePathLimitedChecks(string path, int maxPathLength, bool expandShortPaths) + { + string normalized = PathInternal.NormalizeDirectorySeparators(path); + + if (PathInternal.IsPathTooLong(normalized) || PathInternal.AreSegmentsTooLong(normalized)) + throw new PathTooLongException(); + + if (!PathInternal.IsDevice(normalized) && PathInternal.HasInvalidVolumeSeparator(path)) + throw new ArgumentException(Environment.GetResourceString("Arg_PathIllegal")); + + if (expandShortPaths && normalized.IndexOf('~') != -1) + { + try + { + return LongPathHelper.GetLongPathName(normalized); + } + catch + { + // Don't care if we can't get the long path- might not exist, etc. + } + } + + return normalized; + } + + /// + /// Normalize the path and check for bad characters or other invalid syntax. + /// + [System.Security.SecuritySafeCritical] + [ResourceExposure(ResourceScope.Machine)] + [ResourceConsumption(ResourceScope.Machine)] + private static string NewNormalizePath(string path, int maxPathLength, bool expandShortPaths) + { Contract.Requires(path != null, "path can't be null"); - // If we're doing a full path check, trim whitespace and look for - // illegal path characters. - if (fullCheck) { + + // Embedded null characters are the only invalid character case we want to check up front. + // This is because the nulls will signal the end of the string to Win32 and therefore have + // unpredictable results. Other invalid characters we give a chance to be normalized out. + if (path.IndexOf('\0') != -1) + throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars")); + + // Note that colon and wildcard checks happen in FileIOPermissions + + // Technically this doesn't matter but we used to throw for this case + if (string.IsNullOrWhiteSpace(path)) + throw new ArgumentException(Environment.GetResourceString("Arg_PathIllegal")); + + // We don't want to check invalid characters for device format- see comments for extended above + return LongPathHelper.Normalize(path, (uint)maxPathLength, checkInvalidCharacters: !PathInternal.IsDevice(path), expandShortPaths: expandShortPaths); + } + + [System.Security.SecurityCritical] // auto-generated + [ResourceExposure(ResourceScope.Machine)] + [ResourceConsumption(ResourceScope.Machine)] + internal unsafe static string LegacyNormalizePath(string path, bool fullCheck, int maxPathLength, bool expandShortPaths) + { + Contract.Requires(path != null, "path can't be null"); + + // If we're doing a full path check, trim whitespace and look for illegal path characters. + if (fullCheck) + { // Trim whitespace off the end of the string. // Win32 normalization trims only U+0020. path = path.TrimEnd(TrimEndChars); // Look for illegal path characters. - CheckInvalidPathChars(path); + if (PathInternal.AnyPathHasIllegalCharacters(path)) + throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars")); } int index = 0; @@ -777,50 +907,75 @@ namespace System.IO { return returnVal; } - internal const int MaxLongPath = 32000; - private const string LongPathPrefix = @"\\?\"; - private const string UNCPathPrefix = @"\\"; - private const string UNCLongPathPrefixToInsert = @"?\UNC\"; - private const string UNCLongPathPrefix = @"\\?\UNC\"; + internal const int MaxLongPath = PathInternal.MaxLongPath; - internal unsafe static bool HasLongPathPrefix(String path) + private const string LongPathPrefix = PathInternal.ExtendedPathPrefix; + private const string UNCPathPrefix = PathInternal.UncPathPrefix; + private const string UNCLongPathPrefixToInsert = PathInternal.UncExtendedPrefixToInsert; + private const string UNCLongPathPrefix = PathInternal.UncExtendedPathPrefix; + + internal static bool HasLongPathPrefix(string path) { - return path.StartsWith(LongPathPrefix, StringComparison.Ordinal); + if (AppContextSwitches.UseLegacyPathHandling) + return path.StartsWith(LongPathPrefix, StringComparison.Ordinal); + else + return PathInternal.IsExtended(path); } - internal unsafe static String AddLongPathPrefix(String path) + internal static string AddLongPathPrefix(string path) { - if (path.StartsWith(LongPathPrefix, StringComparison.Ordinal)) - return path; + if (AppContextSwitches.UseLegacyPathHandling) + { + if (path.StartsWith(LongPathPrefix, StringComparison.Ordinal)) + return path; - if (path.StartsWith(UNCPathPrefix, StringComparison.Ordinal)) - return path.Insert(2, UNCLongPathPrefixToInsert); // Given \\server\share in longpath becomes \\?\UNC\server\share => UNCLongPathPrefix + path.SubString(2); => The actual command simply reduces the operation cost. + if (path.StartsWith(UNCPathPrefix, StringComparison.Ordinal)) + return path.Insert(2, UNCLongPathPrefixToInsert); // Given \\server\share in longpath becomes \\?\UNC\server\share => UNCLongPathPrefix + path.SubString(2); => The actual command simply reduces the operation cost. - return LongPathPrefix + path; + return LongPathPrefix + path; + } + else + { + return PathInternal.EnsureExtendedPrefix(path); + } } - internal unsafe static String RemoveLongPathPrefix(String path) + internal static string RemoveLongPathPrefix(string path) { - if (!path.StartsWith(LongPathPrefix, StringComparison.Ordinal)) - return path; + if (AppContextSwitches.UseLegacyPathHandling) + { + if (!path.StartsWith(LongPathPrefix, StringComparison.Ordinal)) + return path; - if (path.StartsWith(UNCLongPathPrefix, StringComparison.OrdinalIgnoreCase)) - return path.Remove(2, 6); // Given \\?\UNC\server\share we return \\server\share => @'\\' + path.SubString(UNCLongPathPrefix.Length) => The actual command simply reduces the operation cost. + if (path.StartsWith(UNCLongPathPrefix, StringComparison.OrdinalIgnoreCase)) + return path.Remove(2, 6); // Given \\?\UNC\server\share we return \\server\share => @'\\' + path.SubString(UNCLongPathPrefix.Length) => The actual command simply reduces the operation cost. - return path.Substring(4); + return path.Substring(4); + } + else + { + return PathInternal.RemoveExtendedPrefix(path); + } } - internal unsafe static StringBuilder RemoveLongPathPrefix(StringBuilder pathSB) + internal static StringBuilder RemoveLongPathPrefix(StringBuilder pathSB) { - string path = pathSB.ToString(); - if (!path.StartsWith(LongPathPrefix, StringComparison.Ordinal)) - return pathSB; + if (AppContextSwitches.UseLegacyPathHandling) + { + if (!PathInternal.StartsWithOrdinal(pathSB, LongPathPrefix)) + return pathSB; - if (path.StartsWith(UNCLongPathPrefix, StringComparison.OrdinalIgnoreCase)) - return pathSB.Remove(2, 6); // Given \\?\UNC\server\share we return \\server\share => @'\\' + path.SubString(UNCLongPathPrefix.Length) => The actual command simply reduces the operation cost. + // Given \\?\UNC\server\share we return \\server\share => @'\\' + path.SubString(UNCLongPathPrefix.Length) => The actual command simply reduces the operation cost. + if (PathInternal.StartsWithOrdinal(pathSB, UNCLongPathPrefix, ignoreCase: true)) + return pathSB.Remove(2, 6); - return pathSB.Remove(0, 4); + return pathSB.Remove(0, 4); + } + else + { + return PathInternal.RemoveExtendedPrefix(pathSB); + } } // Returns the name and extension parts of the given path. The resulting @@ -860,8 +1015,6 @@ namespace System.IO { return null; } - - // Returns the root portion of the given path. The resulting string // consists of those rightmost characters of the path that constitute the // root of the path. Possible patterns for the resulting string are: An @@ -876,7 +1029,10 @@ namespace System.IO { [ResourceConsumption(ResourceScope.Machine)] public static String GetPathRoot(String path) { if (path == null) return null; - path = NormalizePath(path, false); + + // Expanding short paths has no impact on the path root- there is no such thing as an + // 8.3 volume or server/share name. + path = NormalizePath(path, fullCheck: false, expandShortPaths: false); return path.Substring(0, GetRootLength(path)); } @@ -903,15 +1059,9 @@ namespace System.IO { internal static bool IsRelative(string path) { Contract.Assert(path != null, "path can't be null"); - if ((path.Length >= 3 && path[1] == VolumeSeparatorChar && path[2] == DirectorySeparatorChar && - ((path[0] >= 'a' && path[0] <= 'z') || (path[0] >= 'A' && path[0] <= 'Z'))) || - (path.Length >= 2 && path[0] == '\\' && path[1] == '\\')) - return false; - else - return true; - + return PathInternal.IsPartiallyQualified(path); } - + // Returns a cryptographically strong random 8.3 string that can be // used as either a folder name or a file name. public static String GetRandomFileName() @@ -978,7 +1128,7 @@ namespace System.IO { state.EnsureState(); } #else - new FileIOPermission(FileIOPermissionAccess.Write, path).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.Write, path); #endif StringBuilder sb = new StringBuilder(MAX_PATH); uint r = Win32Native.GetTempFileName(path, "tmp", 0, sb); @@ -1214,31 +1364,17 @@ namespace System.IO { searchPattern = searchPattern.Substring(index + 2); } - - } - - internal static bool HasIllegalCharacters(String path, bool checkAdditional) - { - Contract.Requires(path != null); - - if (checkAdditional) - { - return path.IndexOfAny(InvalidPathCharsWithAdditionalChecks) >= 0; - } - - return path.IndexOfAny(RealInvalidPathChars) >= 0; } - internal static void CheckInvalidPathChars(String path, bool checkAdditional = false) + internal static void CheckInvalidPathChars(string path, bool checkAdditional = false) { if (path == null) throw new ArgumentNullException("path"); - if (Path.HasIllegalCharacters(path, checkAdditional)) + if (PathInternal.HasIllegalCharacters(path, checkAdditional)) throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars")); } - internal static String InternalCombine(String path1, String path2) { if (path1==null || path2==null) throw new ArgumentNullException((path1==null) ? "path1" : "path2"); diff --git a/mcs/class/referencesource/mscorlib/system/resources/resourcereader.cs b/mcs/class/referencesource/mscorlib/system/resources/resourcereader.cs index a67ee8c29f5..33c341eb4f7 100644 --- a/mcs/class/referencesource/mscorlib/system/resources/resourcereader.cs +++ b/mcs/class/referencesource/mscorlib/system/resources/resourcereader.cs @@ -1014,10 +1014,15 @@ namespace System.Resources { } } else { - int seekPos = unchecked(4 * _numResources); - if (seekPos < 0) { + // The hexadecimal E translates to binary 1110 + // So, with this & condition we are checking that none of the highest 3 bits are + // set before multiplying, as that would cause an overflow. + if ((_numResources & 0xE0000000) != 0){ + throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted")); } + + int seekPos = unchecked(4 * _numResources); unsafe { _nameHashesPtr = (int*)_ums.PositionPointer; // Skip over the array of nameHashes. @@ -1046,10 +1051,14 @@ namespace System.Resources { } } else { - int seekPos = unchecked(4 * _numResources); - if (seekPos < 0) { + // The hexadecimal E translates to binary 1110 + // So, with this & condition we are checking that none of the highest 3 bits are + // set before multiplying, as that would cause an overflow. + if ((_numResources & 0xE0000000) != 0){ throw new BadImageFormatException(Environment.GetResourceString("BadImageFormat_ResourcesHeaderCorrupted")); } + + int seekPos = unchecked(4 * _numResources); unsafe { _namePositionsPtr = (int*)_ums.PositionPointer; // Skip over the array of namePositions. diff --git a/mcs/class/referencesource/mscorlib/system/runtime/interopservices/windowsruntime/nativemethods.cs b/mcs/class/referencesource/mscorlib/system/runtime/interopservices/windowsruntime/nativemethods.cs index f9cec78699e..893340d673c 100644 --- a/mcs/class/referencesource/mscorlib/system/runtime/interopservices/windowsruntime/nativemethods.cs +++ b/mcs/class/referencesource/mscorlib/system/runtime/interopservices/windowsruntime/nativemethods.cs @@ -28,22 +28,26 @@ namespace System.Runtime.InteropServices.WindowsRuntime [DllImport("api-ms-win-core-winrt-error-l1-1-1.dll", PreserveSig = false)] [SecurityCritical] [SuppressUnmanagedCodeSecurity] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] internal static extern IRestrictedErrorInfo GetRestrictedErrorInfo(); [DllImport("api-ms-win-core-winrt-error-l1-1-1.dll")] [SecurityCritical] [SuppressUnmanagedCodeSecurity] [return: MarshalAs(UnmanagedType.Bool)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] internal static extern bool RoOriginateLanguageException(int error, [MarshalAs(UnmanagedType.HString)]string message, IntPtr languageException); [DllImport("api-ms-win-core-winrt-error-l1-1-1.dll", PreserveSig = false)] [SecurityCritical] [SuppressUnmanagedCodeSecurity] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] internal static extern void RoReportUnhandledError(IRestrictedErrorInfo error); [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] [SecurityCritical] [SuppressUnmanagedCodeSecurity] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] internal static unsafe extern int WindowsCreateString([MarshalAs(UnmanagedType.LPWStr)] string sourceString, int length, [Out] IntPtr *hstring); @@ -51,6 +55,7 @@ namespace System.Runtime.InteropServices.WindowsRuntime [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] [SecurityCritical] [SuppressUnmanagedCodeSecurity] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] internal static unsafe extern int WindowsCreateStringReference(char *sourceString, int length, [Out] HSTRING_HEADER *hstringHeader, @@ -59,11 +64,13 @@ namespace System.Runtime.InteropServices.WindowsRuntime [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] [SecurityCritical] [SuppressUnmanagedCodeSecurity] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] internal static extern int WindowsDeleteString(IntPtr hstring); [DllImport("api-ms-win-core-winrt-string-l1-1-0.dll", CallingConvention = CallingConvention.StdCall)] [SecurityCritical] [SuppressUnmanagedCodeSecurity] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] internal static unsafe extern char* WindowsGetStringRawBuffer(IntPtr hstring, [Out] uint *length); } } diff --git a/mcs/class/referencesource/mscorlib/system/security/accesscontrol/filesecurity.cs b/mcs/class/referencesource/mscorlib/system/security/accesscontrol/filesecurity.cs index 59c44820f33..fad7beb385e 100644 --- a/mcs/class/referencesource/mscorlib/system/security/accesscontrol/filesecurity.cs +++ b/mcs/class/referencesource/mscorlib/system/security/accesscontrol/filesecurity.cs @@ -435,9 +435,9 @@ namespace System.Security.AccessControl [SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)] [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - internal void Persist( String fullPath ) + internal void Persist(string fullPath) { - new FileIOPermission( FileIOPermissionAccess.NoAccess, AccessControlActions.Change, fullPath ).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.NoAccess, AccessControlActions.Change, fullPath); WriteLock(); @@ -455,12 +455,12 @@ namespace System.Security.AccessControl [System.Security.SecuritySafeCritical] // auto-generated [SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)] - internal void Persist( SafeFileHandle handle, String fullPath ) + internal void Persist(SafeFileHandle handle, string fullPath) { - if ( fullPath != null ) - new FileIOPermission( FileIOPermissionAccess.NoAccess, AccessControlActions.Change, fullPath ).Demand(); + if (fullPath != null) + FileIOPermission.QuickDemand(FileIOPermissionAccess.NoAccess, AccessControlActions.Change, fullPath); else - new FileIOPermission( PermissionState.Unrestricted ).Demand(); + FileIOPermission.QuickDemand(PermissionState.Unrestricted); WriteLock(); @@ -627,11 +627,9 @@ namespace System.Security.AccessControl public sealed class FileSecurity : FileSystemSecurity { - #region Constructors - [System.Security.SecuritySafeCritical] // auto-generated public FileSecurity() - : base( false ) + : base(false) { } @@ -639,11 +637,11 @@ namespace System.Security.AccessControl [SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)] [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - public FileSecurity( String fileName, AccessControlSections includeSections ) + public FileSecurity(string fileName, AccessControlSections includeSections) : base(false, fileName, includeSections, false) { - String fullPath = Path.GetFullPathInternal(fileName); - new FileIOPermission(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath).Demand(); + string fullPath = Path.GetFullPathInternal(fileName); + FileIOPermission.QuickDemand(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath, checkForDuplicates: false, needFullPath: false); } // Warning! Be exceedingly careful with this constructor. Do not make @@ -654,26 +652,21 @@ namespace System.Security.AccessControl [SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)] [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - internal FileSecurity( SafeFileHandle handle, String fullPath, AccessControlSections includeSections ) - : base( false, handle, includeSections, false ) + internal FileSecurity(SafeFileHandle handle, string fullPath, AccessControlSections includeSections) + : base(false, handle, includeSections, false) { if (fullPath != null) - new FileIOPermission(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath).Demand(); + FileIOPermission.QuickDemand(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath); else - new FileIOPermission(PermissionState.Unrestricted).Demand(); + FileIOPermission.QuickDemand(PermissionState.Unrestricted); } - - #endregion } - public sealed class DirectorySecurity : FileSystemSecurity { - #region Constructors - [System.Security.SecuritySafeCritical] // auto-generated public DirectorySecurity() - : base( true ) + : base(true) { } @@ -681,14 +674,12 @@ namespace System.Security.AccessControl [SecurityPermission(SecurityAction.Assert, UnmanagedCode=true)] [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - public DirectorySecurity( String name, AccessControlSections includeSections ) - : base( true, name, includeSections, true ) + public DirectorySecurity(string name, AccessControlSections includeSections) + : base(true, name, includeSections, true) { - String fullPath = Path.GetFullPathInternal(name); - new FileIOPermission(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath).Demand(); + string fullPath = Path.GetFullPathInternal(name); + FileIOPermission.QuickDemand(FileIOPermissionAccess.NoAccess, AccessControlActions.View, fullPath, checkForDuplicates: false, needFullPath: false); } - - #endregion } } diff --git a/mcs/class/referencesource/mscorlib/system/security/claims/ClaimsIdentity.cs b/mcs/class/referencesource/mscorlib/system/security/claims/ClaimsIdentity.cs index 5b8627cd9b0..5f3a25e79b7 100644 --- a/mcs/class/referencesource/mscorlib/system/security/claims/ClaimsIdentity.cs +++ b/mcs/class/referencesource/mscorlib/system/security/claims/ClaimsIdentity.cs @@ -315,7 +315,14 @@ namespace System.Security.Claims // if(!IsCircular(claimsIdentity.Actor)) { - m_actor = claimsIdentity.Actor; + if (!AppContextSwitches.SetActorAsReferenceWhenCopyingClaimsIdentity) + { + m_actor = claimsIdentity.Actor.Clone(); + } + else + { + m_actor = claimsIdentity.Actor; + } } else { @@ -334,6 +341,10 @@ namespace System.Security.Claims else SafeAddClaims(claimsIdentity.m_instanceClaims); + if (claimsIdentity.m_userSerializationData != null) + { + m_userSerializationData = claimsIdentity.m_userSerializationData.Clone() as byte[]; + } } else { @@ -594,7 +605,14 @@ namespace System.Security.Claims // the Actor property and so not really needed here. But checking just for sanity sake if(!IsCircular(this.Actor)) { - newIdentity.Actor = this.Actor; + if (!AppContextSwitches.SetActorAsReferenceWhenCopyingClaimsIdentity) + { + newIdentity.Actor = this.Actor.Clone(); + } + else + { + newIdentity.Actor = this.Actor; + } } else { @@ -945,6 +963,7 @@ namespace System.Security.Claims return; m_instanceClaims = new List(); + m_externalClaims = new Collection>(); } diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/cryptoconfig.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/cryptoconfig.cs index 7d3eb777e42..667369d2dd6 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/cryptoconfig.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/cryptoconfig.cs @@ -122,6 +122,7 @@ namespace System.Security.Cryptography { #endif //FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO #if FEATURE_CRYPTO ht.Add("System.Security.Cryptography.SHA1CryptoServiceProvider", Constants.OID_OIWSEC_SHA1); + ht.Add("System.Security.Cryptography.SHA1Cng", Constants.OID_OIWSEC_SHA1); #endif //FEATURE_CRYPTO #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO ht.Add("System.Security.Cryptography.SHA1Managed", Constants.OID_OIWSEC_SHA1); @@ -174,13 +175,6 @@ namespace System.Security.Cryptography { #if FEATURE_CRYPTO Type SHA1CryptoServiceProviderType = typeof(System.Security.Cryptography.SHA1CryptoServiceProvider); Type MD5CryptoServiceProviderType = typeof(System.Security.Cryptography.MD5CryptoServiceProvider); -#endif //FEATURE_CRYPTO -#if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO - Type SHA256ManagedType = typeof(SHA256Managed); -#endif //FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO -#if FEATURE_CRYPTO - Type SHA384ManagedType = typeof(SHA384Managed); - Type SHA512ManagedType = typeof(SHA512Managed); Type RIPEMD160ManagedType = typeof(System.Security.Cryptography.RIPEMD160Managed); Type HMACMD5Type = typeof(System.Security.Cryptography.HMACMD5); Type HMACRIPEMD160Type = typeof(System.Security.Cryptography.HMACRIPEMD160); @@ -209,6 +203,9 @@ namespace System.Security.Cryptography { #if FEATURE_CRYPTO Type DSASignatureDescriptionType = typeof(System.Security.Cryptography.DSASignatureDescription); Type RSAPKCS1SHA1SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA1SignatureDescription); + Type RSAPKCS1SHA256SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA256SignatureDescription); + Type RSAPKCS1SHA384SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA384SignatureDescription); + Type RSAPKCS1SHA512SignatureDescriptionType = typeof(System.Security.Cryptography.RSAPKCS1SHA512SignatureDescription); #endif //FEATURE_CRYPTO #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO Type RNGCryptoServiceProviderType = typeof(System.Security.Cryptography.RNGCryptoServiceProvider); @@ -233,11 +230,26 @@ namespace System.Security.Cryptography { string SHA384CryptoSerivceProviderType = "System.Security.Cryptography.SHA384CryptoServiceProvider, " + AssemblyRef.SystemCore; string SHA512CngType = "System.Security.Cryptography.SHA512Cng, " + AssemblyRef.SystemCore; string SHA512CryptoServiceProviderType = "System.Security.Cryptography.SHA512CryptoServiceProvider, " + AssemblyRef.SystemCore; +#endif //FEATURE_CRYPTO + + +#if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO + bool fipsOnly = AllowOnlyFipsAlgorithms; + object SHA256DefaultType = typeof(SHA256Managed); +#endif //FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO + +#if FEATURE_CRYPTO + if (fipsOnly) + { + SHA256DefaultType = SHA256CngType; + } + object SHA384DefaultType = fipsOnly ? (object)SHA384CngType : (object)typeof(SHA384Managed); + object SHA512DefaultType = fipsOnly ? (object)SHA512CngType : (object)typeof(SHA512Managed); // Cryptography algorithms in System.Security string DpapiDataProtectorType = "System.Security.Cryptography.DpapiDataProtector, " + AssemblyRef.SystemSecurity; - #endif //FEATURE_CRYPTO + #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO // Random number generator ht.Add("RandomNumberGenerator", RNGCryptoServiceProviderType); @@ -256,21 +268,21 @@ namespace System.Security.Cryptography { ht.Add("System.Security.Cryptography.MD5Cng", MD5CngType); #endif //FEATURE_CRYPTO #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO - ht.Add("SHA256", SHA256ManagedType); - ht.Add("SHA-256", SHA256ManagedType); - ht.Add("System.Security.Cryptography.SHA256", SHA256ManagedType); + ht.Add("SHA256", SHA256DefaultType); + ht.Add("SHA-256", SHA256DefaultType); + ht.Add("System.Security.Cryptography.SHA256", SHA256DefaultType); #endif //FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO #if FEATURE_CRYPTO ht.Add("System.Security.Cryptography.SHA256Cng", SHA256CngType); ht.Add("System.Security.Cryptography.SHA256CryptoServiceProvider", SHA256CryptoServiceProviderType); - ht.Add("SHA384", SHA384ManagedType); - ht.Add("SHA-384", SHA384ManagedType); - ht.Add("System.Security.Cryptography.SHA384", SHA384ManagedType); + ht.Add("SHA384", SHA384DefaultType); + ht.Add("SHA-384", SHA384DefaultType); + ht.Add("System.Security.Cryptography.SHA384", SHA384DefaultType); ht.Add("System.Security.Cryptography.SHA384Cng", SHA384CngType); ht.Add("System.Security.Cryptography.SHA384CryptoServiceProvider", SHA384CryptoSerivceProviderType); - ht.Add("SHA512", SHA512ManagedType); - ht.Add("SHA-512", SHA512ManagedType); - ht.Add("System.Security.Cryptography.SHA512", SHA512ManagedType); + ht.Add("SHA512", SHA512DefaultType); + ht.Add("SHA-512", SHA512DefaultType); + ht.Add("System.Security.Cryptography.SHA512", SHA512DefaultType); ht.Add("System.Security.Cryptography.SHA512Cng", SHA512CngType); ht.Add("System.Security.Cryptography.SHA512CryptoServiceProvider", SHA512CryptoServiceProviderType); ht.Add("RIPEMD160", RIPEMD160ManagedType); @@ -357,16 +369,19 @@ namespace System.Security.Cryptography { ht.Add("System.Security.Cryptography.DSASignatureDescription", DSASignatureDescriptionType); ht.Add("http://www.w3.org/2000/09/xmldsig#rsa-sha1", RSAPKCS1SHA1SignatureDescriptionType); ht.Add("System.Security.Cryptography.RSASignatureDescription", RSAPKCS1SHA1SignatureDescriptionType); + ht.Add("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", RSAPKCS1SHA256SignatureDescriptionType); + ht.Add("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", RSAPKCS1SHA384SignatureDescriptionType); + ht.Add("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", RSAPKCS1SHA512SignatureDescriptionType); // Xml Dsig/Enc Hash algorithms ht.Add("http://www.w3.org/2000/09/xmldsig#sha1", SHA1CryptoServiceProviderType); // Add the other hash algorithms introduced with XML Encryption #endif //FEATURE_CRYPTO #if FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO - ht.Add("http://www.w3.org/2001/04/xmlenc#sha256", SHA256ManagedType); + ht.Add("http://www.w3.org/2001/04/xmlenc#sha256", SHA256DefaultType); #endif //FEATURE_CRYPTO || FEATURE_LEGACYNETCFCRYPTO #if FEATURE_CRYPTO && !FEATURE_CORECLR - ht.Add("http://www.w3.org/2001/04/xmlenc#sha512", SHA512ManagedType); + ht.Add("http://www.w3.org/2001/04/xmlenc#sha512", SHA512DefaultType); ht.Add("http://www.w3.org/2001/04/xmlenc#ripemd160", RIPEMD160ManagedType); // Xml Encryption symmetric keys @@ -421,7 +436,7 @@ namespace System.Security.Cryptography { // Xml Dsig-more Uri's as defined in http://www.ietf.org/rfc/rfc4051.txt ht.Add("http://www.w3.org/2001/04/xmldsig-more#md5", MD5CryptoServiceProviderType); - ht.Add("http://www.w3.org/2001/04/xmldsig-more#sha384", SHA384ManagedType); + ht.Add("http://www.w3.org/2001/04/xmldsig-more#sha384", SHA384DefaultType); ht.Add("http://www.w3.org/2001/04/xmldsig-more#hmac-md5", HMACMD5Type); ht.Add("http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160", HMACRIPEMD160Type); #endif //FEATURE_CRYPTO diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/dsa.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/dsa.cs index 51f9a9ae4cc..af2db6e5303 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/dsa.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/dsa.cs @@ -15,6 +15,7 @@ namespace System.Security.Cryptography { using System.Runtime.Serialization; using System.Security.Util; using System.Globalization; + using System.IO; using System.Diagnostics.Contracts; // DSAParameters is serializable so that one could pass the public parameters @@ -63,10 +64,78 @@ namespace System.Security.Cryptography { return (DSA) CryptoConfig.CreateFromName(algName); } + // DSA does not encode the algorithm identifier into the signature blob, therefore CreateSignature and + // VerifySignature do not need the HashAlgorithmName value, only SignData and VerifyData do. abstract public byte[] CreateSignature(byte[] rgbHash); abstract public bool VerifySignature(byte[] rgbHash, byte[] rgbSignature); + protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) + { + throw DerivedClassMustOverride(); + } + + protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) + { + throw DerivedClassMustOverride(); + } + + public byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm) + { + if (data == null) { throw new ArgumentNullException("data"); } + + return SignData(data, 0, data.Length, hashAlgorithm); + } + + public virtual byte[] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) + { + if (data == null) { throw new ArgumentNullException("data"); } + if (offset < 0 || offset > data.Length) { throw new ArgumentOutOfRangeException("offset"); } + if (count < 0 || count > data.Length - offset) { throw new ArgumentOutOfRangeException("count"); } + if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } + + byte[] hash = HashData(data, offset, count, hashAlgorithm); + return CreateSignature(hash); + } + + public virtual byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm) + { + if (data == null) { throw new ArgumentNullException("data"); } + if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } + + byte[] hash = HashData(data, hashAlgorithm); + return CreateSignature(hash); + } + + public bool VerifyData(byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm) + { + if (data == null) { throw new ArgumentNullException("data"); } + + return VerifyData(data, 0, data.Length, signature, hashAlgorithm); + } + + public virtual bool VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm) + { + if (data == null) { throw new ArgumentNullException("data"); } + if (offset < 0 || offset > data.Length) { throw new ArgumentOutOfRangeException("offset"); } + if (count < 0 || count > data.Length - offset) { throw new ArgumentOutOfRangeException("count"); } + if (signature == null) { throw new ArgumentNullException("signature"); } + if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } + + byte[] hash = HashData(data, offset, count, hashAlgorithm); + return VerifySignature(hash, signature); + } + + public virtual bool VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithm) + { + if (data == null) { throw new ArgumentNullException("data"); } + if (signature == null) { throw new ArgumentNullException("signature"); } + if (String.IsNullOrEmpty(hashAlgorithm.Name)) { throw HashAlgorithmNameNullOrEmpty(); } + + byte[] hash = HashData(data, hashAlgorithm); + return VerifySignature(hash, signature); + } + // We can provide a default implementation of FromXmlString because we require // every DSA implementation to implement ImportParameters // All we have to do here is parse the XML. @@ -187,5 +256,15 @@ namespace System.Security.Cryptography { abstract public DSAParameters ExportParameters(bool includePrivateParameters); abstract public void ImportParameters(DSAParameters parameters); + + private static Exception DerivedClassMustOverride() + { + return new NotImplementedException(Environment.GetResourceString("NotSupported_SubclassOverride")); + } + + internal static Exception HashAlgorithmNameNullOrEmpty() + { + return new ArgumentException(Environment.GetResourceString("Cryptography_HashAlgorithmNameNullOrEmpty"), "hashAlgorithm"); + } } } diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/dsacryptoserviceprovider.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/dsacryptoserviceprovider.cs index 318b09813ab..df23a26af10 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/dsacryptoserviceprovider.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/dsacryptoserviceprovider.cs @@ -268,6 +268,36 @@ namespace System.Security.Cryptography { return VerifyHash(rgbHash, null, rgbSignature); } + protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) + { + // we're sealed and the base should have checked this before calling us + Contract.Assert(data != null); + Contract.Assert(offset >= 0 && offset <= data.Length); + Contract.Assert(count >= 0 && count <= data.Length - offset); + Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name)); + + if (hashAlgorithm != HashAlgorithmName.SHA1) + { + throw new CryptographicException(Environment.GetResourceString("Cryptography_UnknownHashAlgorithm", hashAlgorithm.Name)); + } + + return _sha1.ComputeHash(data, offset, count); + } + + protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) + { + // we're sealed and the base should have checked this before calling us + Contract.Assert(data != null); + Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name)); + + if (hashAlgorithm != HashAlgorithmName.SHA1) + { + throw new CryptographicException(Environment.GetResourceString("Cryptography_UnknownHashAlgorithm", hashAlgorithm.Name)); + } + + return _sha1.ComputeHash(data); + } + [System.Security.SecuritySafeCritical] // auto-generated public byte[] SignHash(byte[] rgbHash, string str) { if (rgbHash == null) diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsacryptoserviceprovider.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsacryptoserviceprovider.cs index 0bf87db770e..09548184559 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsacryptoserviceprovider.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsacryptoserviceprovider.cs @@ -37,9 +37,10 @@ namespace System.Security.Cryptography { } [System.Runtime.InteropServices.ComVisible(true)] - public sealed class RSACryptoServiceProvider : RSA + public sealed partial class RSACryptoServiceProvider : RSA , ICspAsymmetricAlgorithm { +#if !MONO private int _dwKeySize; private CspParameters _parameters; private bool _randomKeyContainer; @@ -47,13 +48,13 @@ namespace System.Security.Cryptography { private SafeProvHandle _safeProvHandle; [System.Security.SecurityCritical] // auto-generated private SafeKeyHandle _safeKeyHandle; - +#endif private static volatile CspProviderFlags s_UseMachineKeyStore = 0; // // QCalls // - +#if !MONO [System.Security.SecurityCritical] // auto-generated [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)] [ResourceExposure(ResourceScope.None)] @@ -194,7 +195,7 @@ namespace System.Security.Cryptography { return null; } } - +#endif public override string SignatureAlgorithm { get { return "http://www.w3.org/2000/09/xmldsig#rsa-sha1"; } } @@ -203,7 +204,7 @@ namespace System.Security.Cryptography { get { return (s_UseMachineKeyStore == CspProviderFlags.UseMachineKeyStore); } set { s_UseMachineKeyStore = (value ? CspProviderFlags.UseMachineKeyStore : 0); } } - +#if !MONO public bool PersistKeyInCsp { [System.Security.SecuritySafeCritical] // auto-generated get { @@ -502,7 +503,7 @@ namespace System.Security.Cryptography { private static bool IsPublic(RSAParameters rsaParams) { return (rsaParams.P == null); } - +#endif // // Adapt new RSA abstraction to legacy RSACryptoServiceProvider surface area. // @@ -524,10 +525,14 @@ namespace System.Security.Cryptography { Contract.Assert(count >= 0 && count <= data.Length); Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name)); +#if MONO + throw new NotImplementedException (); +#else using (SafeHashHandle hashHandle = Utils.CreateHash(Utils.StaticProvHandle, GetAlgorithmId(hashAlgorithm))) { Utils.HashData(hashHandle, data, offset, count); return Utils.EndHash(hashHandle); } +#endif } [SecuritySafeCritical] @@ -536,6 +541,9 @@ namespace System.Security.Cryptography { Contract.Assert(data != null); Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name)); +#if MONO + throw new NotImplementedException (); +#else using (SafeHashHandle hashHandle = Utils.CreateHash(Utils.StaticProvHandle, GetAlgorithmId(hashAlgorithm))) { // Read the data 4KB at a time, providing similar read characteristics to a standard HashAlgorithm byte[] buffer = new byte[4096]; @@ -549,6 +557,7 @@ namespace System.Security.Cryptography { return Utils.EndHash(hashHandle); } +#endif } private static int GetAlgorithmId(HashAlgorithmName hashAlgorithm) { diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangedeformatter.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangedeformatter.cs index 416b29f5079..674cdf23f61 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangedeformatter.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangedeformatter.cs @@ -11,6 +11,7 @@ namespace System.Security.Cryptography { [System.Runtime.InteropServices.ComVisible(true)] public class RSAOAEPKeyExchangeDeformatter : AsymmetricKeyExchangeDeformatter { private RSA _rsaKey; // RSA Key value to do decrypt operation + private bool? _rsaOverridesDecrypt; // // public constructors @@ -42,8 +43,8 @@ namespace System.Security.Cryptography { if (_rsaKey == null) throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_MissingKey")); - if (_rsaKey is RSACryptoServiceProvider) { - return ((RSACryptoServiceProvider) _rsaKey).Decrypt(rgbData, true); + if (OverridesDecrypt) { + return _rsaKey.Decrypt(rgbData, RSAEncryptionPadding.OaepSHA1); } else { return Utils.RsaOaepDecrypt(_rsaKey, SHA1.Create(), new PKCS1MaskGenerationMethod(), rgbData); } @@ -54,6 +55,16 @@ namespace System.Security.Cryptography { throw new ArgumentNullException("key"); Contract.EndContractBlock(); _rsaKey = (RSA) key; + _rsaOverridesDecrypt = default(bool?); + } + + private bool OverridesDecrypt { + get { + if (!_rsaOverridesDecrypt.HasValue) { + _rsaOverridesDecrypt = Utils.DoesRsaKeyOverride(_rsaKey, "Decrypt", new Type[] { typeof(byte[]), typeof(RSAEncryptionPadding) }); + } + return _rsaOverridesDecrypt.Value; + } } } } diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangeformatter.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangeformatter.cs index 68746fe1773..a931c154cde 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangeformatter.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsaoaepkeyexchangeformatter.cs @@ -12,6 +12,7 @@ namespace System.Security.Cryptography { public class RSAOAEPKeyExchangeFormatter : AsymmetricKeyExchangeFormatter { private byte[] ParameterValue; private RSA _rsaKey; + private bool? _rsaOverridesEncrypt; private RandomNumberGenerator RngValue; // @@ -64,6 +65,7 @@ namespace System.Security.Cryptography { throw new ArgumentNullException("key"); Contract.EndContractBlock(); _rsaKey = (RSA) key; + _rsaOverridesEncrypt = default(bool?); } [System.Security.SecuritySafeCritical] // auto-generated @@ -71,8 +73,8 @@ namespace System.Security.Cryptography { if (_rsaKey == null) throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_MissingKey")); - if (_rsaKey is RSACryptoServiceProvider) { - return ((RSACryptoServiceProvider) _rsaKey).Encrypt(rgbData, true); + if (OverridesEncrypt) { + return _rsaKey.Encrypt(rgbData, RSAEncryptionPadding.OaepSHA1); } else { return Utils.RsaOaepEncrypt(_rsaKey, SHA1.Create(), new PKCS1MaskGenerationMethod(), RandomNumberGenerator.Create(), rgbData); } @@ -81,5 +83,14 @@ namespace System.Security.Cryptography { public override byte[] CreateKeyExchange(byte[] rgbData, Type symAlgType) { return CreateKeyExchange(rgbData); } + + private bool OverridesEncrypt { + get { + if (!_rsaOverridesEncrypt.HasValue) { + _rsaOverridesEncrypt = Utils.DoesRsaKeyOverride(_rsaKey, "Encrypt", new Type[] { typeof(byte[]), typeof(RSAEncryptionPadding) }); + } + return _rsaOverridesEncrypt.Value; + } + } } } diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1keyexchangedeformatter.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1keyexchangedeformatter.cs index ed412c64dba..ccd8570ada5 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1keyexchangedeformatter.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1keyexchangedeformatter.cs @@ -11,6 +11,7 @@ namespace System.Security.Cryptography { [System.Runtime.InteropServices.ComVisible(true)] public class RSAPKCS1KeyExchangeDeformatter : AsymmetricKeyExchangeDeformatter { RSA _rsaKey; + bool? _rsaOverridesDecrypt; RandomNumberGenerator RngValue; // Constructors @@ -47,8 +48,8 @@ namespace System.Security.Cryptography { throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_MissingKey")); byte[] rgbOut; - if (_rsaKey is RSACryptoServiceProvider) { - rgbOut = ((RSACryptoServiceProvider) _rsaKey).Decrypt(rgbIn, false); + if (OverridesDecrypt) { + rgbOut = _rsaKey.Decrypt(rgbIn, RSAEncryptionPadding.Pkcs1); } else { int i; @@ -83,6 +84,16 @@ namespace System.Security.Cryptography { throw new ArgumentNullException("key"); Contract.EndContractBlock(); _rsaKey = (RSA) key; + _rsaOverridesDecrypt = default(bool?); + } + + private bool OverridesDecrypt { + get { + if (!_rsaOverridesDecrypt.HasValue) { + _rsaOverridesDecrypt = Utils.DoesRsaKeyOverride(_rsaKey, "Decrypt", new Type[] { typeof(byte[]), typeof(RSAEncryptionPadding) }); + } + return _rsaOverridesDecrypt.Value; + } } } } diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1keyexchangeformatter.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1keyexchangeformatter.cs index 19f34b6d6fb..188e55ce1c4 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1keyexchangeformatter.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1keyexchangeformatter.cs @@ -14,6 +14,7 @@ namespace System.Security.Cryptography { public class RSAPKCS1KeyExchangeFormatter : AsymmetricKeyExchangeFormatter { RandomNumberGenerator RngValue; RSA _rsaKey; + bool? _rsaOverridesEncrypt; // // public constructors @@ -50,6 +51,7 @@ namespace System.Security.Cryptography { throw new ArgumentNullException("key"); Contract.EndContractBlock(); _rsaKey = (RSA) key; + _rsaOverridesEncrypt = default(bool?); } public override byte[] CreateKeyExchange(byte[] rgbData) { @@ -62,8 +64,8 @@ namespace System.Security.Cryptography { throw new CryptographicUnexpectedOperationException(Environment.GetResourceString("Cryptography_MissingKey")); byte[] rgbKeyEx; - if (_rsaKey is RSACryptoServiceProvider) { - rgbKeyEx = ((RSACryptoServiceProvider) _rsaKey).Encrypt(rgbData, false); + if (OverridesEncrypt) { + rgbKeyEx = _rsaKey.Encrypt(rgbData, RSAEncryptionPadding.Pkcs1); } else { int cb = _rsaKey.KeySize/8; @@ -101,5 +103,14 @@ namespace System.Security.Cryptography { public override byte[] CreateKeyExchange(byte[] rgbData, Type symAlgType) { return CreateKeyExchange(rgbData); } + + private bool OverridesEncrypt { + get { + if (!_rsaOverridesEncrypt.HasValue) { + _rsaOverridesEncrypt = Utils.DoesRsaKeyOverride(_rsaKey, "Encrypt", new Type[] { typeof(byte[]), typeof(RSAEncryptionPadding) }); + } + return _rsaOverridesEncrypt.Value; + } + } } } diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1signaturedeformatter.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1signaturedeformatter.cs index 01363fefbdd..28ee8738639 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1signaturedeformatter.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1signaturedeformatter.cs @@ -27,6 +27,7 @@ namespace System.Security.Cryptography { private RSA _rsaKey; // RSA Key value to do decrypt operation private String _strOID; // OID value for the HASH algorithm + private bool? _rsaOverridesVerifyHash; // // public constructors @@ -49,6 +50,7 @@ namespace System.Security.Cryptography { throw new ArgumentNullException("key"); Contract.EndContractBlock(); _rsaKey = (RSA) key; + _rsaOverridesVerifyHash = default(bool?); } public override void SetHashAlgorithm(String strName) { @@ -70,15 +72,32 @@ namespace System.Security.Cryptography { // Two cases here -- if we are talking to the CSP version or if we are talking to some other RSA provider. if (_rsaKey is RSACryptoServiceProvider) { + // This path is kept around for desktop compat: in case someone is using this with a hash algorithm that's known to GetAlgIdFromOid but + // not from OidToHashAlgorithmName. int calgHash = X509Utils.GetAlgIdFromOid(_strOID, OidGroup.HashAlgorithm); return ((RSACryptoServiceProvider)_rsaKey).VerifyHash(rgbHash, calgHash, rgbSignature); } + else if (OverridesVerifyHash) { + HashAlgorithmName hashAlgorithmName = Utils.OidToHashAlgorithmName(_strOID); + return _rsaKey.VerifyHash(rgbHash, rgbSignature, hashAlgorithmName, RSASignaturePadding.Pkcs1); + } else { + // Fallback compat path for 3rd-party RSA classes that don't override VerifyHash() + byte[] pad = Utils.RsaPkcs1Padding(_rsaKey, CryptoConfig.EncodeOID(_strOID), rgbHash); // Apply the public key to the signature data to get back the padded buffer actually signed. // Compare the two buffers to see if they match; ignoring any leading zeros return Utils.CompareBigIntArrays(_rsaKey.EncryptValue(rgbSignature), pad); } } + + private bool OverridesVerifyHash { + get { + if (!_rsaOverridesVerifyHash.HasValue) { + _rsaOverridesVerifyHash = Utils.DoesRsaKeyOverride(_rsaKey, "VerifyHash", new Type[] { typeof(byte[]), typeof(byte[]), typeof(HashAlgorithmName), typeof(RSASignaturePadding) }); + } + return _rsaOverridesVerifyHash.Value; + } + } } } diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1signatureformatter.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1signatureformatter.cs index 249ea4b072c..97912425610 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1signatureformatter.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/rsapkcs1signatureformatter.cs @@ -19,6 +19,7 @@ namespace System.Security.Cryptography { public class RSAPKCS1SignatureFormatter : AsymmetricSignatureFormatter { private RSA _rsaKey; private String _strOID; + private bool? _rsaOverridesSignHash; // // public constructors @@ -42,6 +43,7 @@ namespace System.Security.Cryptography { throw new ArgumentNullException("key"); Contract.EndContractBlock(); _rsaKey = (RSA) key; + _rsaOverridesSignHash = default(bool?); } public override void SetHashAlgorithm(String strName) { @@ -61,14 +63,31 @@ namespace System.Security.Cryptography { // Two cases here -- if we are talking to the CSP version or if we are talking to some other RSA provider. if (_rsaKey is RSACryptoServiceProvider) { + // This path is kept around for desktop compat: in case someone is using this with a hash algorithm that's known to GetAlgIdFromOid but + // not from OidToHashAlgorithmName. int calgHash = X509Utils.GetAlgIdFromOid(_strOID, OidGroup.HashAlgorithm); return ((RSACryptoServiceProvider)_rsaKey).SignHash(rgbHash, calgHash); } + else if (OverridesSignHash) { + HashAlgorithmName hashAlgorithmName = Utils.OidToHashAlgorithmName(_strOID); + return _rsaKey.SignHash(rgbHash, hashAlgorithmName, RSASignaturePadding.Pkcs1); + } else { + // Fallback compat path for 3rd-party RSA classes that don't override SignHash() + byte[] pad = Utils.RsaPkcs1Padding(_rsaKey, CryptoConfig.EncodeOID(_strOID), rgbHash); // Create the signature by applying the private key to the padded buffer we just created. return _rsaKey.DecryptValue(pad); } } + + private bool OverridesSignHash { + get { + if (!_rsaOverridesSignHash.HasValue) { + _rsaOverridesSignHash = Utils.DoesRsaKeyOverride(_rsaKey, "SignHash", new Type[] { typeof(byte[]), typeof(HashAlgorithmName), typeof(RSASignaturePadding) }); + } + return _rsaOverridesSignHash.Value; + } + } } } diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/signaturedescription.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/signaturedescription.cs index f115e8afc39..330a0222f09 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/signaturedescription.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/signaturedescription.cs @@ -83,20 +83,52 @@ namespace System.Security.Cryptography { } } - internal class RSAPKCS1SHA1SignatureDescription : SignatureDescription { - public RSAPKCS1SHA1SignatureDescription() { - KeyAlgorithm = "System.Security.Cryptography.RSACryptoServiceProvider"; - DigestAlgorithm = "System.Security.Cryptography.SHA1CryptoServiceProvider"; + internal abstract class RSAPKCS1SignatureDescription : SignatureDescription { + protected RSAPKCS1SignatureDescription(string hashAlgorithm, string digestAlgorithm) { + KeyAlgorithm = "System.Security.Cryptography.RSA"; + DigestAlgorithm = digestAlgorithm; FormatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureFormatter"; DeformatterAlgorithm = "System.Security.Cryptography.RSAPKCS1SignatureDeformatter"; + _hashAlgorithm = hashAlgorithm; + } + + public sealed override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) { + AsymmetricSignatureDeformatter item = base.CreateDeformatter(key); + item.SetHashAlgorithm(_hashAlgorithm); + return item; } - public override AsymmetricSignatureDeformatter CreateDeformatter(AsymmetricAlgorithm key) { - AsymmetricSignatureDeformatter item = (AsymmetricSignatureDeformatter) CryptoConfig.CreateFromName(DeformatterAlgorithm); - item.SetKey(key); - item.SetHashAlgorithm("SHA1"); + public sealed override AsymmetricSignatureFormatter CreateFormatter(AsymmetricAlgorithm key) { + AsymmetricSignatureFormatter item = base.CreateFormatter(key); + item.SetHashAlgorithm(_hashAlgorithm); return item; } + + private string _hashAlgorithm; + } + + internal class RSAPKCS1SHA1SignatureDescription : RSAPKCS1SignatureDescription { + public RSAPKCS1SHA1SignatureDescription() + : base("SHA1", "System.Security.Cryptography.SHA1Cng") { + } + } + + internal class RSAPKCS1SHA256SignatureDescription : RSAPKCS1SignatureDescription { + public RSAPKCS1SHA256SignatureDescription() + : base("SHA256", "System.Security.Cryptography.SHA256Cng") { + } + } + + internal class RSAPKCS1SHA384SignatureDescription : RSAPKCS1SignatureDescription { + public RSAPKCS1SHA384SignatureDescription() + : base("SHA384", "System.Security.Cryptography.SHA384Cng") { + } + } + + internal class RSAPKCS1SHA512SignatureDescription : RSAPKCS1SignatureDescription { + public RSAPKCS1SHA512SignatureDescription() + : base("SHA512", "System.Security.Cryptography.SHA512Cng") { + } } internal class DSASignatureDescription : SignatureDescription { diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/utils.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/utils.cs index e8a95fc3be9..cc08a62a059 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/utils.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/utils.cs @@ -16,6 +16,7 @@ namespace System.Security.Cryptography { using Microsoft.Win32; using System.IO; + using System.Reflection; using System.Globalization; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -1017,7 +1018,74 @@ namespace System.Security.Cryptography [ResourceExposure(ResourceScope.None)] // Creates a process resource, but it can't be scoped. [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] internal static extern SafeHashHandle CreateHash(SafeProvHandle hProv, int algid); +#endif + internal static HashAlgorithmName OidToHashAlgorithmName(string oid) + { + switch (oid) + { + case Constants.OID_OIWSEC_SHA1: + return HashAlgorithmName.SHA1; + + case Constants.OID_OIWSEC_SHA256: + return HashAlgorithmName.SHA256; + case Constants.OID_OIWSEC_SHA384: + return HashAlgorithmName.SHA384; + + case Constants.OID_OIWSEC_SHA512: + return HashAlgorithmName.SHA512; + + default: + throw new NotSupportedException(); + } + } + + // + // Backward-compat hack for third-party RSA-derived classes: + // + // Because the SignHash()/VerifyHash()/Encrypt()/Decrypt() methods are new on RSA, we may + // encounter older third-party RSA-derived classes that don't override them + // (and if they don't override them, these methods will throw since they are effectively abstract methods that had to declared non-abstract + // for backward compat reasons.) + // + internal static bool DoesRsaKeyOverride(RSA rsaKey, string methodName, Type[] parameterTypes) + { + // A fast-path check for the common cases where we know we implemented the overrides. + Type t = rsaKey.GetType(); + if (rsaKey is RSACryptoServiceProvider) + { +#if DEBUG + // On checked builds, do the slow-path check anyway so it gets exercised. + bool foundOverride = DoesRsaKeyOverrideSlowPath(t, methodName, parameterTypes); + BCLDebug.Assert(foundOverride, "RSACryptoServiceProvider expected to override " + methodName); +#endif + return true; + } + + string fullName = t.FullName; + if (fullName == "System.Security.Cryptography.RSACng") + { +#if DEBUG + // On checked builds, do the slow-path check anyway so it gets exercised. + bool foundOverride = DoesRsaKeyOverrideSlowPath(t, methodName, parameterTypes); + BCLDebug.Assert(foundOverride, "RSACng expected to override " + methodName); +#endif + return true; + } + return DoesRsaKeyOverrideSlowPath(t, methodName, parameterTypes); + } + + private static bool DoesRsaKeyOverrideSlowPath(Type t, string methodName, Type[] parameterTypes) + { + MethodInfo method = t.GetMethod(methodName, BindingFlags.Public | BindingFlags.Instance, null, parameterTypes, null); + BCLDebug.Assert(method != null, "method != null"); + Type declaringType = method.DeclaringType; + if (declaringType == typeof(RSA)) + return false; + + return true; + } +#if !MONO [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.None)] [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode), SuppressUnmanagedCodeSecurity] diff --git a/mcs/class/referencesource/mscorlib/system/security/cryptography/x509certificates/x509utils.cs b/mcs/class/referencesource/mscorlib/system/security/cryptography/x509certificates/x509utils.cs index 23f747c0423..e730084e191 100644 --- a/mcs/class/referencesource/mscorlib/system/security/cryptography/x509certificates/x509utils.cs +++ b/mcs/class/referencesource/mscorlib/system/security/cryptography/x509certificates/x509utils.cs @@ -159,7 +159,7 @@ namespace System.Security.Cryptography.X509Certificates if (group != OidGroup.AllGroups) { IntPtr allGroupOidInfo = CryptFindOIDInfo(keyType, rawKey, OidGroup.AllGroups); if (allGroupOidInfo != IntPtr.Zero) { - return (CRYPT_OID_INFO)Marshal.PtrToStructure(fullOidInfo, typeof(CRYPT_OID_INFO)); + return (CRYPT_OID_INFO)Marshal.PtrToStructure(allGroupOidInfo, typeof(CRYPT_OID_INFO)); } } diff --git a/mcs/class/referencesource/mscorlib/system/security/permissions/fileiopermission.cs b/mcs/class/referencesource/mscorlib/system/security/permissions/fileiopermission.cs index 02ef088b5e6..db35ac502b0 100644 --- a/mcs/class/referencesource/mscorlib/system/security/permissions/fileiopermission.cs +++ b/mcs/class/referencesource/mscorlib/system/security/permissions/fileiopermission.cs @@ -24,9 +24,9 @@ namespace System.Security.Permissions { using System.Runtime.Versioning; using System.Diagnostics.Contracts; -[Serializable] + [Serializable] [Flags] -[System.Runtime.InteropServices.ComVisible(true)] + [System.Runtime.InteropServices.ComVisible(true)] public enum FileIOPermissionAccess { NoAccess = 0x00, @@ -36,9 +36,8 @@ namespace System.Security.Permissions { PathDiscovery = 0x08, AllAccess = 0x0F, } - - -[System.Runtime.InteropServices.ComVisible(true)] + + [System.Runtime.InteropServices.ComVisible(true)] [Serializable] sealed public class FileIOPermission : CodeAccessPermission, IUnrestrictedPermission, IBuiltInPermission { @@ -51,7 +50,7 @@ namespace System.Security.Permissions { [OptionalField(VersionAdded = 2)] private FileIOAccess m_changeAcl; private bool m_unrestricted; - + public FileIOPermission(PermissionState state) { if (state == PermissionState.Unrestricted) @@ -67,91 +66,91 @@ namespace System.Security.Permissions { throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPermissionState")); } } - + [System.Security.SecuritySafeCritical] // auto-generated - public FileIOPermission( FileIOPermissionAccess access, String path ) + public FileIOPermission(FileIOPermissionAccess access, String path) { - VerifyAccess( access ); - + VerifyAccess(access); + String[] pathList = new String[] { path }; - AddPathList( access, pathList, false, true, false ); + AddPathList(access, pathList, false, true, false); } - + [System.Security.SecuritySafeCritical] // auto-generated - public FileIOPermission( FileIOPermissionAccess access, String[] pathList ) + public FileIOPermission(FileIOPermissionAccess access, String[] pathList) { - VerifyAccess( access ); - - AddPathList( access, pathList, false, true, false ); + VerifyAccess(access); + + AddPathList(access, pathList, false, true, false); } #if FEATURE_MACL [System.Security.SecuritySafeCritical] // auto-generated - public FileIOPermission( FileIOPermissionAccess access, AccessControlActions control, String path ) + public FileIOPermission(FileIOPermissionAccess access, AccessControlActions control, String path) { - VerifyAccess( access ); - + VerifyAccess(access); + String[] pathList = new String[] { path }; - AddPathList( access, control, pathList, false, true, false ); + AddPathList(access, control, pathList, false, true, false); } - + [System.Security.SecuritySafeCritical] // auto-generated - public FileIOPermission( FileIOPermissionAccess access, AccessControlActions control, String[] pathList ) - : this( access, control, pathList, true, true ) + public FileIOPermission(FileIOPermissionAccess access, AccessControlActions control, String[] pathList) + : this(access, control, pathList, true, true) { } #endif [System.Security.SecurityCritical] // auto-generated - internal FileIOPermission( FileIOPermissionAccess access, String[] pathList, bool checkForDuplicates, bool needFullPath ) + internal FileIOPermission(FileIOPermissionAccess access, String[] pathList, bool checkForDuplicates, bool needFullPath) { - VerifyAccess( access ); - - AddPathList( access, pathList, checkForDuplicates, needFullPath, true ); + VerifyAccess(access); + + AddPathList(access, pathList, checkForDuplicates, needFullPath, true); } #if FEATURE_MACL [System.Security.SecurityCritical] // auto-generated - internal FileIOPermission( FileIOPermissionAccess access, AccessControlActions control, String[] pathList, bool checkForDuplicates, bool needFullPath ) + internal FileIOPermission(FileIOPermissionAccess access, AccessControlActions control, String[] pathList, bool checkForDuplicates, bool needFullPath) { - VerifyAccess( access ); - - AddPathList( access, control, pathList, checkForDuplicates, needFullPath, true ); + VerifyAccess(access); + + AddPathList(access, control, pathList, checkForDuplicates, needFullPath, true); } #endif - public void SetPathList( FileIOPermissionAccess access, String path ) + public void SetPathList(FileIOPermissionAccess access, String path) { String[] pathList; - if(path == null) - pathList = new String[] {}; + if (path == null) + pathList = new String[] { }; else pathList = new String[] { path }; - SetPathList( access, pathList, false ); + SetPathList(access, pathList, false); } - - public void SetPathList( FileIOPermissionAccess access, String[] pathList ) + + public void SetPathList(FileIOPermissionAccess access, String[] pathList) { - SetPathList( access, pathList, true ); + SetPathList(access, pathList, true); } - internal void SetPathList( FileIOPermissionAccess access, - String[] pathList, bool checkForDuplicates ) + internal void SetPathList(FileIOPermissionAccess access, + String[] pathList, bool checkForDuplicates) { - SetPathList( access, AccessControlActions.None, pathList, checkForDuplicates ); + SetPathList(access, AccessControlActions.None, pathList, checkForDuplicates); } [System.Security.SecuritySafeCritical] // auto-generated - internal void SetPathList( FileIOPermissionAccess access, AccessControlActions control, String[] pathList, bool checkForDuplicates ) + internal void SetPathList(FileIOPermissionAccess access, AccessControlActions control, String[] pathList, bool checkForDuplicates) { - VerifyAccess( access ); - + VerifyAccess(access); + if ((access & FileIOPermissionAccess.Read) != 0) m_read = null; - + if ((access & FileIOPermissionAccess.Write) != 0) m_write = null; - + if ((access & FileIOPermissionAccess.Append) != 0) m_append = null; @@ -168,36 +167,36 @@ namespace System.Security.Permissions { m_viewAcl = null; m_changeAcl = null; #endif - + m_unrestricted = false; #if FEATURE_MACL - AddPathList( access, control, pathList, checkForDuplicates, true, true ); + AddPathList(access, control, pathList, checkForDuplicates, true, true); #else AddPathList( access, pathList, checkForDuplicates, true, true ); #endif } [System.Security.SecuritySafeCritical] // auto-generated - public void AddPathList( FileIOPermissionAccess access, String path ) + public void AddPathList(FileIOPermissionAccess access, String path) { String[] pathList; - if(path == null) - pathList = new String[] {}; + if (path == null) + pathList = new String[] { }; else pathList = new String[] { path }; - AddPathList( access, pathList, false, true, false ); + AddPathList(access, pathList, false, true, false); } [System.Security.SecuritySafeCritical] // auto-generated - public void AddPathList( FileIOPermissionAccess access, String[] pathList ) + public void AddPathList(FileIOPermissionAccess access, String[] pathList) { - AddPathList( access, pathList, true, true, true ); + AddPathList(access, pathList, true, true, true); } [System.Security.SecurityCritical] // auto-generated - internal void AddPathList( FileIOPermissionAccess access, String[] pathListOrig, bool checkForDuplicates, bool needFullPath, bool copyPathList ) + internal void AddPathList(FileIOPermissionAccess access, String[] pathListOrig, bool checkForDuplicates, bool needFullPath, bool copyPathList) { - AddPathList( access, AccessControlActions.None, pathListOrig, checkForDuplicates, needFullPath, copyPathList ); + AddPathList(access, AccessControlActions.None, pathListOrig, checkForDuplicates, needFullPath, copyPathList); } [System.Security.SecurityCritical] // auto-generated @@ -205,65 +204,73 @@ namespace System.Security.Permissions { { if (pathListOrig == null) { - throw new ArgumentNullException( "pathList" ); + throw new ArgumentNullException("pathList"); } if (pathListOrig.Length == 0) { - throw new ArgumentException( Environment.GetResourceString("Argument_EmptyPath" )); + throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath")); } Contract.EndContractBlock(); // @ VerifyAccess(access); - + if (m_unrestricted) return; String[] pathList = pathListOrig; - if(copyPathList) + if (copyPathList) { // Make a copy of pathList (in case its value changes after we check for illegal chars) pathList = new String[pathListOrig.Length]; Array.Copy(pathListOrig, pathList, pathListOrig.Length); } - CheckIllegalCharacters( pathList ); + // If we need the full path the standard illegal characters will be checked in StringExpressionSet. + CheckIllegalCharacters(pathList, onlyCheckExtras: needFullPath); + + // StringExpressionSet will do minor normalization, trimming spaces and replacing alternate + // directory separators. It will make an attemt to expand short file names and will check + // for standard colon placement. + // + // If needFullPath is true it will call NormalizePath- which performs short name expansion + // and does the normal validity checks. ArrayList pathArrayList = StringExpressionSet.CreateListFromExpressions(pathList, needFullPath); - + if ((access & FileIOPermissionAccess.Read) != 0) { if (m_read == null) { m_read = new FileIOAccess(); } - m_read.AddExpressions( pathArrayList, checkForDuplicates); + m_read.AddExpressions(pathArrayList, checkForDuplicates); } - + if ((access & FileIOPermissionAccess.Write) != 0) { if (m_write == null) { m_write = new FileIOAccess(); } - m_write.AddExpressions( pathArrayList, checkForDuplicates); + m_write.AddExpressions(pathArrayList, checkForDuplicates); } - + if ((access & FileIOPermissionAccess.Append) != 0) { if (m_append == null) { m_append = new FileIOAccess(); } - m_append.AddExpressions( pathArrayList, checkForDuplicates); + m_append.AddExpressions(pathArrayList, checkForDuplicates); } if ((access & FileIOPermissionAccess.PathDiscovery) != 0) { if (m_pathDiscovery == null) { - m_pathDiscovery = new FileIOAccess( true ); + m_pathDiscovery = new FileIOAccess(true); } - m_pathDiscovery.AddExpressions( pathArrayList, checkForDuplicates); + m_pathDiscovery.AddExpressions(pathArrayList, checkForDuplicates); } #if FEATURE_MACL @@ -273,7 +280,7 @@ namespace System.Security.Permissions { { m_viewAcl = new FileIOAccess(); } - m_viewAcl.AddExpressions( pathArrayList, checkForDuplicates); + m_viewAcl.AddExpressions(pathArrayList, checkForDuplicates); } if ((control & AccessControlActions.Change) != 0) @@ -282,18 +289,18 @@ namespace System.Security.Permissions { { m_changeAcl = new FileIOAccess(); } - m_changeAcl.AddExpressions( pathArrayList, checkForDuplicates); + m_changeAcl.AddExpressions(pathArrayList, checkForDuplicates); } #endif } - + [SecuritySafeCritical] - public String[] GetPathList( FileIOPermissionAccess access ) + public String[] GetPathList(FileIOPermissionAccess access) { - VerifyAccess( access ); - ExclusiveAccess( access ); - - if (AccessIsSet( access, FileIOPermissionAccess.Read )) + VerifyAccess(access); + ExclusiveAccess(access); + + if (AccessIsSet(access, FileIOPermissionAccess.Read)) { if (m_read == null) { @@ -301,8 +308,8 @@ namespace System.Security.Permissions { } return m_read.ToStringArray(); } - - if (AccessIsSet( access, FileIOPermissionAccess.Write )) + + if (AccessIsSet(access, FileIOPermissionAccess.Write)) { if (m_write == null) { @@ -310,8 +317,8 @@ namespace System.Security.Permissions { } return m_write.ToStringArray(); } - - if (AccessIsSet( access, FileIOPermissionAccess.Append )) + + if (AccessIsSet(access, FileIOPermissionAccess.Append)) { if (m_append == null) { @@ -319,8 +326,8 @@ namespace System.Security.Permissions { } return m_append.ToStringArray(); } - - if (AccessIsSet( access, FileIOPermissionAccess.PathDiscovery )) + + if (AccessIsSet(access, FileIOPermissionAccess.PathDiscovery)) { if (m_pathDiscovery == null) { @@ -330,10 +337,10 @@ namespace System.Security.Permissions { } // not reached - + return null; } - + public FileIOPermissionAccess AllLocalFiles { @@ -341,19 +348,19 @@ namespace System.Security.Permissions { { if (m_unrestricted) return FileIOPermissionAccess.AllAccess; - + FileIOPermissionAccess access = FileIOPermissionAccess.NoAccess; - + if (m_read != null && m_read.AllLocalFiles) { access |= FileIOPermissionAccess.Read; } - + if (m_write != null && m_write.AllLocalFiles) { access |= FileIOPermissionAccess.Write; } - + if (m_append != null && m_append.AllLocalFiles) { access |= FileIOPermissionAccess.Append; @@ -363,17 +370,17 @@ namespace System.Security.Permissions { { access |= FileIOPermissionAccess.PathDiscovery; } - + return access; } - + set { if ((value & FileIOPermissionAccess.Read) != 0) { if (m_read == null) m_read = new FileIOAccess(); - + m_read.AllLocalFiles = true; } else @@ -381,12 +388,12 @@ namespace System.Security.Permissions { if (m_read != null) m_read.AllLocalFiles = false; } - + if ((value & FileIOPermissionAccess.Write) != 0) { if (m_write == null) m_write = new FileIOAccess(); - + m_write.AllLocalFiles = true; } else @@ -394,12 +401,12 @@ namespace System.Security.Permissions { if (m_write != null) m_write.AllLocalFiles = false; } - + if ((value & FileIOPermissionAccess.Append) != 0) { if (m_append == null) m_append = new FileIOAccess(); - + m_append.AllLocalFiles = true; } else @@ -411,8 +418,8 @@ namespace System.Security.Permissions { if ((value & FileIOPermissionAccess.PathDiscovery) != 0) { if (m_pathDiscovery == null) - m_pathDiscovery = new FileIOAccess( true ); - + m_pathDiscovery = new FileIOAccess(true); + m_pathDiscovery.AllLocalFiles = true; } else @@ -423,31 +430,31 @@ namespace System.Security.Permissions { } } - + public FileIOPermissionAccess AllFiles { get { if (m_unrestricted) return FileIOPermissionAccess.AllAccess; - + FileIOPermissionAccess access = FileIOPermissionAccess.NoAccess; - + if (m_read != null && m_read.AllFiles) { access |= FileIOPermissionAccess.Read; } - + if (m_write != null && m_write.AllFiles) { access |= FileIOPermissionAccess.Write; } - + if (m_append != null && m_append.AllFiles) { access |= FileIOPermissionAccess.Append; } - + if (m_pathDiscovery != null && m_pathDiscovery.AllFiles) { access |= FileIOPermissionAccess.PathDiscovery; @@ -455,7 +462,7 @@ namespace System.Security.Permissions { return access; } - + set { if (value == FileIOPermissionAccess.AllAccess) @@ -463,12 +470,12 @@ namespace System.Security.Permissions { m_unrestricted = true; return; } - + if ((value & FileIOPermissionAccess.Read) != 0) { if (m_read == null) m_read = new FileIOAccess(); - + m_read.AllFiles = true; } else @@ -476,12 +483,12 @@ namespace System.Security.Permissions { if (m_read != null) m_read.AllFiles = false; } - + if ((value & FileIOPermissionAccess.Write) != 0) { if (m_write == null) m_write = new FileIOAccess(); - + m_write.AllFiles = true; } else @@ -489,12 +496,12 @@ namespace System.Security.Permissions { if (m_write != null) m_write.AllFiles = false; } - + if ((value & FileIOPermissionAccess.Append) != 0) { if (m_append == null) m_append = new FileIOAccess(); - + m_append.AllFiles = true; } else @@ -506,8 +513,8 @@ namespace System.Security.Permissions { if ((value & FileIOPermissionAccess.PathDiscovery) != 0) { if (m_pathDiscovery == null) - m_pathDiscovery = new FileIOAccess( true ); - + m_pathDiscovery = new FileIOAccess(true); + m_pathDiscovery.AllFiles = true; } else @@ -517,42 +524,70 @@ namespace System.Security.Permissions { } } - } - + } + [Pure] - private static void VerifyAccess( FileIOPermissionAccess access ) + private static void VerifyAccess(FileIOPermissionAccess access) { if ((access & ~FileIOPermissionAccess.AllAccess) != 0) throw new ArgumentException(Environment.GetResourceString("Arg_EnumIllegalVal", (int)access)); } - + [Pure] - private static void ExclusiveAccess( FileIOPermissionAccess access ) + private static void ExclusiveAccess(FileIOPermissionAccess access) { if (access == FileIOPermissionAccess.NoAccess) { - throw new ArgumentException( Environment.GetResourceString("Arg_EnumNotSingleFlag") ); + throw new ArgumentException(Environment.GetResourceString("Arg_EnumNotSingleFlag")); } - - if (((int) access & ((int)access-1)) != 0) + + if (((int)access & ((int)access - 1)) != 0) { - throw new ArgumentException( Environment.GetResourceString("Arg_EnumNotSingleFlag") ); + throw new ArgumentException(Environment.GetResourceString("Arg_EnumNotSingleFlag")); } } - private static void CheckIllegalCharacters( String[] str ) + private static void CheckIllegalCharacters(String[] str, bool onlyCheckExtras) { for (int i = 0; i < str.Length; ++i) { - Path.CheckInvalidPathChars(str[i], true); + // FileIOPermission doesn't allow for normalizing across various volume names. This means "C:\" and + // "\\?\C:\" won't be considered correctly. In addition there are many other aliases for the volume + // besides "C:" such as (in one concrete example) "\\?\Harddisk0Partition2\", "\\?\HarddiskVolume6\", + // "\\?\Volume{d1655348-0000-0000-0000-f01500000000}\", etc. + // + // We'll continue to explicitly block extended syntax here by disallowing wildcards no matter where + // they occur in the string (e.g. \\?\ isn't ok) + if (CheckExtraPathCharacters(str[i])) + throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars")); + + if (!onlyCheckExtras) + Path.CheckInvalidPathChars(str[i]); } } - private static bool AccessIsSet( FileIOPermissionAccess access, FileIOPermissionAccess question ) + /// + /// Check for ?,* and null, ignoring extended syntax. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private unsafe static bool CheckExtraPathCharacters(string path) + { + char currentChar; + for (int i = 0; i < path.Length; i++) + { + currentChar = path[i]; + + // We also check for null here as StringExpressionSet will trim it out. (Ensuring we still throw as we always have.) + if (currentChar == '*' || currentChar == '?' || currentChar == '\0') return true; + } + return false; + } + + private static bool AccessIsSet(FileIOPermissionAccess access, FileIOPermissionAccess question) { return (access & question) != 0; } - + private bool IsEmpty() { return (!m_unrestricted && @@ -563,24 +598,24 @@ namespace System.Security.Permissions { (this.m_viewAcl == null || this.m_viewAcl.IsEmpty()) && (this.m_changeAcl == null || this.m_changeAcl.IsEmpty())); } - + //------------------------------------------------------ // // CODEACCESSPERMISSION IMPLEMENTATION // //------------------------------------------------------ - + public bool IsUnrestricted() { return m_unrestricted; } - + //------------------------------------------------------ // // IPERMISSION IMPLEMENTATION // //------------------------------------------------------ - + public override bool IsSubsetOf(IPermission target) { if (target == null) @@ -597,14 +632,14 @@ namespace System.Security.Permissions { else if (this.IsUnrestricted()) return false; else - return ((this.m_read == null || this.m_read.IsSubsetOf( operand.m_read )) && - (this.m_write == null || this.m_write.IsSubsetOf( operand.m_write )) && - (this.m_append == null || this.m_append.IsSubsetOf( operand.m_append )) && - (this.m_pathDiscovery == null || this.m_pathDiscovery.IsSubsetOf( operand.m_pathDiscovery )) && - (this.m_viewAcl == null || this.m_viewAcl.IsSubsetOf( operand.m_viewAcl )) && - (this.m_changeAcl == null || this.m_changeAcl.IsSubsetOf( operand.m_changeAcl ))); + return ((this.m_read == null || this.m_read.IsSubsetOf(operand.m_read)) && + (this.m_write == null || this.m_write.IsSubsetOf(operand.m_write)) && + (this.m_append == null || this.m_append.IsSubsetOf(operand.m_append)) && + (this.m_pathDiscovery == null || this.m_pathDiscovery.IsSubsetOf(operand.m_pathDiscovery)) && + (this.m_viewAcl == null || this.m_viewAcl.IsSubsetOf(operand.m_viewAcl)) && + (this.m_changeAcl == null || this.m_changeAcl.IsSubsetOf(operand.m_changeAcl))); } - + public override IPermission Intersect(IPermission target) { if (target == null) @@ -622,18 +657,18 @@ namespace System.Security.Permissions { { return target.Copy(); } - + if (operand.IsUnrestricted()) { return this.Copy(); } - - FileIOAccess intersectRead = this.m_read == null ? null : this.m_read.Intersect( operand.m_read ); - FileIOAccess intersectWrite = this.m_write == null ? null : this.m_write.Intersect( operand.m_write ); - FileIOAccess intersectAppend = this.m_append == null ? null : this.m_append.Intersect( operand.m_append ); - FileIOAccess intersectPathDiscovery = this.m_pathDiscovery == null ? null : this.m_pathDiscovery.Intersect( operand.m_pathDiscovery ); - FileIOAccess intersectViewAcl = this.m_viewAcl == null ? null : this.m_viewAcl.Intersect( operand.m_viewAcl ); - FileIOAccess intersectChangeAcl = this.m_changeAcl == null ? null : this.m_changeAcl.Intersect( operand.m_changeAcl ); + + FileIOAccess intersectRead = this.m_read == null ? null : this.m_read.Intersect(operand.m_read); + FileIOAccess intersectWrite = this.m_write == null ? null : this.m_write.Intersect(operand.m_write); + FileIOAccess intersectAppend = this.m_append == null ? null : this.m_append.Intersect(operand.m_append); + FileIOAccess intersectPathDiscovery = this.m_pathDiscovery == null ? null : this.m_pathDiscovery.Intersect(operand.m_pathDiscovery); + FileIOAccess intersectViewAcl = this.m_viewAcl == null ? null : this.m_viewAcl.Intersect(operand.m_viewAcl); + FileIOAccess intersectChangeAcl = this.m_changeAcl == null ? null : this.m_changeAcl.Intersect(operand.m_changeAcl); if ((intersectRead == null || intersectRead.IsEmpty()) && (intersectWrite == null || intersectWrite.IsEmpty()) && @@ -644,7 +679,7 @@ namespace System.Security.Permissions { { return null; } - + FileIOPermission intersectPermission = new FileIOPermission(PermissionState.None); intersectPermission.m_unrestricted = false; intersectPermission.m_read = intersectRead; @@ -653,10 +688,10 @@ namespace System.Security.Permissions { intersectPermission.m_pathDiscovery = intersectPathDiscovery; intersectPermission.m_viewAcl = intersectViewAcl; intersectPermission.m_changeAcl = intersectChangeAcl; - + return intersectPermission; } - + public override IPermission Union(IPermission other) { if (other == null) @@ -670,19 +705,19 @@ namespace System.Security.Permissions { { throw new ArgumentException(Environment.GetResourceString("Argument_WrongType", this.GetType().FullName)); } - + if (this.IsUnrestricted() || operand.IsUnrestricted()) { - return new FileIOPermission( PermissionState.Unrestricted ); + return new FileIOPermission(PermissionState.Unrestricted); } - - FileIOAccess unionRead = this.m_read == null ? operand.m_read : this.m_read.Union( operand.m_read ); - FileIOAccess unionWrite = this.m_write == null ? operand.m_write : this.m_write.Union( operand.m_write ); - FileIOAccess unionAppend = this.m_append == null ? operand.m_append : this.m_append.Union( operand.m_append ); - FileIOAccess unionPathDiscovery = this.m_pathDiscovery == null ? operand.m_pathDiscovery : this.m_pathDiscovery.Union( operand.m_pathDiscovery ); - FileIOAccess unionViewAcl = this.m_viewAcl == null ? operand.m_viewAcl : this.m_viewAcl.Union( operand.m_viewAcl ); - FileIOAccess unionChangeAcl = this.m_changeAcl == null ? operand.m_changeAcl : this.m_changeAcl.Union( operand.m_changeAcl ); - + + FileIOAccess unionRead = this.m_read == null ? operand.m_read : this.m_read.Union(operand.m_read); + FileIOAccess unionWrite = this.m_write == null ? operand.m_write : this.m_write.Union(operand.m_write); + FileIOAccess unionAppend = this.m_append == null ? operand.m_append : this.m_append.Union(operand.m_append); + FileIOAccess unionPathDiscovery = this.m_pathDiscovery == null ? operand.m_pathDiscovery : this.m_pathDiscovery.Union(operand.m_pathDiscovery); + FileIOAccess unionViewAcl = this.m_viewAcl == null ? operand.m_viewAcl : this.m_viewAcl.Union(operand.m_viewAcl); + FileIOAccess unionChangeAcl = this.m_changeAcl == null ? operand.m_changeAcl : this.m_changeAcl.Union(operand.m_changeAcl); + if ((unionRead == null || unionRead.IsEmpty()) && (unionWrite == null || unionWrite.IsEmpty()) && (unionAppend == null || unionAppend.IsEmpty()) && @@ -692,7 +727,7 @@ namespace System.Security.Permissions { { return null; } - + FileIOPermission unionPermission = new FileIOPermission(PermissionState.None); unionPermission.m_unrestricted = false; unionPermission.m_read = unionRead; @@ -702,9 +737,9 @@ namespace System.Security.Permissions { unionPermission.m_viewAcl = unionViewAcl; unionPermission.m_changeAcl = unionChangeAcl; - return unionPermission; + return unionPermission; } - + public override IPermission Copy() { FileIOPermission copy = new FileIOPermission(PermissionState.None); @@ -740,97 +775,97 @@ namespace System.Security.Permissions { copy.m_changeAcl = this.m_changeAcl.Copy(); } } - return copy; + return copy; } - + #if FEATURE_CAS_POLICY public override SecurityElement ToXml() { - SecurityElement esd = CodeAccessPermission.CreatePermissionElement( this, "System.Security.Permissions.FileIOPermission" ); + SecurityElement esd = CodeAccessPermission.CreatePermissionElement(this, "System.Security.Permissions.FileIOPermission"); if (!IsUnrestricted()) { if (this.m_read != null && !this.m_read.IsEmpty()) { - esd.AddAttribute( "Read", SecurityElement.Escape( m_read.ToString() ) ); + esd.AddAttribute("Read", SecurityElement.Escape(m_read.ToString())); } if (this.m_write != null && !this.m_write.IsEmpty()) { - esd.AddAttribute( "Write", SecurityElement.Escape( m_write.ToString() ) ); + esd.AddAttribute("Write", SecurityElement.Escape(m_write.ToString())); } if (this.m_append != null && !this.m_append.IsEmpty()) { - esd.AddAttribute( "Append", SecurityElement.Escape( m_append.ToString() ) ); + esd.AddAttribute("Append", SecurityElement.Escape(m_append.ToString())); } if (this.m_pathDiscovery != null && !this.m_pathDiscovery.IsEmpty()) { - esd.AddAttribute( "PathDiscovery", SecurityElement.Escape( m_pathDiscovery.ToString() ) ); + esd.AddAttribute("PathDiscovery", SecurityElement.Escape(m_pathDiscovery.ToString())); } if (this.m_viewAcl != null && !this.m_viewAcl.IsEmpty()) { - esd.AddAttribute( "ViewAcl", SecurityElement.Escape( m_viewAcl.ToString() ) ); + esd.AddAttribute("ViewAcl", SecurityElement.Escape(m_viewAcl.ToString())); } if (this.m_changeAcl != null && !this.m_changeAcl.IsEmpty()) { - esd.AddAttribute( "ChangeAcl", SecurityElement.Escape( m_changeAcl.ToString() ) ); + esd.AddAttribute("ChangeAcl", SecurityElement.Escape(m_changeAcl.ToString())); } } else { - esd.AddAttribute( "Unrestricted", "true" ); + esd.AddAttribute("Unrestricted", "true"); } return esd; } - + [System.Security.SecuritySafeCritical] // auto-generated public override void FromXml(SecurityElement esd) { - CodeAccessPermission.ValidateElement( esd, this ); + CodeAccessPermission.ValidateElement(esd, this); String et; - + if (XMLUtil.IsUnrestricted(esd)) { m_unrestricted = true; return; } - - + + m_unrestricted = false; - - et = esd.Attribute( "Read" ); + + et = esd.Attribute("Read"); if (et != null) { - m_read = new FileIOAccess( et ); + m_read = new FileIOAccess(et); } else { m_read = null; } - - et = esd.Attribute( "Write" ); + + et = esd.Attribute("Write"); if (et != null) { - m_write = new FileIOAccess( et ); + m_write = new FileIOAccess(et); } else { m_write = null; } - - et = esd.Attribute( "Append" ); + + et = esd.Attribute("Append"); if (et != null) { - m_append = new FileIOAccess( et ); + m_append = new FileIOAccess(et); } else { m_append = null; } - et = esd.Attribute( "PathDiscovery" ); + et = esd.Attribute("PathDiscovery"); if (et != null) { - m_pathDiscovery = new FileIOAccess( et ); + m_pathDiscovery = new FileIOAccess(et); m_pathDiscovery.PathDiscovery = true; } else @@ -838,20 +873,20 @@ namespace System.Security.Permissions { m_pathDiscovery = null; } - et = esd.Attribute( "ViewAcl" ); + et = esd.Attribute("ViewAcl"); if (et != null) { - m_viewAcl = new FileIOAccess( et ); + m_viewAcl = new FileIOAccess(et); } else { m_viewAcl = null; } - et = esd.Attribute( "ChangeAcl" ); + et = esd.Attribute("ChangeAcl"); if (et != null) { - m_changeAcl = new FileIOAccess( et ); + m_changeAcl = new FileIOAccess(et); } else { @@ -875,60 +910,60 @@ namespace System.Security.Permissions { public override bool Equals(Object obj) { FileIOPermission perm = obj as FileIOPermission; - if(perm == null) + if (perm == null) return false; - if(m_unrestricted && perm.m_unrestricted) + if (m_unrestricted && perm.m_unrestricted) return true; - if(m_unrestricted != perm.m_unrestricted) + if (m_unrestricted != perm.m_unrestricted) return false; - if(m_read == null) + if (m_read == null) { - if(perm.m_read != null && !perm.m_read.IsEmpty()) + if (perm.m_read != null && !perm.m_read.IsEmpty()) return false; } - else if(!m_read.Equals(perm.m_read)) + else if (!m_read.Equals(perm.m_read)) return false; - if(m_write == null) + if (m_write == null) { - if(perm.m_write != null && !perm.m_write.IsEmpty()) - return false; + if (perm.m_write != null && !perm.m_write.IsEmpty()) + return false; } - else if(!m_write.Equals(perm.m_write)) + else if (!m_write.Equals(perm.m_write)) return false; - if(m_append == null) + if (m_append == null) { - if(perm.m_append != null && !perm.m_append.IsEmpty()) - return false; + if (perm.m_append != null && !perm.m_append.IsEmpty()) + return false; } - else if(!m_append.Equals(perm.m_append)) + else if (!m_append.Equals(perm.m_append)) return false; - if(m_pathDiscovery == null) + if (m_pathDiscovery == null) { - if(perm.m_pathDiscovery != null && !perm.m_pathDiscovery.IsEmpty()) - return false; + if (perm.m_pathDiscovery != null && !perm.m_pathDiscovery.IsEmpty()) + return false; } - else if(!m_pathDiscovery.Equals(perm.m_pathDiscovery)) + else if (!m_pathDiscovery.Equals(perm.m_pathDiscovery)) return false; - if(m_viewAcl == null) + if (m_viewAcl == null) { - if(perm.m_viewAcl != null && !perm.m_viewAcl.IsEmpty()) - return false; + if (perm.m_viewAcl != null && !perm.m_viewAcl.IsEmpty()) + return false; } - else if(!m_viewAcl.Equals(perm.m_viewAcl)) + else if (!m_viewAcl.Equals(perm.m_viewAcl)) return false; - if(m_changeAcl == null) + if (m_changeAcl == null) { - if(perm.m_changeAcl != null && !perm.m_changeAcl.IsEmpty()) - return false; + if (perm.m_changeAcl != null && !perm.m_changeAcl.IsEmpty()) + return false; } - else if(!m_changeAcl.Equals(perm.m_changeAcl)) + else if (!m_changeAcl.Equals(perm.m_changeAcl)) return false; return true; @@ -951,12 +986,8 @@ namespace System.Security.Permissions { /// IMPORTANT: This method should only be used after calling GetFullPath on the path to verify /// /// - /// - /// - /// - /// [System.Security.SecuritySafeCritical] - internal static void QuickDemand(FileIOPermissionAccess access, string fullPath, bool checkForDuplicates, bool needFullPath) + internal static void QuickDemand(FileIOPermissionAccess access, string fullPath, bool checkForDuplicates = false, bool needFullPath = true) { if (!CodeAccessSecurityEngine.QuickCheckForAllDemands()) { @@ -964,18 +995,109 @@ namespace System.Security.Permissions { } else { - //Emulate FileIOPermission checks - Path.CheckInvalidPathChars(fullPath, true); + EmulateFileIOPermissionChecks(fullPath); + } + } + + /// + /// Call this method if you don't need a the FileIOPermission for anything other than calling Demand() once. + /// + /// This method tries to verify full access before allocating a FileIOPermission object. + /// If full access is there, then we still have to emulate the checks that creating the + /// FileIOPermission object would have performed. + /// + /// IMPORTANT: This method should only be used after calling GetFullPath on the path to verify + /// + /// + [System.Security.SecuritySafeCritical] + internal static void QuickDemand(FileIOPermissionAccess access, string[] fullPathList, bool checkForDuplicates = false, bool needFullPath = true) + { + if (!CodeAccessSecurityEngine.QuickCheckForAllDemands()) + { + new FileIOPermission(access, fullPathList, checkForDuplicates, needFullPath).Demand(); + } + else + { + foreach (string fullPath in fullPathList) + { + EmulateFileIOPermissionChecks(fullPath); + } + } + } - if (fullPath.Length > 2 && fullPath.IndexOf(':', 2) != -1) + [System.Security.SecuritySafeCritical] + internal static void QuickDemand(PermissionState state) + { + if (!CodeAccessSecurityEngine.QuickCheckForAllDemands()) + { + new FileIOPermission(state).Demand(); + } + } + +#if FEATURE_MACL + [System.Security.SecuritySafeCritical] + internal static void QuickDemand(FileIOPermissionAccess access, AccessControlActions control, string fullPath, bool checkForDuplicates = false, bool needFullPath = true) + { + if (!CodeAccessSecurityEngine.QuickCheckForAllDemands()) + { + new FileIOPermission(access, control, new string[] { fullPath }, checkForDuplicates, needFullPath).Demand(); + } + else + { + EmulateFileIOPermissionChecks(fullPath); + } + } + + [System.Security.SecuritySafeCritical] + internal static void QuickDemand(FileIOPermissionAccess access, AccessControlActions control, string[] fullPathList, bool checkForDuplicates = true, bool needFullPath = true) + { + if (!CodeAccessSecurityEngine.QuickCheckForAllDemands()) + { + new FileIOPermission(access, control, fullPathList, checkForDuplicates, needFullPath).Demand(); + } + else + { + foreach (string fullPath in fullPathList) { - throw new NotSupportedException(Environment.GetResourceString("Argument_PathFormatNotSupported")); + EmulateFileIOPermissionChecks(fullPath); } } } +#endif + + /// + /// Perform the additional path checks that would normally happen when creating a FileIOPermission object. + /// + /// A path that has already gone through GetFullPath or Normalize + internal static void EmulateFileIOPermissionChecks(string fullPath) + { + // Callers should have already made checks for invalid path format via normalization. This method will only make the + // additional checks needed to throw the same exceptions that would normally throw when using FileIOPermission. + // These checks are done via CheckIllegalCharacters() and StringExpressionSet in AddPathList() above. + // + // We have to check the beginning as some paths may be passed in as path + @"\.", which will be normalized away. + BCLDebug.Assert( + fullPath.StartsWith(Path.NormalizePath(fullPath, fullCheck: false), StringComparison.OrdinalIgnoreCase), + string.Format("path isn't normalized: {0}", fullPath)); + + // Checking for colon / invalid characters on device paths blocks legitimate access to objects such as named pipes. + if (AppContextSwitches.UseLegacyPathHandling || !PathInternal.IsDevice(fullPath)) + { + // GetFullPath already checks normal invalid path characters. We need to just check additional (wildcard) characters here. + // (By calling the standard helper we can allow extended paths \\?\ through when the support is enabled.) + if (PathInternal.HasWildCardCharacters(fullPath)) + { + throw new ArgumentException(Environment.GetResourceString("Argument_InvalidPathChars")); + } + if (PathInternal.HasInvalidVolumeSeparator(fullPath)) + { + throw new NotSupportedException(Environment.GetResourceString("Argument_PathFormatNotSupported")); + } + } + } } - + [Serializable] internal sealed class FileIOAccess { diff --git a/mcs/class/referencesource/mscorlib/system/security/principal/windowsidentity.cs b/mcs/class/referencesource/mscorlib/system/security/principal/windowsidentity.cs index 93cb2555874..e045de8e253 100644 --- a/mcs/class/referencesource/mscorlib/system/security/principal/windowsidentity.cs +++ b/mcs/class/referencesource/mscorlib/system/security/principal/windowsidentity.cs @@ -609,6 +609,8 @@ namespace System.Security.Principal // Public methods. // [SecuritySafeCritical] + [DynamicSecurityMethodAttribute()] + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable public static void RunImpersonated(SafeAccessTokenHandle safeAccessTokenHandle, Action action) { if (action == null) @@ -627,6 +629,8 @@ namespace System.Security.Principal } [SecuritySafeCritical] + [DynamicSecurityMethodAttribute()] + [MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable public static T RunImpersonated(SafeAccessTokenHandle safeAccessTokenHandle, Func func) { if (func == null) diff --git a/mcs/class/referencesource/mscorlib/system/security/util/stringexpressionset.cs b/mcs/class/referencesource/mscorlib/system/security/util/stringexpressionset.cs index 101d15ee58d..698f76f02e5 100644 --- a/mcs/class/referencesource/mscorlib/system/security/util/stringexpressionset.cs +++ b/mcs/class/referencesource/mscorlib/system/security/util/stringexpressionset.cs @@ -219,33 +219,35 @@ namespace System.Security.Util { throw new ArgumentNullException( "str" ); } Contract.EndContractBlock(); + ArrayList retArrayList = new ArrayList(); for (int index = 0; index < str.Length; ++index) { if (str[index] == null) throw new ArgumentNullException( "str" ); + // Replace alternate directory separators String oneString = StaticProcessWholeString( str[index] ); if (oneString != null && oneString.Length != 0) { - String temp = StaticProcessSingleString( oneString); + // Trim leading and trailing spaces + String temp = StaticProcessSingleString(oneString); - int indexOfNull = temp.IndexOf( '\0' ); + int indexOfNull = temp.IndexOf('\0'); if (indexOfNull != -1) - temp = temp.Substring( 0, indexOfNull ); + temp = temp.Substring(0, indexOfNull); if (temp != null && temp.Length != 0) { - if (Path.IsRelative(temp)) + if (PathInternal.IsPartiallyQualified(temp)) { - throw new ArgumentException( Environment.GetResourceString( "Argument_AbsolutePathRequired" ) ); + throw new ArgumentException(Environment.GetResourceString("Argument_AbsolutePathRequired")); } temp = CanonicalizePath( temp, needFullPath ); - retArrayList.Add( temp ); } } @@ -746,24 +748,14 @@ namespace System.Security.Util { [System.Security.SecurityCritical] // auto-generated [ResourceExposure(ResourceScope.Machine)] [ResourceConsumption(ResourceScope.Machine)] - internal static String CanonicalizePath( String path, bool needFullPath ) + internal static string CanonicalizePath(string path, bool needFullPath) { - if (path.IndexOf( '~' ) != -1) - { - string longPath = null; - GetLongPathName(path, JitHelpers.GetStringHandleOnStack(ref longPath)); - path = (longPath != null) ? longPath : path; - } - - if (path.IndexOf( ':', 2 ) != -1) - throw new NotSupportedException( Environment.GetResourceString( "Argument_PathFormatNotSupported" ) ); - if (needFullPath) { - String newPath = System.IO.Path.GetFullPathInternal( path ); - if (path.EndsWith( m_directorySeparator + ".", StringComparison.Ordinal )) + string newPath = Path.GetFullPathInternal(path); + if (path.EndsWith(m_directorySeparator + ".", StringComparison.Ordinal)) { - if (newPath.EndsWith( m_directorySeparator )) + if (newPath.EndsWith(m_directorySeparator)) { newPath += "."; } @@ -771,11 +763,23 @@ namespace System.Security.Util { { newPath += m_directorySeparator + "."; } - } - return newPath; + } + path = newPath; } - else - return path; + else if (path.IndexOf('~') != -1) + { + // GetFullPathInternal() will expand 8.3 file names + string longPath = null; + GetLongPathName(path, JitHelpers.GetStringHandleOnStack(ref longPath)); + path = (longPath != null) ? longPath : path; + } + + // This blocks usage of alternate data streams and some extended syntax paths (\\?\C:\). Checking after + // normalization allows valid paths such as " C:\" to be considered ok (as it will become "C:\"). + if (path.IndexOf(':', 2) != -1) + throw new NotSupportedException(Environment.GetResourceString("Argument_PathFormatNotSupported")); + + return path; } } } diff --git a/mcs/class/referencesource/mscorlib/system/security/util/urlstring.cs b/mcs/class/referencesource/mscorlib/system/security/util/urlstring.cs index b009ff0a8ec..c629fb4f695 100644 --- a/mcs/class/referencesource/mscorlib/system/security/util/urlstring.cs +++ b/mcs/class/referencesource/mscorlib/system/security/util/urlstring.cs @@ -354,13 +354,24 @@ namespace System.Security.Util { // 3. Throws a PathTooLongException if the length of the resulting URL is >= MAX_PATH. // This is done to prevent security issues due to canonicalization truncations. // Remove this method when the Path class supports "\\?\" - internal static String PreProcessForExtendedPathRemoval(String url, bool isFileUrl) + internal static string PreProcessForExtendedPathRemoval(string url, bool isFileUrl) { - bool uncShare = false; - return PreProcessForExtendedPathRemoval(url, isFileUrl, ref uncShare); + return PreProcessForExtendedPathRemoval(checkPathLength: true, url: url, isFileUrl: isFileUrl); } - private static String PreProcessForExtendedPathRemoval(String url, bool isFileUrl, ref bool isUncShare) + internal static string PreProcessForExtendedPathRemoval(bool checkPathLength, string url, bool isFileUrl) + { + bool isUncShare = false; + return PreProcessForExtendedPathRemoval(checkPathLength: checkPathLength, url: url, isFileUrl: isFileUrl, isUncShare: ref isUncShare); + } + + // Keeping this signature to avoid reflection breaks + private static string PreProcessForExtendedPathRemoval(string url, bool isFileUrl, ref bool isUncShare) + { + return PreProcessForExtendedPathRemoval(checkPathLength: true, url: url, isFileUrl: isFileUrl, isUncShare: ref isUncShare); + } + + private static string PreProcessForExtendedPathRemoval(bool checkPathLength, string url, bool isFileUrl, ref bool isUncShare) { // This is the modified URL that we will return StringBuilder modifiedUrl = new StringBuilder(url); @@ -434,15 +445,24 @@ namespace System.Security.Util { } // ITEM 3 - If the path is greater than or equal (due to terminating NULL in windows) MAX_PATH, we throw. - if (modifiedUrl.Length >= Path.MAX_PATH) + if (checkPathLength) { - throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); + // This needs to be a separate method to avoid hitting the static constructor on AppContextSwitches + CheckPathTooLong(modifiedUrl); } // Create the result string from the StringBuilder return modifiedUrl.ToString(); } + [MethodImpl(MethodImplOptions.NoInlining)] + private static void CheckPathTooLong(StringBuilder path) + { + if (path.Length >= (AppContextSwitches.BlockLongPaths ? PathInternal.MaxShortPath : PathInternal.MaxLongPath)) + { + throw new PathTooLongException(Environment.GetResourceString("IO.PathTooLong")); + } + } // Do any misc massaging of data in the URL private String PreProcessURL(String url, bool isFileURL) diff --git a/mcs/class/referencesource/mscorlib/system/text/stringbuilder.cs b/mcs/class/referencesource/mscorlib/system/text/stringbuilder.cs index 357bfe6c6ae..46c377bdeba 100644 --- a/mcs/class/referencesource/mscorlib/system/text/stringbuilder.cs +++ b/mcs/class/referencesource/mscorlib/system/text/stringbuilder.cs @@ -1968,7 +1968,7 @@ namespace System.Text { VerifyClassInvariant(); - if ((minBlockCharCount + Length) > m_MaxCapacity) + if (minBlockCharCount + Length < minBlockCharCount || (minBlockCharCount + Length) > m_MaxCapacity) throw new ArgumentOutOfRangeException("requiredLength", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity")); // Compute the length of the new block we need @@ -2028,7 +2028,8 @@ namespace System.Text { VerifyClassInvariant(); Contract.Assert(count > 0, "Count must be strictly positive"); Contract.Assert(index >= 0, "Index can't be negative"); - if (count + Length > m_MaxCapacity) + + if (count + Length < count || count + Length > m_MaxCapacity) throw new ArgumentOutOfRangeException("requiredLength", Environment.GetResourceString("ArgumentOutOfRange_SmallCapacity")); chunk = this; diff --git a/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs b/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs index 1e3f9293f7c..6ee970a08ef 100644 --- a/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs +++ b/mcs/class/referencesource/mscorlib/system/threading/Tasks/Task.cs @@ -3630,7 +3630,14 @@ namespace System.Threading.Tasks ITaskCompletionAction singleTaskCompletionAction = continuationObject as ITaskCompletionAction; if (singleTaskCompletionAction != null) { - singleTaskCompletionAction.Invoke(this); + if (bCanInlineContinuations) + { + singleTaskCompletionAction.Invoke(this); + } + else + { + ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(singleTaskCompletionAction, this), forceGlobal: false); + } LogFinishCompletionNotification(); return; } @@ -3711,7 +3718,15 @@ namespace System.Threading.Tasks { Contract.Assert(currentContinuation is ITaskCompletionAction, "Expected continuation element to be Action, TaskContinuation, or ITaskContinuationAction"); var action = (ITaskCompletionAction)currentContinuation; - action.Invoke(this); + + if (bCanInlineContinuations) + { + action.Invoke(this); + } + else + { + ThreadPool.UnsafeQueueCustomWorkItem(new CompletionActionInvoker(action, this), forceGlobal: false); + } } } } @@ -6673,6 +6688,30 @@ namespace System.Threading.Tasks } } + internal sealed class CompletionActionInvoker : IThreadPoolWorkItem + { + private readonly ITaskCompletionAction m_action; + private readonly Task m_completingTask; + + internal CompletionActionInvoker(ITaskCompletionAction action, Task completingTask) + { + m_action = action; + m_completingTask = completingTask; + } + + [SecurityCritical] + public void ExecuteWorkItem() + { + m_action.Invoke(m_completingTask); + } + + [SecurityCritical] + public void MarkAborted(ThreadAbortException tae) + { + /* NOP */ + } + } + // Proxy class for better debugging experience internal class SystemThreadingTasks_TaskDebugView { -- 2.25.1