diff options
Diffstat (limited to 'src/mscorlib/src/System/Security/Policy/Evidence.cs')
-rw-r--r-- | src/mscorlib/src/System/Security/Policy/Evidence.cs | 1865 |
1 files changed, 0 insertions, 1865 deletions
diff --git a/src/mscorlib/src/System/Security/Policy/Evidence.cs b/src/mscorlib/src/System/Security/Policy/Evidence.cs index 8bf8aa7e92..22479dff6c 100644 --- a/src/mscorlib/src/System/Security/Policy/Evidence.cs +++ b/src/mscorlib/src/System/Security/Policy/Evidence.cs @@ -2,28 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -// - namespace System.Security.Policy { - using System; - using System.Collections; - using System.Collections.Generic; - using System.Configuration.Assemblies; - using System.Diagnostics.Contracts; - using System.IO; - using System.Reflection; - using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - using System.Runtime.Remoting; #if FEATURE_SERIALIZATION using System.Runtime.Serialization; using System.Runtime.Serialization.Formatters.Binary; #endif // FEATURE_SERIALIZATION - using System.Security.Permissions; - using System.Security.Util; - using System.Threading; - using Microsoft.Win32.SafeHandles; /// <summary> /// The Evidence class keeps track of information that can be used to make security decisions about @@ -48,1856 +33,6 @@ namespace System.Security.Policy #endif [ComVisible(true)] public sealed class Evidence -#if FEATURE_CAS_POLICY - : ICollection -#endif // FEATURE_CAS_POLICY { -#if !FEATURE_CORECLR && FEATURE_RWLOCK -#if FEATURE_SERIALIZATION - [OptionalField(VersionAdded = 4)] - private Dictionary<Type, EvidenceTypeDescriptor> m_evidence; - - [OptionalField(VersionAdded = 4)] - private bool m_deserializedTargetEvidence; - - // These fields are only used to deserialize v2.0 serialized versions of Evidence. It will be null - // after the seriailzation process is complete, and should not be used. -#pragma warning disable 414 - private volatile ArrayList m_hostList; - private volatile ArrayList m_assemblyList; -#pragma warning restore 414 -#else // !FEATURE_SERIALIZATION - private Dictionary<Type, EvidenceTypeDescriptor> m_evidence; -#endif // FEATURE_SERIALIZATION - - [NonSerialized] - private ReaderWriterLock m_evidenceLock; - - [NonSerialized] - private uint m_version; - - [NonSerialized] - private IRuntimeEvidenceFactory m_target; - - private bool m_locked; - - // If this evidence collection is a clone where we may need to backpatch to the original, this will - // reference the collection it was cloned from. See - // code:System.Security.Policy.Evidence#BackpatchGeneratedEvidence - [NonSerialized] - private WeakReference m_cloneOrigin; - - private static volatile Type[] s_runtimeEvidenceTypes; - - /// <summary> - /// Set of actions that we could perform if we detect that we are attempting to add evidence - /// when we already have evidence of that type stored. - /// </summary> - private enum DuplicateEvidenceAction - { - Throw, // Throw an exception - Merge, // Create a list of all the evidence objects - SelectNewObject // The newly added object wins - } - -#if FEATURE_CAS_POLICY - public Evidence() - { - m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>(); - m_evidenceLock = new ReaderWriterLock(); - } -#endif // FEATURE_CAS_POLICY - - /// <summary> - /// Create a deep copy of an evidence object - /// </summary> - public Evidence(Evidence evidence) - { - m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>(); - - if (evidence != null) - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(evidence, EvidenceLockHolder.LockType.Reader)) - { - foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in evidence.m_evidence) - { - EvidenceTypeDescriptor cloneDescriptor = evidenceType.Value; - if (cloneDescriptor != null) - { - cloneDescriptor = cloneDescriptor.Clone(); - } - - m_evidence[evidenceType.Key] = cloneDescriptor; - } - - m_target = evidence.m_target; - m_locked = evidence.m_locked; -#if FEATURE_SERIALIZATION - m_deserializedTargetEvidence = evidence.m_deserializedTargetEvidence; -#endif // FEATURE_SERIALIZATION - - // see code:System.Security.Policy.Evidence#BackpatchGeneratedEvidence - if (evidence.Target != null) - { - m_cloneOrigin = new WeakReference(evidence); - } - } - } - - // see code:System.Security.Policy.Evidence#EvidenceLock - m_evidenceLock = new ReaderWriterLock(); - } - - [Obsolete("This constructor is obsolete. Please use the constructor which takes arrays of EvidenceBase instead.")] - public Evidence(object[] hostEvidence, object[] assemblyEvidence) - { - m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>(); - - // This is a legacy evidence entry point, so we add through the legacy add APIs in order to get - // proper legacy wrapping and merge behavior. -#pragma warning disable 618 - if (hostEvidence != null) - { - foreach (object hostEvidenceObject in hostEvidence) - { - AddHost(hostEvidenceObject); - } - } - - if (assemblyEvidence != null) - { - foreach (object assemblyEvidenceObject in assemblyEvidence) - { - AddAssembly(assemblyEvidenceObject); - } - } -#pragma warning restore 618 - - // see code:System.Security.Policy.Evidence#EvidenceLock - m_evidenceLock = new ReaderWriterLock(); - } - - public Evidence(EvidenceBase[] hostEvidence, EvidenceBase[] assemblyEvidence) - { - m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>(); - - if (hostEvidence != null) - { - foreach (EvidenceBase hostEvidenceObject in hostEvidence) - { - AddHostEvidence(hostEvidenceObject, GetEvidenceIndexType(hostEvidenceObject), DuplicateEvidenceAction.Throw); - } - } - - if (assemblyEvidence != null) - { - foreach (EvidenceBase assemblyEvidenceObject in assemblyEvidence) - { - AddAssemblyEvidence(assemblyEvidenceObject, GetEvidenceIndexType(assemblyEvidenceObject), DuplicateEvidenceAction.Throw); - } - } - - // see code:System.Security.Policy.Evidence#EvidenceLock - m_evidenceLock = new ReaderWriterLock(); - } - - /// <summary> - /// Create an empty evidence collection which will contain evidence for a specific assembly or - /// AppDomain - /// </summary> - [SecuritySafeCritical] - internal Evidence(IRuntimeEvidenceFactory target) - { - Contract.Assert(target != null); - - m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>(); - m_target = target; - - // Setup the types of evidence that the CLR can generate for a target as keys in the dictionary - foreach (Type runtimeEvidenceType in RuntimeEvidenceTypes) - { - BCLDebug.Assert(typeof(EvidenceBase).IsAssignableFrom(runtimeEvidenceType), "All runtime evidence types should be EvidenceBases"); - m_evidence[runtimeEvidenceType] = null; - } - - QueryHostForPossibleEvidenceTypes(); - - // see code:System.Security.Policy.Evidence#EvidenceLock - m_evidenceLock = new ReaderWriterLock(); - } - - internal static Type[] RuntimeEvidenceTypes - { - get - { - if (s_runtimeEvidenceTypes == null) - { - Type[] runtimeEvidenceTypes = new Type[] - { -#if FEATURE_CLICKONCE - typeof(System.Runtime.Hosting.ActivationArguments), -#endif // FEATURE_CLICKONCE -#if FEATURE_CAS_POLICY - typeof(ApplicationDirectory), -#endif // FEATURE_CAS_POLICY - typeof(ApplicationTrust), -#if FEATURE_CAS_POLICY - typeof(GacInstalled), - typeof(Hash), - typeof(Publisher), -#endif // FEATURE_CAS_POLICY - typeof(Site), - typeof(StrongName), - typeof(Url), - typeof(Zone) - }; - -#if FEATURE_CAS_POLICY - // We only supply permission request evidence in legacy CAS mode - if (AppDomain.CurrentDomain.IsLegacyCasPolicyEnabled) - { -#pragma warning disable 618 // We need to generate PermissionRequestEvidence in compatibility mode - int l = runtimeEvidenceTypes.Length; - Array.Resize(ref runtimeEvidenceTypes, l+1); - runtimeEvidenceTypes[l] = typeof(PermissionRequestEvidence); -#pragma warning restore 618 - } -#endif // FEATURE_CAS_POLICY - - s_runtimeEvidenceTypes = runtimeEvidenceTypes; - } - - return s_runtimeEvidenceTypes; - } - } - - // - // #EvidenceLock - // - // Evidence synchronization locking wrappers. In the case where the lock has not yet been created, - // we know that we're in the process of constructing the evidence collection and therefore we can - // act as though the evidence is locked. If there is a lock in place, then just delegate back to it. - // - // The nested EvidenceLockHolder and EvidenceUpgradeLockHolder utility classes can be used to wrap - // these methods when acquiring and releasing the evidence lock. - // - - // Millisecond timeout when waiting to acquire the evidence lock - private const int LockTimeout = 5000; - - private bool IsReaderLockHeld - { - get { return m_evidenceLock == null || m_evidenceLock.IsReaderLockHeld; } - } - - private bool IsWriterLockHeld - { - get { return m_evidenceLock == null || m_evidenceLock.IsWriterLockHeld; } - } - - private void AcquireReaderLock() - { - Contract.Assert(m_evidenceLock == null || !IsReaderLockHeld); - - if (m_evidenceLock != null) - { - m_evidenceLock.AcquireReaderLock(LockTimeout); - } - } - - private void AcquireWriterlock() - { - Contract.Assert(m_evidenceLock == null || !IsWriterLockHeld); - - if (m_evidenceLock != null) - { - m_evidenceLock.AcquireWriterLock(LockTimeout); - } - } - - private void DowngradeFromWriterLock(ref LockCookie lockCookie) - { - Contract.Assert(IsWriterLockHeld); - if (m_evidenceLock != null) - { - m_evidenceLock.DowngradeFromWriterLock(ref lockCookie); - } - } - - private LockCookie UpgradeToWriterLock() - { - Contract.Assert(IsReaderLockHeld); - return m_evidenceLock != null ? m_evidenceLock.UpgradeToWriterLock(LockTimeout) : new LockCookie(); - } - - private void ReleaseReaderLock() - { - Contract.Assert(IsReaderLockHeld); - - if (m_evidenceLock != null) - { - m_evidenceLock.ReleaseReaderLock(); - } - } - - private void ReleaseWriterLock() - { - Contract.Assert(IsWriterLockHeld); - - if (m_evidenceLock != null) - { - m_evidenceLock.ReleaseWriterLock(); - } - } - - [Obsolete("This method is obsolete. Please use AddHostEvidence instead.")] - [SecuritySafeCritical] - public void AddHost(object id) - { - if (id == null) - throw new ArgumentNullException("id"); - if (!id.GetType().IsSerializable) - throw new ArgumentException(Environment.GetResourceString("Policy_EvidenceMustBeSerializable"), "id"); - Contract.EndContractBlock(); - - if (m_locked) - { - new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand(); - } - - EvidenceBase evidence = WrapLegacyEvidence(id); - Type evidenceIndex = GetEvidenceIndexType(evidence); - - // Whidbey allowed for multiple types of the same evidence, so if we're being called via the Whidbey - // APIs, then allow the evidences to merge together. - AddHostEvidence(evidence, evidenceIndex, DuplicateEvidenceAction.Merge); - } - - [Obsolete("This method is obsolete. Please use AddAssemblyEvidence instead.")] - public void AddAssembly(object id) - { - if (id == null) - throw new ArgumentNullException("id"); - if (!id.GetType().IsSerializable) - throw new ArgumentException(Environment.GetResourceString("Policy_EvidenceMustBeSerializable"), "id"); - Contract.EndContractBlock(); - - EvidenceBase evidence = WrapLegacyEvidence(id); - Type evidenceIndex = GetEvidenceIndexType(evidence); - - // Whidbey allowed for multiple types of the same evidence, so if we're being called via the Whidbey - // APIs, then allow the evidences to merge together. - AddAssemblyEvidence(evidence, evidenceIndex, DuplicateEvidenceAction.Merge); - } - - /// <summary> - /// Add a piece of evidence to the assembly supplied evidence list. This method will disallow adding - /// evidence if there is already evidence of that type in the assembly list. - /// </summary> - [ComVisible(false)] - public void AddAssemblyEvidence<T>(T evidence) where T : EvidenceBase - { - if (evidence == null) - throw new ArgumentNullException("evidence"); - Contract.EndContractBlock(); - - // Index the evidence under the type that the Add function was called with, unless we were given - // a plain EvidenceBase or a wrapped legacy evidence. In that case, we need to index under a - // more specific type. - Type evidenceType = typeof(T); - if (typeof(T) == typeof(EvidenceBase) || evidence is ILegacyEvidenceAdapter) - { - evidenceType = GetEvidenceIndexType(evidence); - } - - AddAssemblyEvidence(evidence, evidenceType, DuplicateEvidenceAction.Throw); - } - - private void AddAssemblyEvidence(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction) - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) - { - AddAssemblyEvidenceNoLock(evidence, evidenceType, duplicateAction); - } - } - - private void AddAssemblyEvidenceNoLock(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction) - { - Contract.Assert(IsWriterLockHeld); - Contract.Assert(evidence != null); - Contract.Assert(evidenceType != null); - - // We need to make sure that any target supplied evidence is deserialized before adding to the - // Assembly collection in order to preserve the semantics that the evidence objects supplied by - // the target are the original versions and evidence objects added via the APIs are the duplicates. - DeserializeTargetEvidence(); - - EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType, true); - - ++m_version; - if (descriptor.AssemblyEvidence == null) - { - descriptor.AssemblyEvidence = evidence; - } - else - { - descriptor.AssemblyEvidence = HandleDuplicateEvidence(descriptor.AssemblyEvidence, - evidence, - duplicateAction); - } - } - - /// <summary> - /// Add a piece of evidence to the host supplied evidence list. This method will disallow adding - /// evidence if there is already evidence of that type in the host list. - /// </summary> - [ComVisible(false)] - public void AddHostEvidence<T>(T evidence) where T : EvidenceBase - { - if (evidence == null) - throw new ArgumentNullException("evidence"); - Contract.EndContractBlock(); - - // Index the evidence under the type that the Add function was called with, unless we were given - // a plain EvidenceBase or a wrapped legacy evidence. In that case, we need to index under a - // more specific type. - Type evidenceType = typeof(T); - if (typeof(T) == typeof(EvidenceBase) || evidence is ILegacyEvidenceAdapter) - { - evidenceType = GetEvidenceIndexType(evidence); - } - - AddHostEvidence(evidence, evidenceType, DuplicateEvidenceAction.Throw); - } - - [SecuritySafeCritical] - private void AddHostEvidence(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction) - { - Contract.Assert(evidence != null); - Contract.Assert(evidenceType != null); - - if (Locked) - { - new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand(); - } - - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) - { - AddHostEvidenceNoLock(evidence, evidenceType, duplicateAction); - } - } - - /// <summary> - /// Add evidence to the host supplied evidence collection without acquiring the evidence lock or - /// checking to make sure that the caller has permission to bypass locked evidence. - /// </summary> - private void AddHostEvidenceNoLock(EvidenceBase evidence, Type evidenceType, DuplicateEvidenceAction duplicateAction) - { - Contract.Assert(IsWriterLockHeld); - Contract.Assert(evidence != null); - Contract.Assert(evidenceType != null); - - EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType, true); - - ++m_version; - if (descriptor.HostEvidence == null) - { - descriptor.HostEvidence = evidence; - } - else - { - descriptor.HostEvidence = HandleDuplicateEvidence(descriptor.HostEvidence, - evidence, - duplicateAction); - } - } - - /// <summary> - /// Ask the host for the types of evidence that it might provide if it is asked. - /// - /// This should only be called when setting up the Evidence collection to interact with the - /// host, and should not be used once that connection is established and the evidence has been - /// made available to user code. - /// </summary> - [SecurityCritical] - private void QueryHostForPossibleEvidenceTypes() - { -#if FEATURE_CAS_POLICY - Contract.Assert(IsWriterLockHeld); - - // First check to see if we have a HostSecurityManager - if (AppDomain.CurrentDomain.DomainManager != null) - { - HostSecurityManager hsm = AppDomain.CurrentDomain.DomainManager.HostSecurityManager; - if (hsm != null) - { - Type[] hostSuppliedTypes = null; - - AppDomain targetDomain = m_target.Target as AppDomain; - Assembly targetAssembly = m_target.Target as Assembly; - - // - // If the HostSecurityManager wants to supply evidence for the type of target that we have, - // then ask it what types of evidence it might supply. - // - - if (targetAssembly != null && - (hsm.Flags & HostSecurityManagerOptions.HostAssemblyEvidence) == HostSecurityManagerOptions.HostAssemblyEvidence) - { - hostSuppliedTypes = hsm.GetHostSuppliedAssemblyEvidenceTypes(targetAssembly); - } - else if (targetDomain != null && - (hsm.Flags & HostSecurityManagerOptions.HostAppDomainEvidence) == HostSecurityManagerOptions.HostAppDomainEvidence) - { - hostSuppliedTypes = hsm.GetHostSuppliedAppDomainEvidenceTypes(); - } - - // - // Finally, mark the descriptor for each of the types that the host can supply to indicate - // we should ask the host to generate them if we're asked. - // - - if (hostSuppliedTypes != null) - { - foreach (Type hostEvidenceType in hostSuppliedTypes) - { - EvidenceTypeDescriptor evidenceDescriptor = GetEvidenceTypeDescriptor(hostEvidenceType, true); - evidenceDescriptor.HostCanGenerate = true; - } - } - } - } -#endif // FEATURE_CAS_POLICY - } - - internal bool IsUnmodified - { - get { return m_version == 0; } - } - - /// <summary> - /// Set or check to see if the evidence is locked. Locked evidence cannot have its host supplied - /// evidence list be modified without a successful demand for ControlEvidence. Any code can lock - /// evidence, but only code with ControlEvidence may unlock it. - /// - /// This lock is not the same as the synchronization lock that gates access to the evidence collection. - /// </summary> - public bool Locked - { - get - { - return m_locked; - } - - [SecuritySafeCritical] - set - { - if (!value) - { - new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand(); - - m_locked = false; - } - else - { - m_locked = true; - } - } - } - - /// <summary> - /// Target of any delay generated evidence objects - /// </summary> - internal IRuntimeEvidenceFactory Target - { - get { return m_target; } - - // - // There are two retargeting scenarios supported: - // - // 1. A PEFileEvidenceFactory is being upgraded to an AssemblyEvidenceFactory and we don't want - // to throw away any already generated evidence. - // 2. A detached evidence collection is being applied to an AppDomain and that domain has a - // HostSecurityManager. In that case, we want to attach the target to the AppDomain to - // allow the HostSecurityManager to get callbacks for delay generated evidence. - // - - [SecurityCritical] - set - { -#if FEATURE_CAS_POLICY - Contract.Assert((m_target != null && m_target is PEFileEvidenceFactory && value != null && value is AssemblyEvidenceFactory) || - (m_target == null && value != null && value is AppDomainEvidenceFactory), - "Evidence retargeting should only be from PEFile -> Assembly or detached -> AppDomain."); -#endif // FEATURE_CAS_POLICY - - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) - { - m_target = value; - - // Since we've updated what we're pointing at, we need to query the host to determine what - // types of evidence that it can generate for this new target. - QueryHostForPossibleEvidenceTypes(); - } - } - } - - /// <summary> - /// Get the type that would be used to index into the evidence dictionary for this object - /// </summary> - private static Type GetEvidenceIndexType(EvidenceBase evidence) - { - Contract.Assert(evidence != null); - - // - // Legacy wrapper evidence types should be indexed via the type of evidence that they're wrapping - // so check to see if we have one of those; otherwise just return the type itself. - // - - ILegacyEvidenceAdapter adapter = evidence as ILegacyEvidenceAdapter; - return adapter == null ? evidence.GetType() : adapter.EvidenceType; - } - - /// <summary> - /// Get the type descriptor for a specific type of evidence. This method should be used instead - /// of accessing the dictionary directly as it will handle the case where a new descriptor needs - /// to be created. - /// </summary> - internal EvidenceTypeDescriptor GetEvidenceTypeDescriptor(Type evidenceType) - { - return GetEvidenceTypeDescriptor(evidenceType, false); - } - - /// <summary> - /// Get the type descriptor for a specific type of evidence, optionally creating a descriptor if - /// we did not yet know about this type of evidence. This method should be used instead of - /// accessing the dictionary directly as it will handle the case where a new descriptor needs - /// to be created. - /// </summary> - private EvidenceTypeDescriptor GetEvidenceTypeDescriptor(Type evidenceType, bool addIfNotExist) - { - Contract.Assert(IsReaderLockHeld || IsWriterLockHeld); - Contract.Assert(evidenceType != null); - - // If we don't know about the type being indexed and we don't want to add it then exit out - EvidenceTypeDescriptor descriptor = null; - if (!m_evidence.TryGetValue(evidenceType, out descriptor) && !addIfNotExist) - { - return null; - } - - // If we haven't yet created a descriptor for this type then create one now - if (descriptor == null) - { - descriptor = new EvidenceTypeDescriptor(); -#if _DEBUG - descriptor.SetEvidenceType(evidenceType); -#endif // _DEBUG - - bool upgradedLock = false; - LockCookie upgradeCookie = new LockCookie(); - try - { - if (!IsWriterLockHeld) - { - upgradeCookie = UpgradeToWriterLock(); - upgradedLock = true; - } - - m_evidence[evidenceType] = descriptor; - } - finally - { - if (upgradedLock) - DowngradeFromWriterLock(ref upgradeCookie); - } - } - - return descriptor; - } - - /// <summary> - /// This method is called if a piece of evidence is added but another piece of evidence of the same - /// type already existed. We have different strategies depending on compatibility concerns of the - /// calling code. - /// </summary> - private static EvidenceBase HandleDuplicateEvidence(EvidenceBase original, - EvidenceBase duplicate, - DuplicateEvidenceAction action) - { - Contract.Assert(original != null); - Contract.Assert(duplicate != null); - Contract.Assert(original.GetType() == duplicate.GetType() || original.GetType() == typeof(LegacyEvidenceList)); - - switch (action) - { - // Throw - duplicate evidence is not allowed (Arrowhead behavior), so throw an exception - case DuplicateEvidenceAction.Throw: - throw new InvalidOperationException(Environment.GetResourceString("Policy_DuplicateEvidence", duplicate.GetType().FullName)); - - // SelectNewObject - MergeWithNoDuplicates behavior - the duplicate object wins - case DuplicateEvidenceAction.SelectNewObject: - return duplicate; - - // Merge - compat behavior. Merge the old and new evidence into a list so that both may exist - case DuplicateEvidenceAction.Merge: - - LegacyEvidenceList list = original as LegacyEvidenceList; - if (list == null) - { - list = new LegacyEvidenceList(); - list.Add(original); - } - - list.Add(duplicate); - return list; - - default: - BCLDebug.Assert(false, "Uknown DuplicateEvidenceAction"); - return null; - } - } - - /// <summary> - /// Wrap evidence we recieved through a legacy API to ensure that it is stored in an EvidenceBase - /// </summary> - private static EvidenceBase WrapLegacyEvidence(object evidence) - { - Contract.Assert(evidence != null); - - EvidenceBase wrappedEvidence = evidence as EvidenceBase; - if (wrappedEvidence == null) - { - wrappedEvidence = new LegacyEvidenceWrapper(evidence); - } - - return wrappedEvidence; - } - - /// <summary> - /// Upwrap evidence stored in a legacy adapter. - /// - /// This is only necessary for the case where multiple objects derived from EvidenceBase is - /// are added via the legacy APIs and are then retrieved via GetHostEvidence. This may occur if - /// a legacy application adds CLR supplied evidence types via the old APIs and a new application - /// consumes the resulting evidence. - /// </summary> - private static object UnwrapEvidence(EvidenceBase evidence) - { - ILegacyEvidenceAdapter adapter = evidence as ILegacyEvidenceAdapter; - return adapter == null ? evidence : adapter.EvidenceObject; - } - - /// <summary> - /// Merge two evidence collections together. Note that this will cause all of the lazily - /// generated evidence for the input collection to be generated, as well as causing any lazily - /// generated evidence that both collections share to be generated in the target. - /// </summary> - [SecuritySafeCritical] - public void Merge(Evidence evidence) - { - if (evidence == null) - { - return; - } - - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) - { - bool checkedLock = false; - IEnumerator hostEnumerator = evidence.GetHostEnumerator(); - while (hostEnumerator.MoveNext()) - { - if (Locked && !checkedLock) - { - new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand(); - checkedLock = true; - } - - // If we could potentially have evidence of the type about to be merged into our host list, - // then make sure that we generate that evidence before merging. This will prevent the - // newly merged evidence from masking the value that we would have generated on our own. - Type hostEvidenceType = hostEnumerator.Current.GetType(); - if (m_evidence.ContainsKey(hostEvidenceType)) - { - GetHostEvidenceNoLock(hostEvidenceType); - } - - EvidenceBase hostEvidence = WrapLegacyEvidence(hostEnumerator.Current); - AddHostEvidenceNoLock(hostEvidence, - GetEvidenceIndexType(hostEvidence), - DuplicateEvidenceAction.Merge); - } - - // Add each piece of assembly evidence. We don't need to deserialize our copy of the - // evidence because AddAssemblyEvidenceNoLock will do this for us. - IEnumerator assemblyEnumerator = evidence.GetAssemblyEnumerator(); - while (assemblyEnumerator.MoveNext()) - { - EvidenceBase assemblyEvidence = WrapLegacyEvidence(assemblyEnumerator.Current); - AddAssemblyEvidenceNoLock(assemblyEvidence, - GetEvidenceIndexType(assemblyEvidence), - DuplicateEvidenceAction.Merge); - } - } - } - - /// <summary> - /// Same as merge, except only one instance of any one evidence type is allowed. When duplicates - /// are found, the evidence in the input argument will have priority. Note this will force the - /// entire input evidence to be generated, and does not check for locked evidence - /// </summary> - internal void MergeWithNoDuplicates(Evidence evidence) - { - if (evidence == null) - { - return; - } - - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) - { - IEnumerator hostEnumerator = evidence.GetHostEnumerator(); - while (hostEnumerator.MoveNext()) - { - EvidenceBase hostEvidence = WrapLegacyEvidence(hostEnumerator.Current); - AddHostEvidenceNoLock(hostEvidence, - GetEvidenceIndexType(hostEvidence), - DuplicateEvidenceAction.SelectNewObject); - } - - IEnumerator assemblyEnumerator = evidence.GetAssemblyEnumerator(); - while (assemblyEnumerator.MoveNext()) - { - EvidenceBase assemblyEvidence = WrapLegacyEvidence(assemblyEnumerator.Current); - AddAssemblyEvidenceNoLock(assemblyEvidence, - GetEvidenceIndexType(assemblyEvidence), - DuplicateEvidenceAction.SelectNewObject); - } - } - } - -#if FEATURE_SERIALIZATION - /// <summary> - /// Do a full serialization of the evidence, which requires that we generate all of the evidence - /// we can and disconnect ourselves from the host and source assembly. - /// </summary> - [ComVisible(false)] - [OnSerializing] - [SecurityCritical] - [PermissionSet(SecurityAction.Assert, Unrestricted = true)] - private void OnSerializing(StreamingContext context) - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) - { - // First, force all of the host evidence that might be lazily generated to be created - foreach (Type evidenceType in new List<Type>(m_evidence.Keys)) - { - GetHostEvidenceNoLock(evidenceType); - } - - // Also ensure that all serialized assembly evidence has been created - DeserializeTargetEvidence(); - } - - // Fill in legacy evidence lists. We can't guarantee thread-safety here using locks - // because we can't put a lock in the serialization code that will read the lists. - // The best we can do is prevent another thread from seeing a half-populated list. - // Therefore, we assign the lists after we've populated them fully (and declare them volatile.) - ArrayList hostList = new ArrayList(); - IEnumerator hostEnumerator = GetHostEnumerator(); - while (hostEnumerator.MoveNext()) - { - hostList.Add(hostEnumerator.Current); - } - m_hostList = hostList; - - ArrayList assemblyList = new ArrayList(); - IEnumerator assemblyEnumerator = GetAssemblyEnumerator(); - while (assemblyEnumerator.MoveNext()) - { - assemblyList.Add(assemblyEnumerator.Current); - } - m_assemblyList = assemblyList; - } - - /// <summary> - /// Finish deserializing legacy evidence - /// </summary> - [ComVisible(false)] - [OnDeserialized] - [SecurityCritical] - private void OnDeserialized(StreamingContext context) - { - // Look at host and assembly evidence lists only if we serialized using Whidbey. - if (m_evidence == null) - { - m_evidence = new Dictionary<Type, EvidenceTypeDescriptor>(); - - // Whidbey evidence may need to be wrapped or added to a LegacyEvidenceList, so we go - // through the legacy APIs to add them. -#pragma warning disable 618 - if (m_hostList != null) - { - foreach (object evidenceObject in m_hostList) - { - if (evidenceObject != null) - { - AddHost(evidenceObject); - } - } - - m_hostList = null; - } - - if (m_assemblyList != null) - { - foreach (object evidenceObject in m_assemblyList) - { - if (evidenceObject != null) - { - AddAssembly(evidenceObject); - } - } - - m_assemblyList = null; - } -#pragma warning restore 618 - } - - // see code:System.Security.Policy.Evidence#EvidenceLock - m_evidenceLock = new ReaderWriterLock(); - } -#endif // FEATURE_SERIALIZATION - - /// <summary> - /// Load any serialized evidence out of the target assembly into our evidence collection. - /// - /// We allow entry to this method with only a reader lock held, since most of the time we will - /// not need to write to the evidence dictionary. If we haven't yet deserialized the target - /// evidence, then we will upgrade to a writer lock at that point. - /// </summary> - private void DeserializeTargetEvidence() - { -#if FEATURE_SERIALIZATION - Contract.Assert(IsReaderLockHeld || IsWriterLockHeld); - - if (m_target != null && !m_deserializedTargetEvidence) - { - bool upgradedLock = false; - LockCookie lockCookie = new LockCookie(); - try - { - if (!IsWriterLockHeld) - { - lockCookie = UpgradeToWriterLock(); - upgradedLock = true; - } - - // Set this to true here because AddAssemblyEvidenceNoLock will attempt to reenter this - // method creating possible infinite recursion. - m_deserializedTargetEvidence = true; - - foreach (EvidenceBase targetEvidence in m_target.GetFactorySuppliedEvidence()) - { - AddAssemblyEvidenceNoLock(targetEvidence, GetEvidenceIndexType(targetEvidence), DuplicateEvidenceAction.Throw); - } - } - finally - { - if (upgradedLock) - DowngradeFromWriterLock(ref lockCookie); - } - } -#endif // FEATURE_SERIALIZATION - } - -#if FEATURE_SERIALIZATION - /// <summary> - /// Serialize out raw evidence objects which have already been generated, ignoring any evidence - /// which might be present but has not yet been created for this assembly. - /// - /// This is used for indexing into the security policy cache, since we know that once policy is - /// resolved, the relevent membership conditions will have checked for any applicable evidence - /// and therefore after poliyc resolution this evidence collection will contain any evidence - /// objects necessary to arrive at its grant set. - /// </summary> - [SecurityCritical] - internal byte[] RawSerialize() - { - try - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) - { - // Filter out any evidence which is not yet generated - Dictionary<Type, EvidenceBase> generatedEvidence = new Dictionary<Type, EvidenceBase>(); - foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in m_evidence) - { - if (evidenceType.Value != null && evidenceType.Value.HostEvidence != null) - { - generatedEvidence[evidenceType.Key] = evidenceType.Value.HostEvidence; - } - } - - using (MemoryStream serializationStream = new MemoryStream()) - { - BinaryFormatter formatter = new BinaryFormatter(); - formatter.Serialize(serializationStream, generatedEvidence); - return serializationStream.ToArray(); - } - } - } - catch (SecurityException) - { - // We're running in a context where it's not safe to serialize the evidence out. In this case - // Simply decline to cache the result of the policy evaluation - return null; - } - } -#endif // FEATURE_SERIALIZATION - - // - // ICollection implementation. All ICollection interface members are potentially much more - // expensive in Arrowhead then they were downlevel. They should not be used if the standard Get and - // Add methods will work instead. - // - - [Obsolete("Evidence should not be treated as an ICollection. Please use the GetHostEnumerator and GetAssemblyEnumerator methods rather than using CopyTo.")] - public void CopyTo(Array array, int index) - { - if (array == null) - throw new ArgumentNullException("array"); - if (index < 0 || index > array.Length - Count) - throw new ArgumentOutOfRangeException("index"); - Contract.EndContractBlock(); - - int currentIndex = index; - - IEnumerator hostEnumerator = GetHostEnumerator(); - while (hostEnumerator.MoveNext()) - { - array.SetValue(hostEnumerator.Current, currentIndex); - ++currentIndex; - } - - IEnumerator assemblyEnumerator = GetAssemblyEnumerator(); - while (assemblyEnumerator.MoveNext()) - { - array.SetValue(assemblyEnumerator.Current, currentIndex); - ++currentIndex; - } - } - - public IEnumerator GetHostEnumerator() - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) - { - return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Host); - } - } - - public IEnumerator GetAssemblyEnumerator() - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) - { - DeserializeTargetEvidence(); - return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Assembly); - } - } - - /// <summary> - /// Get an enumerator that can iterate over the raw evidence objects stored for the assembly - /// </summary> - internal RawEvidenceEnumerator GetRawAssemblyEvidenceEnumerator() - { - Contract.Assert(IsReaderLockHeld); - DeserializeTargetEvidence(); - return new RawEvidenceEnumerator(this, new List<Type>(m_evidence.Keys), false); - } - - /// <summary> - /// Get an enumerator that can iterate over the raw evidence objects stored for the host - /// </summary> - /// <returns></returns> - internal RawEvidenceEnumerator GetRawHostEvidenceEnumerator() - { - Contract.Assert(IsReaderLockHeld); - return new RawEvidenceEnumerator(this, new List<Type>(m_evidence.Keys), true); - } - - [Obsolete("GetEnumerator is obsolete. Please use GetAssemblyEnumerator and GetHostEnumerator instead.")] - public IEnumerator GetEnumerator() - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) - { - return new EvidenceEnumerator(this, EvidenceEnumerator.Category.Host | EvidenceEnumerator.Category.Assembly); - } - } - - /// <summary> - /// Get a specific type of assembly supplied evidence - /// </summary> - [ComVisible(false)] - public T GetAssemblyEvidence<T>() where T : EvidenceBase - { - return UnwrapEvidence(GetAssemblyEvidence(typeof(T))) as T; - } - - internal EvidenceBase GetAssemblyEvidence(Type type) - { - Contract.Assert(type != null); - - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) - { - return GetAssemblyEvidenceNoLock(type); - } - } - - private EvidenceBase GetAssemblyEvidenceNoLock(Type type) - { - Contract.Assert(IsReaderLockHeld || IsWriterLockHeld); - Contract.Assert(type != null); - - DeserializeTargetEvidence(); - EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(type); - if (descriptor != null) - { - return descriptor.AssemblyEvidence; - } - - return null; - } - - /// <summary> - /// Get a specific type of host supplied evidence - /// </summary> - [ComVisible(false)] - public T GetHostEvidence<T>() where T : EvidenceBase - { - return UnwrapEvidence(GetHostEvidence(typeof(T))) as T; - } - - /// <summary> - /// Get a specific type of evidence from the host which may not have been verified yet. If the - /// evidence was not verified, then don't mark it as being used yet. - /// </summary> - internal T GetDelayEvaluatedHostEvidence<T>() where T : EvidenceBase, IDelayEvaluatedEvidence - { - return UnwrapEvidence(GetHostEvidence(typeof(T), false)) as T; - } - - internal EvidenceBase GetHostEvidence(Type type) - { - Contract.Assert(type != null); - - return GetHostEvidence(type, true); - } - - [SecuritySafeCritical] - private EvidenceBase GetHostEvidence(Type type, bool markDelayEvaluatedEvidenceUsed) - { - Contract.Assert(type != null); - - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) - { - EvidenceBase evidence = GetHostEvidenceNoLock(type); - - if (markDelayEvaluatedEvidenceUsed) - { - IDelayEvaluatedEvidence delayEvidence = evidence as IDelayEvaluatedEvidence; - if (delayEvidence != null) - { - delayEvidence.MarkUsed(); - } - } - - return evidence; - } - } - - /// <summary> - /// Get host supplied evidence from the collection - /// - /// We attempt to find host evdience in the following order: - /// - /// 1. Already generated or explicitly supplied evidence - /// 2. Evidence supplied by the CLR host - /// 3. Evidence supplied by the CLR itself - /// </summary> - [SecurityCritical] - private EvidenceBase GetHostEvidenceNoLock(Type type) - { - Contract.Assert(IsReaderLockHeld || IsWriterLockHeld); - Contract.Assert(type != null); - - EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(type); - - // If the evidence descriptor doesn't exist for the host evidence type than the evidence doesn't - // exist and neither the host nor the runtime can produce it. - if (descriptor == null) - { - return null; - } - - // If the evidence has already been generated or if it was explicitly provided then return that - if (descriptor.HostEvidence != null) - { - return descriptor.HostEvidence; - } - - // If we have a target, then the host or the runtime might be able to generate this type of - // evidence on demand. - if (m_target != null && !descriptor.Generated) - { - using (EvidenceUpgradeLockHolder lockHolder = new EvidenceUpgradeLockHolder(this)) - { - // Make sure that we don't attempt to generate this type of evidencea again if we fail to - // generate it now. - descriptor.Generated = true; - - EvidenceBase generatedEvidence = GenerateHostEvidence(type, descriptor.HostCanGenerate); - if (generatedEvidence != null) - { - descriptor.HostEvidence = generatedEvidence; - - // - // #BackpatchGeneratedEvidence - // - // If we were cloned from another evidence collection propigate any generated evidence - // back to the original collection. Since Assembly and AppDomain both clone their - // evidence before giving it to users, this prevents us from having to regenerate - // evidence types on each clone that gets created. Note that we do not want to do this - // backpatching if the origin already has evidence of this type or if it has had - // this type of evidence removed from its collection. - // - - Evidence cloneOrigin = m_cloneOrigin != null ? m_cloneOrigin.Target as Evidence : null; - if (cloneOrigin != null) - { - BCLDebug.Assert(cloneOrigin.Target != null && cloneOrigin.Target == Target, - "Attempt to backpatch evidence to a collection with a different target."); - - using (EvidenceLockHolder cloneLockHolder = new EvidenceLockHolder(cloneOrigin, EvidenceLockHolder.LockType.Writer)) - { - EvidenceTypeDescriptor cloneDescriptor = cloneOrigin.GetEvidenceTypeDescriptor(type); - if (cloneDescriptor != null && cloneDescriptor.HostEvidence == null) - { - cloneDescriptor.HostEvidence = generatedEvidence.Clone() as EvidenceBase; - } - } - } - - } - - return generatedEvidence; - } - } - - // The evidence could not be generated and was not found - return null; - } - - /// <summary> - /// Attempt to generate host evidence on demand via calls to the runtime host or the evidence facotry - /// </summary> - [SecurityCritical] - private EvidenceBase GenerateHostEvidence(Type type, bool hostCanGenerate) - { - Contract.Assert(type != null); - Contract.Assert(IsWriterLockHeld); - -#if FEATURE_CAS_POLICY - // First let the host generate the evidence if it can. - if (hostCanGenerate) - { - AppDomain targetDomain = m_target.Target as AppDomain; - Assembly targetAssembly = m_target.Target as Assembly; - - EvidenceBase hostEvidence = null; - if (targetDomain != null) - { - hostEvidence = AppDomain.CurrentDomain.HostSecurityManager.GenerateAppDomainEvidence(type); - } - else if (targetAssembly != null) - { - hostEvidence = AppDomain.CurrentDomain.HostSecurityManager.GenerateAssemblyEvidence(type, targetAssembly); - } - - // If the host generated the evidence, verify that it generated the evidence we expected - // and use that. - if (hostEvidence != null) - { - if (!type.IsAssignableFrom(hostEvidence.GetType())) - { - string hostType = AppDomain.CurrentDomain.HostSecurityManager.GetType().FullName; - string recievedType = hostEvidence.GetType().FullName; - string requestedType = type.FullName; - - throw new InvalidOperationException(Environment.GetResourceString("Policy_IncorrectHostEvidence", hostType, recievedType, requestedType)); - } - - return hostEvidence; - } - } -#endif // FEATURE_CAS_POLICY - - // Finally, check to see if the CLR can generate the evidence - return m_target.GenerateEvidence(type); - } - - [Obsolete("Evidence should not be treated as an ICollection. Please use GetHostEnumerator and GetAssemblyEnumerator to iterate over the evidence to collect a count.")] - public int Count - { - get - { - int count = 0; - - IEnumerator hostEvidence = GetHostEnumerator(); - while (hostEvidence.MoveNext()) - { - ++count; - } - - IEnumerator assemblyEvidence = GetAssemblyEnumerator(); - while (assemblyEvidence.MoveNext()) - { - ++count; - } - - return count; - } - } - - /// <summary> - /// Get the number of pieces of evidence which are currently generated, without causing any - /// lazily generated evidence to be created. - /// </summary> - [ComVisible(false)] - internal int RawCount - { - get - { - int count = 0; - - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) - { - foreach (Type evidenceType in new List<Type>(m_evidence.Keys)) - { - EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(evidenceType); - - if (descriptor != null) - { - if (descriptor.AssemblyEvidence != null) - { - ++count; - } - if (descriptor.HostEvidence != null) - { - ++count; - } - } - } - } - - return count; - } - } - - public Object SyncRoot - { - get { return this; } - } - - public bool IsSynchronized - { - get { return true; } - } - - public bool IsReadOnly - { - get { return false; } - } - -#if FEATURE_CAS_POLICY - [ComVisible(false)] - public Evidence Clone() - { - return new Evidence(this); - } -#endif // FEATURE_CAS_POLICY - - [ComVisible(false)] - [SecuritySafeCritical] - public void Clear() - { - if (Locked) - { - new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand(); - } - - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) - { - ++m_version; - m_evidence.Clear(); - } - } - - [ComVisible(false)] - [SecuritySafeCritical] - public void RemoveType(Type t) - { - if (t == null) - throw new ArgumentNullException("t"); - Contract.EndContractBlock(); - - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Writer)) - { - EvidenceTypeDescriptor descriptor = GetEvidenceTypeDescriptor(t); - if (descriptor != null) - { - ++m_version; - - // If we've locked this evidence collection, we need to do the lock check in the case that - // either we have host evidence, or that the host might generate it, since removing the - // evidence will cause us to bypass the host's ability to ever generate the evidence. - if (Locked && (descriptor.HostEvidence != null || descriptor.HostCanGenerate)) - { - new SecurityPermission(SecurityPermissionFlag.ControlEvidence).Demand(); - } - - m_evidence.Remove(t); - } - } - } - - /// <summary> - /// Mark all of the already generated evidence in the collection as having been used during a - /// policy evaluation. - /// </summary> - internal void MarkAllEvidenceAsUsed() - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) - { - foreach (KeyValuePair<Type, EvidenceTypeDescriptor> evidenceType in m_evidence) - { - if (evidenceType.Value != null) - { - IDelayEvaluatedEvidence hostEvidence = evidenceType.Value.HostEvidence as IDelayEvaluatedEvidence; - if (hostEvidence != null) - { - hostEvidence.MarkUsed(); - } - - IDelayEvaluatedEvidence assemblyEvidence = evidenceType.Value.AssemblyEvidence as IDelayEvaluatedEvidence; - if (assemblyEvidence != null) - { - assemblyEvidence.MarkUsed(); - } - } - } - } - } - -#if FEATURE_CAS_POLICY - /// <summary> - /// Determine if delay evaluated strong name evidence is contained in this collection, and if so - /// if it was used during policy evaluation. - /// - /// This method is called from the VM in SecurityPolicy::WasStrongNameEvidenceUsed - /// This class should be used as an adapter layer to allow the public facing EvidenceEnumerator to - /// be able to get the evidence values out of an Evidence class. It is tightly coupled with the - /// internal data structures holding the evidence objects in the Evidence class. - /// </summary> - private bool WasStrongNameEvidenceUsed() - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(this, EvidenceLockHolder.LockType.Reader)) - { - EvidenceTypeDescriptor snTypeDescriptor = GetEvidenceTypeDescriptor(typeof(StrongName)); - if (snTypeDescriptor != null) - { - IDelayEvaluatedEvidence snEvidence = snTypeDescriptor.HostEvidence as IDelayEvaluatedEvidence; - return snEvidence != null && snEvidence.WasUsed; - } - - return false; - } - } -#endif // FEATURE_CAS_POLICY - - /// <summary> - /// Utility class to wrap acquiring a lock onto the evidence collection - /// </summary> - private class EvidenceLockHolder : IDisposable - { - private Evidence m_target; - private LockType m_lockType; - - public enum LockType - { - Reader, - Writer - } - - public EvidenceLockHolder(Evidence target, LockType lockType) - { - Contract.Assert(target != null); - Contract.Assert(lockType == LockType.Reader || lockType == LockType.Writer); - - m_target = target; - m_lockType = lockType; - - if (m_lockType == LockType.Reader) - { - m_target.AcquireReaderLock(); - } - else - { - m_target.AcquireWriterlock(); - } - } - - public void Dispose() - { - if (m_lockType == LockType.Reader && m_target.IsReaderLockHeld) - { - m_target.ReleaseReaderLock(); - } - else if (m_lockType == LockType.Writer && m_target.IsWriterLockHeld) - { - m_target.ReleaseWriterLock(); - } - } - } - - /// <summary> - /// Utility class to wrap upgrading an acquired reader lock to a writer lock and then - /// downgrading it back to a reader lock. - /// </summary> - private class EvidenceUpgradeLockHolder : IDisposable - { - private Evidence m_target; - private LockCookie m_cookie; - - public EvidenceUpgradeLockHolder(Evidence target) - { - Contract.Assert(target != null); - - m_target = target; - m_cookie = m_target.UpgradeToWriterLock(); - } - - public void Dispose() - { - if (m_target.IsWriterLockHeld) - { - m_target.DowngradeFromWriterLock(ref m_cookie); - } - } - } - - /// <summary> - /// Enumerator that iterates directly over the evidence type map, returning back the evidence objects - /// that are contained in it. This enumerator will generate any lazy evaluated evidence it finds, - /// but it does not attempt to deal with legacy evidence adapters. - /// - /// This class should be used as an adapter layer to allow the public facing EvidenceEnumerator to - /// be able to get the evidence values out of an Evidence class. It is tightly coupled with the - /// internal data structures holding the evidence objects in the Evidence class. - /// </summary> - internal sealed class RawEvidenceEnumerator : IEnumerator<EvidenceBase> - { - private Evidence m_evidence; - private bool m_hostEnumerator; // true to enumerate host evidence, false to enumerate assembly evidence - private uint m_evidenceVersion; - - private Type[] m_evidenceTypes; - private int m_typeIndex; - private EvidenceBase m_currentEvidence; - - private static volatile List<Type> s_expensiveEvidence; - - public RawEvidenceEnumerator(Evidence evidence, IEnumerable<Type> evidenceTypes, bool hostEnumerator) - { - Contract.Assert(evidence != null); - Contract.Assert(evidenceTypes != null); - - m_evidence = evidence; - m_hostEnumerator = hostEnumerator; - m_evidenceTypes = GenerateEvidenceTypes(evidence, evidenceTypes, hostEnumerator); - m_evidenceVersion = evidence.m_version; - - Reset(); - } - - public EvidenceBase Current - { - get - { - if (m_evidence.m_version != m_evidenceVersion) - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); - - return m_currentEvidence; - } - } - - object IEnumerator.Current - { - get - { - if (m_evidence.m_version != m_evidenceVersion) - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); - - return m_currentEvidence; - } - } - - /// <summary> - /// List of types of evidence that we would like to avoid generating if possible - /// </summary> - private static List<Type> ExpensiveEvidence - { - get - { - if (s_expensiveEvidence == null) - { - List<Type> expensiveEvidence = new List<Type>(); -#if FEATURE_CAS_POLICY - expensiveEvidence.Add(typeof(Hash)); - expensiveEvidence.Add(typeof(Publisher)); -#endif // FEATURE_CAS_POLICY - s_expensiveEvidence = expensiveEvidence; - -#if _DEBUG - List<Type> runtimeTypes = new List<Type>(Evidence.RuntimeEvidenceTypes); - foreach (Type expensiveType in s_expensiveEvidence) - { - BCLDebug.Assert(runtimeTypes.Contains(expensiveType), - "Evidence type not generated by the runtime found in expensive evidence type list"); - } -#endif // _DEBUG - } - - return s_expensiveEvidence; - } - } - - public void Dispose() - { - return; - } - - /// <summary> - /// Generate the array of types of evidence that could have values for - /// </summary> - private static Type[] GenerateEvidenceTypes(Evidence evidence, - IEnumerable<Type> evidenceTypes, - bool hostEvidence) - { - Contract.Assert(evidence != null); - Contract.Assert(evidenceTypes != null); - - // - // Sort the evidence being generated into three categories, which we enumerate in order: - // 1. Evidence which has already been generated - // 2. Evidence which is relatively inexpensive to generate - // 3. Evidence which is expensive to generate. - // - // This allows us to be as efficient as possible in case the user of the enumerator stops the - // enumeration before we step up to the next more expensive category. - // - - List<Type> alreadyGeneratedList = new List<Type>(); - List<Type> inexpensiveList = new List<Type>(); - List<Type> expensiveList = new List<Type>(ExpensiveEvidence.Count); - - // Iterate over the evidence types classifying into the three groups. We need to copy the list - // here since GetEvidenceTypeDescriptor will potentially update the evidence dictionary, which - // evidenceTypes iterates over. - foreach (Type evidenceType in evidenceTypes) - { - EvidenceTypeDescriptor descriptor = evidence.GetEvidenceTypeDescriptor(evidenceType); - BCLDebug.Assert(descriptor != null, "descriptor != null"); - - bool alreadyGenerated = (hostEvidence && descriptor.HostEvidence != null) || - (!hostEvidence && descriptor.AssemblyEvidence != null); - - if (alreadyGenerated) - { - alreadyGeneratedList.Add(evidenceType); - } - else if (ExpensiveEvidence.Contains(evidenceType)) - { - expensiveList.Add(evidenceType); - } - else - { - inexpensiveList.Add(evidenceType); - } - } - - Type[] enumerationTypes = new Type[alreadyGeneratedList.Count + inexpensiveList.Count + expensiveList.Count]; - alreadyGeneratedList.CopyTo(enumerationTypes, 0); - inexpensiveList.CopyTo(enumerationTypes, alreadyGeneratedList.Count); - expensiveList.CopyTo(enumerationTypes, alreadyGeneratedList.Count + inexpensiveList.Count); - - return enumerationTypes; - } - - [SecuritySafeCritical] - public bool MoveNext() - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(m_evidence, EvidenceLockHolder.LockType.Reader)) - { - if (m_evidence.m_version != m_evidenceVersion) - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); - - m_currentEvidence = null; - - // Iterate over the possible types of evidence that we could have until we find one that - // really exists, or we run out of posibilities. - do - { - ++m_typeIndex; - - if (m_typeIndex < m_evidenceTypes.Length) - { - if (m_hostEnumerator) - { - m_currentEvidence = m_evidence.GetHostEvidenceNoLock(m_evidenceTypes[m_typeIndex]); - } - else - { - m_currentEvidence = m_evidence.GetAssemblyEvidenceNoLock(m_evidenceTypes[m_typeIndex]); - } - } - } - while (m_typeIndex < m_evidenceTypes.Length && m_currentEvidence == null); - } - - return m_currentEvidence != null; - } - - public void Reset() - { - if (m_evidence.m_version != m_evidenceVersion) - throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_EnumFailedVersion")); - - m_typeIndex = -1; - m_currentEvidence = null; - } - } - - private sealed class EvidenceEnumerator : IEnumerator - { - private Evidence m_evidence; - private Category m_category; - private Stack m_enumerators; - - private object m_currentEvidence; - - [Flags] - internal enum Category - { - Host = 0x1, // Enumerate only host supplied evidence - Assembly = 0x2 // Enumerate only assembly supplied evidence - } - - internal EvidenceEnumerator(Evidence evidence, Category category) - { - Contract.Assert(evidence != null); - Contract.Assert(evidence.IsReaderLockHeld); - - m_evidence = evidence; - m_category = category; - ResetNoLock(); - } - - public bool MoveNext() - { - IEnumerator currentEnumerator = CurrentEnumerator; - - // No more enumerators means we can't go any further - if (currentEnumerator == null) - { - m_currentEvidence = null; - return false; - } - - // See if the current enumerator can continue - if (currentEnumerator.MoveNext()) - { - // - // If we've found an adapter for legacy evidence, we need to unwrap it for it to be the - // current enumerator's value. For wrapped evidence, this is a simple unwrap, for a list of - // evidence, we need to make that the current enumerator and get its first value. - // - - LegacyEvidenceWrapper legacyWrapper = currentEnumerator.Current as LegacyEvidenceWrapper; - LegacyEvidenceList legacyList = currentEnumerator.Current as LegacyEvidenceList; - - if (legacyWrapper != null) - { - m_currentEvidence = legacyWrapper.EvidenceObject; - } - else if (legacyList != null) - { - IEnumerator legacyListEnumerator = legacyList.GetEnumerator(); - m_enumerators.Push(legacyListEnumerator); - MoveNext(); - } - else - { - m_currentEvidence = currentEnumerator.Current; - } - - BCLDebug.Assert(m_currentEvidence != null, "m_currentEvidence != null"); - return true; - } - else - { - // If we've reached the end of the current enumerator, move to the next one and try again - m_enumerators.Pop(); - return MoveNext(); - } - } - - public object Current - { - get { return m_currentEvidence; } - } - - private IEnumerator CurrentEnumerator - { - get - { - return m_enumerators.Count > 0 ? m_enumerators.Peek() as IEnumerator : null; - } - } - - public void Reset() - { - using (EvidenceLockHolder lockHolder = new EvidenceLockHolder(m_evidence, EvidenceLockHolder.LockType.Reader)) - { - ResetNoLock(); - } - } - - private void ResetNoLock() - { - Contract.Assert(m_evidence != null); - Contract.Assert(m_evidence.IsReaderLockHeld); - - m_currentEvidence = null; - m_enumerators = new Stack(); - - if ((m_category & Category.Host) == Category.Host) - { - m_enumerators.Push(m_evidence.GetRawHostEvidenceEnumerator()); - } - if ((m_category & Category.Assembly) == Category.Assembly) - { - m_enumerators.Push(m_evidence.GetRawAssemblyEvidenceEnumerator()); - } - } - } -#endif //!FEATURE_CORECLR && FEATURE_RWLOCK } } |