Security Issues in Reflection Emit

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

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 .NET Framework. See Version Information, later in this article.

Dynamic Assemblies

Dynamic assemblies are created by using overloads of the AppDomain.DefineDynamicAssembly method. Most overloads of this method are deprecated in .NET Framework 4, because of the elimination of machine-wide security policy. The remaining overloads can be executed by any code, regardless of trust level. These overloads fall into two groups: those that specify a list of attributes to apply to the dynamic assembly when it is created, and those that do not. If you do not specify the transparency model for the assembly, by applying the SecurityRulesAttribute attribute when you create it, the transparency model is inherited from the emitting assembly.

Note

Attributes that you apply to the dynamic assembly after it is created, by using the SetCustomAttribute method, do not take effect until the assembly has been saved to disk and loaded into memory again.

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.

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 assembly is not saved to disk.

  • Debug symbols are not generated. (Internet and LocalIntranet permission sets do not include the necessary permissions.)

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, Type[]) and DynamicMethod(String, Type, 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 CIL 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.

If the application domain permits it, 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 is enabled if the application domain grants 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.

The system assembly that hosts anonymously-hosted dynamic methods uses the SecurityRuleSet.Level1 transparency model, which is the transparency model that was used in .NET Framework before .NET Framework 4.

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 .NET Framework 4, machine-wide security policy is eliminated and security transparency becomes the default enforcement mechanism.

Starting with .NET Framework 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 .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 .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. .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, .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, .NET Framework 2.0 SP1 introduces anonymously hosted methods.

Obtaining Information on Types and Members

Starting with .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 .NET Framework require ReflectionPermission with the ReflectionPermissionFlag.TypeInformation flag. For more information, see Security Considerations for Reflection.

See also