Implement mono_gc_alloc_fixed on Boehm to be uncollectable. This matches SGen behavio...
[mono.git] / mcs / class / referencesource / System / misc / SecurityUtils.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SecurityUtils.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6
7 /*
8  */
9
10
11 #if WINFORMS_NAMESPACE
12     namespace System.Windows.Forms
13 #elif DRAWING_NAMESPACE
14     namespace System.Drawing
15 #elif WINFORMS_PUBLIC_GRAPHICS_LIBRARY
16     namespace System.Internal
17 #elif SYSTEM_NAMESPACE
18     namespace System
19 #elif SYSTEM_WEB
20     namespace System.Web
21 #elif SYSTEM_DATA_LINQ
22     namespace System.Data.Linq
23 #else
24 namespace System.Windows.Forms 
25 #endif
26 {
27     using System;
28     using System.Reflection;
29     using System.Diagnostics.CodeAnalysis;
30     using System.Security;
31     using System.Security.Permissions;
32
33     /// <devdoc>
34     ///     Useful methods to securely call 'dangerous' managed APIs (especially reflection).
35     ///     See http://wiki/default.aspx/Microsoft.Projects.DotNetClient.SecurityConcernsAroundReflection
36     ///     for more information specifically about why we need to be careful about reflection invocations.
37     /// </devdoc>
38     internal static class SecurityUtils {
39
40         private static volatile ReflectionPermission memberAccessPermission = null;
41         private static volatile ReflectionPermission restrictedMemberAccessPermission = null;
42
43         private static ReflectionPermission MemberAccessPermission
44         {
45             get {
46                 if (memberAccessPermission == null) {
47                     memberAccessPermission = new ReflectionPermission(ReflectionPermissionFlag.MemberAccess);
48                 }
49                 return memberAccessPermission;
50             }
51         }
52
53         private static ReflectionPermission RestrictedMemberAccessPermission {
54             get {
55                 if (restrictedMemberAccessPermission == null) {
56                     restrictedMemberAccessPermission = new ReflectionPermission(ReflectionPermissionFlag.RestrictedMemberAccess);
57                 }
58                 return restrictedMemberAccessPermission;
59             }
60         }
61
62         private static void DemandReflectionAccess(Type type) {
63 #if FEATURE_MONO_CAS
64             try {
65                 MemberAccessPermission.Demand();
66             }
67             catch (SecurityException) {
68                 DemandGrantSet(type.Assembly);
69             }
70 #endif
71         }
72
73         [SecuritySafeCritical]
74         private static void DemandGrantSet(Assembly assembly) {
75 #if FEATURE_MONO_CAS
76             PermissionSet targetGrantSet = assembly.PermissionSet;
77             targetGrantSet.AddPermission(RestrictedMemberAccessPermission);
78             targetGrantSet.Demand();
79 #endif
80         }
81
82         private static bool HasReflectionPermission(Type type) {
83             try {
84                 DemandReflectionAccess(type);
85                 return true;
86             }
87             catch (SecurityException) {
88             }
89
90             return false;
91         }
92
93        
94         /// <devdoc>
95         ///     This helper method provides safe access to Activator.CreateInstance.
96         ///     NOTE: This overload will work only with public .ctors. 
97         /// </devdoc>
98         internal static object SecureCreateInstance(Type type) {
99             return SecureCreateInstance(type, null, false);
100         }
101
102
103         /// <devdoc>
104         ///     This helper method provides safe access to Activator.CreateInstance.
105         ///     Set allowNonPublic to true if you want non public ctors to be used. 
106         /// </devdoc>
107         internal static object SecureCreateInstance(Type type, object[] args, bool allowNonPublic) {
108             if (type == null) {
109                 throw new ArgumentNullException("type");
110             }
111
112             BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;
113            
114             // if it's an internal type, we demand reflection permission.
115             if (!type.IsVisible) {
116                 DemandReflectionAccess(type);
117             }
118             else if (allowNonPublic && !HasReflectionPermission(type)) {
119                 // Someone is trying to instantiate a public type in *our* assembly, but does not
120                 // have full reflection permission. We shouldn't pass BindingFlags.NonPublic in this case.
121                 // The reason we don't directly demand the permission here is because we don't know whether
122                 // a public or non-public .ctor will be invoked. We want to allow the public .ctor case to
123                 // succeed.
124                 allowNonPublic = false;
125             }
126             
127             if (allowNonPublic) {
128                 flags |= BindingFlags.NonPublic;
129             }
130
131             return Activator.CreateInstance(type, flags, null, args, null);
132         }
133
134 #if (!WINFORMS_NAMESPACE)
135
136         /// <devdoc>
137         ///     This helper method provides safe access to Activator.CreateInstance.
138         ///     NOTE: This overload will work only with public .ctors. 
139         /// </devdoc>
140         internal static object SecureCreateInstance(Type type, object[] args) {
141             return SecureCreateInstance(type, args, false);
142         }
143
144
145         /// <devdoc>
146         ///     Helper method to safely invoke a .ctor. You should prefer SecureCreateInstance to this.
147         ///     Set allowNonPublic to true if you want non public ctors to be used. 
148         /// </devdoc>
149         internal static object SecureConstructorInvoke(Type type, Type[] argTypes, object[] args, bool allowNonPublic) {
150             return SecureConstructorInvoke(type, argTypes, args, allowNonPublic, BindingFlags.Default);
151         }
152
153         /// <devdoc>
154         ///     Helper method to safely invoke a .ctor. You should prefer SecureCreateInstance to this.
155         ///     Set allowNonPublic to true if you want non public ctors to be used. 
156         ///     The 'extraFlags' parameter is used to pass in any other flags you need, 
157         ///     besides Public, NonPublic and Instance.
158         /// </devdoc>
159         internal static object SecureConstructorInvoke(Type type, Type[] argTypes, object[] args, 
160                                                        bool allowNonPublic, BindingFlags extraFlags) {
161             if (type == null) {
162                 throw new ArgumentNullException("type");
163             }
164    
165             // if it's an internal type, we demand reflection permission.
166             if (!type.IsVisible) {
167                 DemandReflectionAccess(type);
168             }
169             else if (allowNonPublic && !HasReflectionPermission(type)) {
170                 // Someone is trying to invoke a ctor on a public type, but does not
171                 // have full reflection permission. We shouldn't pass BindingFlags.NonPublic in this case.
172                 allowNonPublic = false;
173             }
174
175             BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | extraFlags;
176             if (!allowNonPublic) {
177                 flags &= ~BindingFlags.NonPublic;
178             }
179
180             ConstructorInfo ctor = type.GetConstructor(flags, null, argTypes, null);
181             if (ctor != null) {
182                 return ctor.Invoke(args);
183             }
184
185             return null;
186         }
187
188         private static bool GenericArgumentsAreVisible(MethodInfo method) {
189             if (method.IsGenericMethod) {
190                 Type[] parameterTypes = method.GetGenericArguments();
191                 foreach (Type type in parameterTypes) {
192                     if (!type.IsVisible) {
193                         return false;
194                     }
195                 }
196             }
197             return true;
198         }
199        
200         /// <devdoc>
201         ///     This helper method provides safe access to FieldInfo's GetValue method.
202         /// </devdoc>
203         internal static object FieldInfoGetValue(FieldInfo field, object target) {
204             Type type = field.DeclaringType;
205             if (type == null) {
206                 // Type is null for Global fields.
207                 if (!field.IsPublic) {
208                     DemandGrantSet(field.Module.Assembly);
209                 }
210             } else if (!(type != null && type.IsVisible && field.IsPublic)) {
211                 DemandReflectionAccess(type);
212             }
213             return field.GetValue(target);
214         }
215
216         /// <devdoc>
217         ///     This helper method provides safe access to MethodInfo's Invoke method.
218         /// </devdoc>
219         internal static object MethodInfoInvoke(MethodInfo method, object target, object[] args) {
220             Type type = method.DeclaringType;
221             if (type == null) {
222                 // Type is null for Global methods. In this case we would need to demand grant set on 
223                 // the containing assembly for internal methods.
224                 if (!(method.IsPublic && GenericArgumentsAreVisible(method))) {
225                     DemandGrantSet(method.Module.Assembly);
226                 }
227             } else if (!(type.IsVisible && method.IsPublic && GenericArgumentsAreVisible(method))) {
228                 // this demand is required for internal types in system.dll and its friend assemblies. 
229                 DemandReflectionAccess(type);
230             }
231             return method.Invoke(target, args);
232         }
233
234         /// <devdoc>
235         ///     This helper method provides safe access to ConstructorInfo's Invoke method.
236         ///     Constructors can't be generic, so we don't check if argument types are visible
237         /// </devdoc>
238         internal static object ConstructorInfoInvoke(ConstructorInfo ctor, object[] args) {
239             Type type = ctor.DeclaringType;
240             if ((type != null) && !(type.IsVisible && ctor.IsPublic)) {
241                 DemandReflectionAccess(type);
242             }
243             return ctor.Invoke(args);
244         }
245
246         /// <devdoc>
247         ///     This helper method provides safe access to Array.CreateInstance.
248         /// </devdoc>
249         internal static object ArrayCreateInstance(Type type, int length) {
250             if (!type.IsVisible) {
251                 DemandReflectionAccess(type);
252             }
253             return Array.CreateInstance(type, length);
254         }
255 #endif
256     }
257 }