76e02fafbaf129d1df896e79c433af109780ea35
[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             try {
64                 MemberAccessPermission.Demand();
65             }
66             catch (SecurityException) {
67                 DemandGrantSet(type.Assembly);
68             }
69         }
70
71         [SecuritySafeCritical]
72         private static void DemandGrantSet(Assembly assembly) {
73             PermissionSet targetGrantSet = assembly.PermissionSet;
74             targetGrantSet.AddPermission(RestrictedMemberAccessPermission);
75             targetGrantSet.Demand();
76         }
77
78         private static bool HasReflectionPermission(Type type) {
79             try {
80                 DemandReflectionAccess(type);
81                 return true;
82             }
83             catch (SecurityException) {
84             }
85
86             return false;
87         }
88
89        
90         /// <devdoc>
91         ///     This helper method provides safe access to Activator.CreateInstance.
92         ///     NOTE: This overload will work only with public .ctors. 
93         /// </devdoc>
94         internal static object SecureCreateInstance(Type type) {
95             return SecureCreateInstance(type, null, false);
96         }
97
98
99         /// <devdoc>
100         ///     This helper method provides safe access to Activator.CreateInstance.
101         ///     Set allowNonPublic to true if you want non public ctors to be used. 
102         /// </devdoc>
103         internal static object SecureCreateInstance(Type type, object[] args, bool allowNonPublic) {
104             if (type == null) {
105                 throw new ArgumentNullException("type");
106             }
107
108             BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance;
109            
110             // if it's an internal type, we demand reflection permission.
111             if (!type.IsVisible) {
112                 DemandReflectionAccess(type);
113             }
114             else if (allowNonPublic && !HasReflectionPermission(type)) {
115                 // Someone is trying to instantiate a public type in *our* assembly, but does not
116                 // have full reflection permission. We shouldn't pass BindingFlags.NonPublic in this case.
117                 // The reason we don't directly demand the permission here is because we don't know whether
118                 // a public or non-public .ctor will be invoked. We want to allow the public .ctor case to
119                 // succeed.
120                 allowNonPublic = false;
121             }
122             
123             if (allowNonPublic) {
124                 flags |= BindingFlags.NonPublic;
125             }
126
127             return Activator.CreateInstance(type, flags, null, args, null);
128         }
129
130 #if (!WINFORMS_NAMESPACE)
131
132         /// <devdoc>
133         ///     This helper method provides safe access to Activator.CreateInstance.
134         ///     NOTE: This overload will work only with public .ctors. 
135         /// </devdoc>
136         internal static object SecureCreateInstance(Type type, object[] args) {
137             return SecureCreateInstance(type, args, false);
138         }
139
140
141         /// <devdoc>
142         ///     Helper method to safely invoke a .ctor. You should prefer SecureCreateInstance to this.
143         ///     Set allowNonPublic to true if you want non public ctors to be used. 
144         /// </devdoc>
145         internal static object SecureConstructorInvoke(Type type, Type[] argTypes, object[] args, bool allowNonPublic) {
146             return SecureConstructorInvoke(type, argTypes, args, allowNonPublic, BindingFlags.Default);
147         }
148
149         /// <devdoc>
150         ///     Helper method to safely invoke a .ctor. You should prefer SecureCreateInstance to this.
151         ///     Set allowNonPublic to true if you want non public ctors to be used. 
152         ///     The 'extraFlags' parameter is used to pass in any other flags you need, 
153         ///     besides Public, NonPublic and Instance.
154         /// </devdoc>
155         internal static object SecureConstructorInvoke(Type type, Type[] argTypes, object[] args, 
156                                                        bool allowNonPublic, BindingFlags extraFlags) {
157             if (type == null) {
158                 throw new ArgumentNullException("type");
159             }
160    
161             // if it's an internal type, we demand reflection permission.
162             if (!type.IsVisible) {
163                 DemandReflectionAccess(type);
164             }
165             else if (allowNonPublic && !HasReflectionPermission(type)) {
166                 // Someone is trying to invoke a ctor on a public type, but does not
167                 // have full reflection permission. We shouldn't pass BindingFlags.NonPublic in this case.
168                 allowNonPublic = false;
169             }
170
171             BindingFlags flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | extraFlags;
172             if (!allowNonPublic) {
173                 flags &= ~BindingFlags.NonPublic;
174             }
175
176             ConstructorInfo ctor = type.GetConstructor(flags, null, argTypes, null);
177             if (ctor != null) {
178                 return ctor.Invoke(args);
179             }
180
181             return null;
182         }
183
184         private static bool GenericArgumentsAreVisible(MethodInfo method) {
185             if (method.IsGenericMethod) {
186                 Type[] parameterTypes = method.GetGenericArguments();
187                 foreach (Type type in parameterTypes) {
188                     if (!type.IsVisible) {
189                         return false;
190                     }
191                 }
192             }
193             return true;
194         }
195        
196         /// <devdoc>
197         ///     This helper method provides safe access to FieldInfo's GetValue method.
198         /// </devdoc>
199         internal static object FieldInfoGetValue(FieldInfo field, object target) {
200             Type type = field.DeclaringType;
201             if (type == null) {
202                 // Type is null for Global fields.
203                 if (!field.IsPublic) {
204                     DemandGrantSet(field.Module.Assembly);
205                 }
206             } else if (!(type != null && type.IsVisible && field.IsPublic)) {
207                 DemandReflectionAccess(type);
208             }
209             return field.GetValue(target);
210         }
211
212         /// <devdoc>
213         ///     This helper method provides safe access to MethodInfo's Invoke method.
214         /// </devdoc>
215         internal static object MethodInfoInvoke(MethodInfo method, object target, object[] args) {
216             Type type = method.DeclaringType;
217             if (type == null) {
218                 // Type is null for Global methods. In this case we would need to demand grant set on 
219                 // the containing assembly for internal methods.
220                 if (!(method.IsPublic && GenericArgumentsAreVisible(method))) {
221                     DemandGrantSet(method.Module.Assembly);
222                 }
223             } else if (!(type.IsVisible && method.IsPublic && GenericArgumentsAreVisible(method))) {
224                 // this demand is required for internal types in system.dll and its friend assemblies. 
225                 DemandReflectionAccess(type);
226             }
227             return method.Invoke(target, args);
228         }
229
230         /// <devdoc>
231         ///     This helper method provides safe access to ConstructorInfo's Invoke method.
232         ///     Constructors can't be generic, so we don't check if argument types are visible
233         /// </devdoc>
234         internal static object ConstructorInfoInvoke(ConstructorInfo ctor, object[] args) {
235             Type type = ctor.DeclaringType;
236             if ((type != null) && !(type.IsVisible && ctor.IsPublic)) {
237                 DemandReflectionAccess(type);
238             }
239             return ctor.Invoke(args);
240         }
241
242         /// <devdoc>
243         ///     This helper method provides safe access to Array.CreateInstance.
244         /// </devdoc>
245         internal static object ArrayCreateInstance(Type type, int length) {
246             if (!type.IsVisible) {
247                 DemandReflectionAccess(type);
248             }
249             return Array.CreateInstance(type, length);
250         }
251 #endif
252     }
253 }