Udostępnij za pośrednictwem


Security Issues in Reflection Emit

The .NET Framework provides three ways to emit Microsoft intermediate language (MSIL), each with its own security issues:

  • Dynamic assemblies

  • Anonymously hosted dynamic methods

  • Dynamic methods associated with existing assemblies

Regardless of the way you generate dynamic code, executing the generated code requires all the permissions that are required by the types and methods the generated code uses.

Note

The permissions that are required for reflecting on code and emitting code have changed with succeeding releases of the .NET Framework. See Version Information, later in this topic.

Dynamic Assemblies

Dynamic assemblies are created by using overloads of the AppDomain.DefineDynamicAssembly method. The permissions that are required depend on the overload that is used. Overloads that supply evidence, for example, require SecurityPermission with the SecurityPermissionFlag.ControlEvidence flag. Some overloads require no permissions and can be called from code that has only Internet permissions.

Code in a dynamic assembly can access visible types and members in other assemblies.

Note

Dynamic assemblies do not use the ReflectionPermissionFlag.MemberAccess and ReflectionPermissionFlag.RestrictedMemberAccess flags that allow dynamic methods to access nonpublic types and members.

Generating code with debug symbols requires ReflectionPermission with the ReflectionPermissionFlag.ReflectionEmit flag.

Transient dynamic assemblies are created in memory and never saved to disk, so they require no file access permissions. Saving a dynamic assembly to disk requires FileIOPermission with the appropriate flags.

Generating Dynamic Assemblies from Partially Trusted Code

Consider the conditions in which an assembly with Internet permissions can generate a transient dynamic assembly and execute its code:

  • The dynamic assembly uses only public types and members of other assemblies.

  • The permissions demanded by those types and members are included in the grant set of the partially trusted assembly.

  • The DefineDynamicAssembly method overload that is used to create the dynamic assembly requires no special permissions (that is, no evidence is supplied, and so on).

  • The assembly is not saved to disk.

  • Debug symbols are not generated. (Internet and LocalIntranet permission sets do not include the ReflectionPermissionFlag.ReflectionEmit flag.)

Establishing Permissions for Dynamic Assemblies

In the following list, "emitter" is the assembly that generates the dynamic assembly.

  • An emitter that has SecurityPermission with the SecurityPermissionFlag.ControlEvidence flag can supply evidence for the generated code. This evidence is mapped through policy to determine the granted permissions.

  • An emitter can supply null evidence, in which case the assembly gets the permission set of the emitter. This ensures that the generated code does not have more permissions than its emitter.

  • If you supply permission sets with SecurityAction.RequestMinimum, SecurityAction.RequestOptional, or SecurityAction.RequestRefuse, those permission sets do not get used until the assembly has been saved to disk and then loaded from disk.

  • After a dynamic assembly has been saved to disk, the assembly is treated like any other assembly that is loaded from disk.

  • Code that is generated by semi-trusted emitters is always verified. Specifically, the runtime always verifies code that does not have SecurityPermission with the SecurityPermissionFlag.SkipVerification flag. Fully trusted emitters can skip verification or require the generated code to be verified.

Anonymously Hosted Dynamic Methods

Anonymously hosted dynamic methods are created by using the two DynamicMethod constructors that do not specify an associated type or module, DynamicMethod(String, Type, array<Type[]) and DynamicMethod(String, Type, array<Type[], Boolean). These constructors place the dynamic methods in a system-provided, fully trusted, security-transparent assembly. No permissions are required to use these constructors or to emit code for the dynamic methods.

Instead, when an anonymously hosted dynamic method is created, the call stack is captured. When the method is constructed, security demands are made against the captured call stack.

Note

Conceptually, demands are made during the construction of the method. That is, demands could be made as each MSIL instruction is emitted. In the current implementation, all demands are made when the DynamicMethod.CreateDelegate method is called or when the just-in-time (JIT) compiler is invoked, if the method is invoked without calling CreateDelegate.

Anonymously hosted dynamic methods can skip JIT visibility checks, subject to the following restriction: The nonpublic types and members accessed by an anonymously hosted dynamic method must be in assemblies whose grant sets are equal to, or subsets of, the grant set of the emitting call stack. This restricted ability to skip JIT visibility checks requires ReflectionPermission with the ReflectionPermissionFlag.RestrictedMemberAccess flag.

  • If your method uses only public types and members, no permissions are required during construction.

  • If you specify that JIT visibility checks should be skipped, the demand that is made when the method is constructed includes ReflectionPermission with the ReflectionPermissionFlag.RestrictedMemberAccess flag and the grant set of the assembly that contains the nonpublic member that is being accessed.

Because the grant set of the nonpublic member is taken into consideration, partially trusted code that has been granted ReflectionPermissionFlag.RestrictedMemberAccess cannot elevate its privileges by executing nonpublic members of trusted assemblies.

