AssemblyFilter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / MS / Internal / AppModel / AssemblyFilter.cs / 1 / AssemblyFilter.cs

                            //---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//              This class is used to filter assemblies as they are loaded into an application domain. 
//              The intent is to bring the AppDomain down in the case that one of these is on a disallowed list
//              similar to the kill bit for Activex 
//
// History:
//  11/15/05: akaza     Created.
//--------------------------------------------------------------------------- 

using System; 
using System.Windows; 
using MS.Internal.PresentationFramework;
using System.Collections.Generic; 
using MS.Win32;
using Microsoft.Win32;
using System.Security;
using System.Security.Permissions; 
using System.Reflection;
using System.Text; 
using MS.Internal.AppModel; 
using MS.Internal;
using System.Windows.Resources; 
using System.Diagnostics;
using System.Runtime.InteropServices;

 
namespace MS.Internal
{ 
 
    internal class AssemblyFilter
    { 
        /// 
        ///     Critical: This code sets the allowed assemblies on AssemblyList
        ///     TreatAsSafe: Initializing the data is ok since it does not expose anything
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        static  AssemblyFilter() 
        { 
            _disallowedListExtracted = new SecurityCriticalDataForSet(false);
            _assemblyList = new SecurityCriticalDataForSet>(new System.Collections.Generic.List()); 
        }

        /// 
        ///     Critical: This code calls into unmanaged Api that has a SUC on this (IAssemblCache related) 
        /// 
        [SecurityCritical] 
        internal void FilterCallback(Object sender, AssemblyLoadEventArgs args) 
        {
            // This code is reentrant 
            lock (_lock)
            {
                // Extract assembly
                Assembly a = args.LoadedAssembly; 
                // xmlns cache loads assemblies as reflection only and we cannot inspect these using the code below
                // so we ignore also keeping this first is super important because the first time cost is really high 
                // other wise also we cannot do any processing on a reflection only assembly aside from reflection based actions 
                if (!a.ReflectionOnly)
                { 
                    // check if it is in the Gac , this ensures that we eliminate any non GAC assembly which are of no risk
                    if (a.GlobalAssemblyCache)
                    {
                        object[] aptca = a.GetCustomAttributes(typeof(AllowPartiallyTrustedCallersAttribute), false); 
                        // if the dll has APTCA
                        if (aptca.Length > 0 && aptca[0] is AllowPartiallyTrustedCallersAttribute) 
                        { 
                            string assemblyName = AssemblyNameWithFileVersion(a);
                            // If we are on the disallowed list kill the application domain 
                            if (AssemblyOnDisallowedList(assemblyName))
                            {
                                // Kill the application domain
                                UnsafeNativeMethods.ProcessUnhandledException_DLL(SR.Get(SRID.KillBitEnforcedShutdown) + assemblyName); 
                                // I want to ensure that the process really dies
                                new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();//BlessedAssert 
                                try 
                                {
                                    System.Environment.Exit(-1); 
                                }
                                finally
                                {
                                    SecurityPermission.RevertAssert(); 
                                    Debug.Fail("Environment.Exit() failed.");
                                } 
                            } 
                        }
                    } 
                }
            }
        }
 
        //appends assembly name with file version to generate a unique entry for the assembly lookup process
        ///  
        ///     Critical: This code elevates to extract assembly name 
        /// 
        [SecurityCritical] 
        private string AssemblyNameWithFileVersion(Assembly a)
        {
            FileVersionInfo fileVersionInfo;
            StringBuilder sb = new StringBuilder(a.FullName); 
            // we need unrestricted here because the location is demands too.
            (new FileIOPermission(PermissionState.Unrestricted)).Assert();//BlessedAssert 
            try 
            {
                fileVersionInfo = FileVersionInfo.GetVersionInfo(a.Location); 
            }
            finally
            {
                FileIOPermission.RevertAssert(); 
            }
            if (fileVersionInfo != null && fileVersionInfo.ProductVersion != null) 
            { 
                sb.Append(FILEVERSION_STRING + fileVersionInfo.ProductVersion);
            } 
            return ((sb.ToString()).ToLower(System.Globalization.CultureInfo.InvariantCulture)).Trim();
        }

        ///  
        ///     Critical: This code populates _assemblyList with Disallowed Elements and sets the bit that dictates whether to repopulate it
        ///  
        [SecurityCritical] 
        private bool AssemblyOnDisallowedList(String assemblyToCheck)
        { 
            bool retVal = false;
            // if the list disallowed list is not populated populate it once
            if (_disallowedListExtracted.Value == false)
            { 
                // hit the registry one time and read
                ExtractDisallowedRegistryList(); 
                _disallowedListExtracted.Value = true; 
            }
            if (_assemblyList.Value.Contains(assemblyToCheck)) 
            {
                retVal = true;
            }
            return retVal; 
        }
 
