Policy levels are instrumental elements of CAS policy. In both Figure 1
and Figure 2
, you'll notice three policy level nodes under Runtime Security Policy: Enterprise, Machine, and User. Another policy level, AppDomain doesn't appear because it is controlled by the developer rather than via configuration. Within each policy level is a set of code groups defining policy at that level. Policy is resolved by evaluating policy for each level, using code groups, and then resolving the final policy, using policy levels.
|Figure 3: Union of matching code groups in a single policy level.|
Inside of a policy level is a set of hierarchically organized code groups. Policy resolution begins at the top of the code group hierarchy, checking assembly evidence with the membership condition. If the assembly meets the membership condition of a given code group, it adds that code group's permission set to its set of permissions for that policy level. Additionally, when a membership condition is met, .NET evaluates code groups lower in the hierarchy. CAS policy traverses the entire code group hierarchy, gathering a set of permissions for every membership condition match within that policy level. The grant set of permissions belonging to that policy level is the union of all permissions for which a membership condition was met. This occurs for each policy level. Figure 3
illustrates the permission grant set, colored in gray, of an arbitrary policy level with three code groups whose membership conditions matched evidence on an assembly.
Once .NET computes the grant set for each policy level, the final set of permissions must be resolved. .NET determines the final grant set by calculating the intersection of all the policy levels. In Figure 4, the gray portion shows the intersection of the permission grant sets of the User, Machine, and Enterprise policy levels, which is the final permission set granted to an assembly. Although the AppDomain policy level is not shown in Figure 4, it also intersects with the other three policy levels.
|Figure 4: Intersection of policy levels for a final grant set of an assembly.|
The default CAS policy configuration gives the All_Code code group FullTrust permissions at the User and Enterprise policy levels. This effectively makes the Machine policy level control CAS policy a default configuration. This is important to pay attention to because accidentally applying policy to User or Enterprise can break a policy and would be hard to find and fix, unless that is what you explicitly want to do.
Exclusive and Level Final
While .NET normally resolves CAS policy through code group unions and policy level intersections, there are exceptions to this process that offer more control in setting policy for special circumstances. Two policy attributes, Exclusive and Level Final, are shown as check boxes at the bottom of Figure 5.
|Figure 5: The check boxes are attributes that modify policy resolution for Exclusive and Level Final.|
The Exclusive attribute applies when traversing the code group hierarchy within a single policy level. If the membership condition of a code group is matched and that code group is marked as Exclusive
, then the permission set for that code group will be the only permission set granted to an assembly at this policy level. Even if the membership conditions of other code groups at the same policy level match assembly evidence, their permissions will not be added to the assembly's permission grant set.
You use the Exclusive attribute to force an assembly to have no more permissions than those specified by a specific permission set. For example, if you wanted to guarantee that a given assembly did not receive any permission, you would create a code group with a membership condition matching some evidence for that assembly and give it the Nothing permission set.
Another policy statement attribute that alters default policy resolution is Level Final. If you place a Level Final on a code group at a given policy level and the assembly has evidence that matches the membership condition of that code group, none of the policy levels below that policy level will be evaluated. The hierarchy of policy levels starts with Enterprise at the top, then goes down to Machine, and finally ends at User.
The practical application of Level Final is to force a given policy on a system, preventing lower level policies from changing the policy in any way. For example, consider the System Administrator who needs to install an application that must run on every workstation in the company. They would set the policy for the assemblies belonging to that application at the Enterprise policy level. This means that settings at the Machine and User policy levels will not interfere in the policy set at the Enterprise policy level for that application's assemblies.
Another branch of the Runtime Security Policy node in the Microsoft .NET Framework 1.1 Configuration tool is the Policy Assemblies. Policy assemblies are those assemblies containing types used to resolve CAS policy.
To understand why you might add an assembly to policy assemblies, consider what happens at runtime when .NET evaluates a policy level. The CLR will load all assemblies that hold permission objects so that it can use them to resolve policy. However, anytime the CLR loads an assembly, it must resolve permissions for that assembly. This opens up a chicken and egg situation where an assembly containing permissions will continue to be loaded recursively. To solve this problem, all assemblies containing permission types are added to the policy assemblies list, giving them FullTrust permissions.