As with any other emitted code, executing the dynamic method requires whatever permissions are demanded by the methods the dynamic method uses.

For more information, see the DynamicMethod class.

Generating Anonymously Hosted Dynamic Methods from Partially Trusted Code

Consider the conditions in which an assembly with Internet permissions can generate an anonymously hosted dynamic method and execute it:

  • The dynamic method uses only public types and members. If its grant set includes ReflectionPermissionFlag.RestrictedMemberAccess, it can use nonpublic types and members of any assembly whose grant set is equal to, or a subset of, the grant set of the emitting assembly.

  • The permissions that are required by all the types and members used by the dynamic method are included in the grant set of the partially trusted assembly.

Note

Dynamic methods do not support debug symbols.

Dynamic Methods Associated with Existing Assemblies

To associate a dynamic method with a type or module in an existing assembly, use any of the DynamicMethod constructors that specify the associated type or module. The permissions that are required to call these constructors vary, because associating a dynamic method with an existing type or module gives the dynamic method access to nonpublic types and members:

  • A dynamic method that is associated with a type has access to all members of that type, even private members, and to all internal types and members in the assembly that contains the associated type.

  • A dynamic method that is associated with a module has access to all the internal types and members (Friend in Visual Basic, assembly in common language runtime metadata) in the module.

In addition, you can use a constructor that specifies the ability to skip the visibility checks of the JIT compiler. Doing so gives your dynamic method access to all types and members in all assemblies, regardless of access level.

The permissions demanded by the constructor depend on how much access you decide to give your dynamic method:

Although the items in this list are described in terms of the grant set of the emitting assembly, remember that the demands are made against the full call stack, including the application domain boundary.

For more information, see the DynamicMethod class.

Generating Dynamic Methods from Partially Trusted Code

Note

The recommended way to generate dynamic methods from partially trusted code is to use anonymously hosted dynamic methods.

Consider the conditions in which an assembly with Internet permissions can generate a dynamic method and execute it:

  • Either the dynamic method is associated with the module or type that emits it, or its grant set includes ReflectionPermissionFlag.RestrictedMemberAccess and it is associated with a module in an assembly whose grant set is equal to, or a subset of, the grant set of the emitting assembly.

  • The dynamic method uses only public types and members. If its grant set includes ReflectionPermissionFlag.RestrictedMemberAccess and it is associated with a module in an assembly whose grant set is equal to, or a subset of, the grant set of the emitting assembly, it can use types and members marked internal (Friend in Visual Basic, assembly in common language runtime metadata) in the associated module.

  • The permissions demanded by all the types and members used by the dynamic method are included in the grant set of the partially trusted assembly.

  • The dynamic method does not skip JIT visibility checks.

Note

Dynamic methods do not support debug symbols.

Version Information

Starting with the .NET Framework version 2.0 Service Pack 1, ReflectionPermission with the ReflectionPermissionFlag.ReflectionEmit flag is no longer required when emitting dynamic assemblies and dynamic methods. This flag is required in all earlier versions of the .NET Framework.

Note

ReflectionPermission with the ReflectionPermissionFlag.ReflectionEmit flag is included by default in the FullTrust and LocalIntranet named permission sets, but not in the Internet permission set. Therefore, in earlier versions of the .NET Framework, a library can be used with Internet permissions only if it executes an Assert for ReflectionEmit. Such libraries require careful security review because coding errors could result in security holes. The .NET Framework 2.0 SP1 allows code to be emitted in partial trust scenarios without issuing any security demands, because generating code is not inherently a privileged operation. That is, the generated code has no more permissions than the assembly that emits it. This allows libraries that emit code to be security transparent and removes the need to assert ReflectionEmit, which simplifies the task of writing a secure library.

In addition, the .NET Framework 2.0 SP1 introduces the ReflectionPermissionFlag.RestrictedMemberAccess flag for accessing nonpublic types and members from partially trusted dynamic methods. Earlier versions of the .NET Framework require the ReflectionPermissionFlag.MemberAccess flag for dynamic methods that access nonpublic types and members; this is a permission that should never be granted to partially trusted code.

Finally, the .NET Framework 2.0 SP1 introduces anonymously hosted methods.

To use these features, your application should target the .NET Framework version 3.5. For more information, see .NET Framework 3.5 Architecture.

Obtaining Information on Types and Members

Starting with the .NET Framework 2.0, no permissions are required to obtain information about nonpublic types and members. Reflection is used to obtain information needed to emit dynamic methods. For example, MethodInfo objects are used to emit method calls. Earlier versions of the .NET Framework require ReflectionPermission with the ReflectionPermissionFlag.TypeInformation flag. For more information, see Security Considerations for Reflection.

See Also

Concepts

Security Considerations for Reflection

Other Resources

Emitting Dynamic Methods and Assemblies