        ///  
        ///     Critical: This code opens an HKLM registry location and reads it. We do not want
        ///     to call this over and over as it could cause performance issues 
        /// 
        [SecurityCritical]
        private  void ExtractDisallowedRegistryList()
        { 
            string[] disallowedAssemblies;
            RegistryKey featureKey; 
            //Assert for read access to HKLM\Software\Microsoft\.NetFramework\Policy\APTCA 
            (new RegistryPermission(RegistryPermissionAccess.Read, KILL_BIT_REGISTRY_HIVE + KILL_BIT_REGISTRY_LOCATION)).Assert();//BlessedAssert
            try 
            {
                // open the key and read the value
                featureKey = Registry.LocalMachine.OpenSubKey(KILL_BIT_REGISTRY_LOCATION);
                if (featureKey != null) 
                {
                    // Enumerate through all keys and populate dictionary 
                    disallowedAssemblies = featureKey.GetSubKeyNames(); 
                    // iterate over this list and for each extract the APTCA_FLAG value and set it in the
                    // dictionary 
                    foreach (string assemblyName in disallowedAssemblies)
                    {
                        featureKey = Registry.LocalMachine.OpenSubKey(KILL_BIT_REGISTRY_LOCATION + @"\" + assemblyName);
                        object keyValue = featureKey.GetValue(SUBKEY_VALUE); 
                        // if there exists a value and it is 1 add to hash table
                        if ((keyValue != null) && (int)(keyValue) == 1) 
                        { 
                            if (!_assemblyList.Value.Contains(assemblyName))
                            { 
                                _assemblyList.Value.Add(assemblyName.ToLower(System.Globalization.CultureInfo.InvariantCulture).Trim());
                            }
                        }
                    } 

                } 
            } 
            finally
            { 
                RegistryPermission.RevertAssert();
            }
        }
 
        /// 
        ///     Critical: This holds a list of assemblies that are on an allowed and disallowed list and can be exploited to load 
        ///     unsafe dll's into appdomain 
        /// 
        static SecurityCriticalDataForSet> _assemblyList; 

        /// 
        ///     Critical: This bit determines whether we need to hit the registry and load the disallowed elements.
        ///     We would like to see this happen only once per appdomain and delay it as much as possible 
        /// 
        static SecurityCriticalDataForSet _disallowedListExtracted; 
 
        static object _lock = new object();
 
        private const string FILEVERSION_STRING = @", FileVersion=";
        // This is the location in the registry where all the keys are stored
        private const string KILL_BIT_REGISTRY_HIVE = @"HKEY_LOCAL_MACHINE\";
        private const string KILL_BIT_REGISTRY_LOCATION = @"Software\Microsoft\.NetFramework\policy\APTCA"; 
        private const string SUBKEY_VALUE = @"APTCA_FLAG";
    } 
 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// 
//    Copyright (C) Microsoft Corporation.  All rights reserved.
//  
//
// Description: 
//              This class is used to filter assemblies as they are loaded into an application domain. 
//              The intent is to bring the AppDomain down in the case that one of these is on a disallowed list
//              similar to the kill bit for Activex 
//
// History:
//  11/15/05: akaza     Created.
//--------------------------------------------------------------------------- 

using System; 
using System.Windows; 
using MS.Internal.PresentationFramework;
using System.Collections.Generic; 
using MS.Win32;
using Microsoft.Win32;
using System.Security;
using System.Security.Permissions; 
using System.Reflection;
using System.Text; 
using MS.Internal.AppModel; 
using MS.Internal;
using System.Windows.Resources; 
using System.Diagnostics;
using System.Runtime.InteropServices;

 
namespace MS.Internal
{ 
 
    internal class AssemblyFilter
    { 
        /// 
        ///     Critical: This code sets the allowed assemblies on AssemblyList
        ///     TreatAsSafe: Initializing the data is ok since it does not expose anything
        ///  
        [SecurityCritical,SecurityTreatAsSafe]
        static  AssemblyFilter() 
        { 
            _disallowedListExtracted = new SecurityCriticalDataForSet(false);
            _assemblyList = new SecurityCriticalDataForSet>(new System.Collections.Generic.List()); 
        }

        /// 
        ///     Critical: This code calls into unmanaged Api that has a SUC on this (IAssemblCache related) 
        /// 
        [SecurityCritical] 
        internal void FilterCallback(Object sender, AssemblyLoadEventArgs args) 
        {
            // This code is reentrant 
            lock (_lock)
            {
                // Extract assembly
                Assembly a = args.LoadedAssembly; 
                // xmlns cache loads assemblies as reflection only and we cannot inspect these using the code below
                // so we ignore also keeping this first is super important because the first time cost is really high 
                // other wise also we cannot do any processing on a reflection only assembly aside from reflection based actions 
                if (!a.ReflectionOnly)
                { 
                    // check if it is in the Gac , this ensures that we eliminate any non GAC assembly which are of no risk
                    if (a.GlobalAssemblyCache)
                    {
                        object[] aptca = a.GetCustomAttributes(typeof(AllowPartiallyTrustedCallersAttribute), false); 
                        // if the dll has APTCA
                        if (aptca.Length > 0 && aptca[0] is AllowPartiallyTrustedCallersAttribute) 
                        { 
                            string assemblyName = AssemblyNameWithFileVersion(a);
                            // If we are on the disallowed list kill the application domain 
                            if (AssemblyOnDisallowedList(assemblyName))
                            {
                                // Kill the application domain
                                UnsafeNativeMethods.ProcessUnhandledException_DLL(SR.Get(SRID.KillBitEnforcedShutdown) + assemblyName); 
                                // I want to ensure that the process really dies
                                new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();//BlessedAssert 
                                try 
                                {
                                    System.Environment.Exit(-1); 
                                }
                                finally
                                {
                                    SecurityPermission.RevertAssert(); 
                                    Debug.Fail("Environment.Exit() failed.");
                                } 
                            } 
                        }
                    } 
                }
            }
        }
 
