1 //------------------------------------------------------------------------------
2 // <copyright file="SecurityUtils.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
11 #if Microsoft_NAMESPACE
12 namespace System
.Windows
.Forms
13 #elif DRAWING_NAMESPACE
14 namespace System
.Drawing
15 #elif Microsoft_PUBLIC_GRAPHICS_LIBRARY
16 namespace System
.Internal
17 #elif SYSTEM_NAMESPACE
21 #elif SYSTEM_DATA_LINQ
22 namespace System
.Data
.Linq
24 namespace System
.Windows
.Forms
28 using System
.Reflection
;
29 using System
.Diagnostics
.CodeAnalysis
;
30 using System
.Security
;
31 using System
.Security
.Permissions
;
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.
38 internal static class SecurityUtils
{
41 private static volatile ReflectionPermission memberAccessPermission
= null;
42 private static volatile ReflectionPermission restrictedMemberAccessPermission
= null;
44 private static ReflectionPermission MemberAccessPermission
47 if (memberAccessPermission
== null) {
48 memberAccessPermission
= new ReflectionPermission(ReflectionPermissionFlag
.MemberAccess
);
50 return memberAccessPermission
;
54 private static ReflectionPermission RestrictedMemberAccessPermission
{
56 if (restrictedMemberAccessPermission
== null) {
57 restrictedMemberAccessPermission
= new ReflectionPermission(ReflectionPermissionFlag
.RestrictedMemberAccess
);
59 return restrictedMemberAccessPermission
;
64 private static void DemandReflectionAccess(Type type
) {
67 MemberAccessPermission
.Demand();
69 catch (SecurityException
) {
70 DemandGrantSet(type
.Assembly
);
75 [SecuritySafeCritical
]
76 private static void DemandGrantSet(Assembly assembly
) {
78 PermissionSet targetGrantSet
= assembly
.PermissionSet
;
79 targetGrantSet
.AddPermission(RestrictedMemberAccessPermission
);
80 targetGrantSet
.Demand();
84 private static bool HasReflectionPermission(Type type
) {
87 DemandReflectionAccess(type
);
90 catch (SecurityException
) {
101 /// This helper method provides safe access to Activator.CreateInstance.
102 /// NOTE: This overload will work only with public .ctors.
104 internal static object SecureCreateInstance(Type type
) {
105 return SecureCreateInstance(type
, null, false);
110 /// This helper method provides safe access to Activator.CreateInstance.
111 /// Set allowNonPublic to true if you want non public ctors to be used.
113 internal static object SecureCreateInstance(Type type
, object[] args
, bool allowNonPublic
) {
115 throw new ArgumentNullException("type");
118 BindingFlags flags
= BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.CreateInstance
;
120 // if it's an internal type, we demand reflection permission.
121 if (!type
.IsVisible
) {
122 DemandReflectionAccess(type
);
124 else if (allowNonPublic
&& !HasReflectionPermission(type
)) {
125 // Someone is trying to instantiate a public type in *our* assembly, but does not
126 // have full reflection permission. We shouldn't pass BindingFlags.NonPublic in this case.
127 // The reason we don't directly demand the permission here is because we don't know whether
128 // a public or non-public .ctor will be invoked. We want to allow the public .ctor case to
130 allowNonPublic
= false;
133 if (allowNonPublic
) {
134 flags
|= BindingFlags
.NonPublic
;
137 return Activator
.CreateInstance(type
, flags
, null, args
, null);
140 #if (!Microsoft_NAMESPACE)
143 /// This helper method provides safe access to Activator.CreateInstance.
144 /// NOTE: This overload will work only with public .ctors.
146 internal static object SecureCreateInstance(Type type
, object[] args
) {
147 return SecureCreateInstance(type
, args
, false);
152 /// Helper method to safely invoke a .ctor. You should prefer SecureCreateInstance to this.
153 /// Set allowNonPublic to true if you want non public ctors to be used.
155 internal static object SecureConstructorInvoke(Type type
, Type
[] argTypes
, object[] args
, bool allowNonPublic
) {
156 return SecureConstructorInvoke(type
, argTypes
, args
, allowNonPublic
, BindingFlags
.Default
);
160 /// Helper method to safely invoke a .ctor. You should prefer SecureCreateInstance to this.
161 /// Set allowNonPublic to true if you want non public ctors to be used.
162 /// The 'extraFlags' parameter is used to pass in any other flags you need,
163 /// besides Public, NonPublic and Instance.
165 internal static object SecureConstructorInvoke(Type type
, Type
[] argTypes
, object[] args
,
166 bool allowNonPublic
, BindingFlags extraFlags
) {
168 throw new ArgumentNullException("type");
171 // if it's an internal type, we demand reflection permission.
172 if (!type
.IsVisible
) {
173 DemandReflectionAccess(type
);
175 else if (allowNonPublic
&& !HasReflectionPermission(type
)) {
176 // Someone is trying to invoke a ctor on a public type, but does not
177 // have full reflection permission. We shouldn't pass BindingFlags.NonPublic in this case.
178 allowNonPublic
= false;
181 BindingFlags flags
= BindingFlags
.Instance
| BindingFlags
.Public
| BindingFlags
.NonPublic
| extraFlags
;
182 if (!allowNonPublic
) {
183 flags
&= ~BindingFlags
.NonPublic
;
186 ConstructorInfo ctor
= type
.GetConstructor(flags
, null, argTypes
, null);
188 return ctor
.Invoke(args
);
194 private static bool GenericArgumentsAreVisible(MethodInfo method
) {
195 if (method
.IsGenericMethod
) {
196 Type
[] parameterTypes
= method
.GetGenericArguments();
197 foreach (Type type
in parameterTypes
) {
198 if (!type
.IsVisible
) {
207 /// This helper method provides safe access to FieldInfo's GetValue method.
209 internal static object FieldInfoGetValue(FieldInfo field
, object target
) {
210 Type type
= field
.DeclaringType
;
212 // Type is null for Global fields.
213 if (!field
.IsPublic
) {
214 DemandGrantSet(field
.Module
.Assembly
);
216 } else if (!(type
!= null && type
.IsVisible
&& field
.IsPublic
)) {
217 DemandReflectionAccess(type
);
219 return field
.GetValue(target
);
223 /// This helper method provides safe access to MethodInfo's Invoke method.
225 internal static object MethodInfoInvoke(MethodInfo method
, object target
, object[] args
) {
226 Type type
= method
.DeclaringType
;
228 // Type is null for Global methods. In this case we would need to demand grant set on
229 // the containing assembly for internal methods.
230 if (!(method
.IsPublic
&& GenericArgumentsAreVisible(method
))) {
231 DemandGrantSet(method
.Module
.Assembly
);
233 } else if (!(type
.IsVisible
&& method
.IsPublic
&& GenericArgumentsAreVisible(method
))) {
234 // this demand is required for internal types in system.dll and its friend assemblies.
235 DemandReflectionAccess(type
);
237 return method
.Invoke(target
, args
);
241 /// This helper method provides safe access to ConstructorInfo's Invoke method.
242 /// Constructors can't be generic, so we don't check if argument types are visible
244 internal static object ConstructorInfoInvoke(ConstructorInfo ctor
, object[] args
) {
245 Type type
= ctor
.DeclaringType
;
246 if ((type
!= null) && !(type
.IsVisible
&& ctor
.IsPublic
)) {
247 DemandReflectionAccess(type
);
249 return ctor
.Invoke(args
);
253 /// This helper method provides safe access to Array.CreateInstance.
255 internal static object ArrayCreateInstance(Type type
, int length
) {
256 if (!type
.IsVisible
) {
257 DemandReflectionAccess(type
);
259 return Array
.CreateInstance(type
, length
);