        //appends assembly name with file version to generate a unique entry for the assembly lookup process
        ///  
        ///     Critical: This code elevates to extract assembly name 
        /// 
        [SecurityCritical] 
        private string AssemblyNameWithFileVersion(Assembly a)
        {
            FileVersionInfo fileVersionInfo;
            StringBuilder sb = new StringBuilder(a.FullName); 
            // we need unrestricted here because the location is demands too.
            (new FileIOPermission(PermissionState.Unrestricted)).Assert();//BlessedAssert 
            try 
            {
                fileVersionInfo = FileVersionInfo.GetVersionInfo(a.Location); 
            }
            finally
            {
                FileIOPermission.RevertAssert(); 
            }
            if (fileVersionInfo != null && fileVersionInfo.ProductVersion != null) 
            { 
                sb.Append(FILEVERSION_STRING + fileVersionInfo.ProductVersion);
            } 
            return ((sb.ToString()).ToLower(System.Globalization.CultureInfo.InvariantCulture)).Trim();
        }

        ///  
        ///     Critical: This code populates _assemblyList with Disallowed Elements and sets the bit that dictates whether to repopulate it
        ///  
        [SecurityCritical] 
        private bool AssemblyOnDisallowedList(String assemblyToCheck)
        { 
            bool retVal = false;
            // if the list disallowed list is not populated populate it once
            if (_disallowedListExtracted.Value == false)
            { 
                // hit the registry one time and read
                ExtractDisallowedRegistryList(); 
                _disallowedListExtracted.Value = true; 
            }
            if (_assemblyList.Value.Contains(assemblyToCheck)) 
            {
                retVal = true;
            }
            return retVal; 
        }
 
        ///  
        ///     Critical: This code opens an HKLM registry location and reads it. We do not want
        ///     to call this over and over as it could cause performance issues 
        /// 
        [SecurityCritical]
        private  void ExtractDisallowedRegistryList()
        { 
            string[] disallowedAssemblies;
            RegistryKey featureKey; 
            //Assert for read access to HKLM\Software\Microsoft\.NetFramework\Policy\APTCA 
            (new RegistryPermission(RegistryPermissionAccess.Read, KILL_BIT_REGISTRY_HIVE + KILL_BIT_REGISTRY_LOCATION)).Assert();//BlessedAssert
            try 
            {
                // open the key and read the value
                featureKey = Registry.LocalMachine.OpenSubKey(KILL_BIT_REGISTRY_LOCATION);
                if (featureKey != null) 
                {
                    // Enumerate through all keys and populate dictionary 
                    disallowedAssemblies = featureKey.GetSubKeyNames(); 
                    // iterate over this list and for each extract the APTCA_FLAG value and set it in the
                    // dictionary 
                    foreach (string assemblyName in disallowedAssemblies)
                    {
                        featureKey = Registry.LocalMachine.OpenSubKey(KILL_BIT_REGISTRY_LOCATION + @"\" + assemblyName);
                        object keyValue = featureKey.GetValue(SUBKEY_VALUE); 
                        // if there exists a value and it is 1 add to hash table
                        if ((keyValue != null) && (int)(keyValue) == 1) 
                        { 
                            if (!_assemblyList.Value.Contains(assemblyName))
                            { 
                                _assemblyList.Value.Add(assemblyName.ToLower(System.Globalization.CultureInfo.InvariantCulture).Trim());
                            }
                        }
                    } 

                } 
            } 
            finally
            { 
                RegistryPermission.RevertAssert();
            }
        }
 
        /// 
        ///     Critical: This holds a list of assemblies that are on an allowed and disallowed list and can be exploited to load 
        ///     unsafe dll's into appdomain 
        /// 
        static SecurityCriticalDataForSet> _assemblyList; 

        /// 
        ///     Critical: This bit determines whether we need to hit the registry and load the disallowed elements.
        ///     We would like to see this happen only once per appdomain and delay it as much as possible 
        /// 
        static SecurityCriticalDataForSet _disallowedListExtracted; 
 
        static object _lock = new object();
 
        private const string FILEVERSION_STRING = @", FileVersion=";
        // This is the location in the registry where all the keys are stored
        private const string KILL_BIT_REGISTRY_HIVE = @"HKEY_LOCAL_MACHINE\";
        private const string KILL_BIT_REGISTRY_LOCATION = @"Software\Microsoft\.NetFramework\policy\APTCA"; 
        private const string SUBKEY_VALUE = @"APTCA_FLAG";
    } 
 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK