Policy Levels

for RuBoard

Now we have code groups and code group hierarchies made up of membership conditions and permission sets. These aren't quite enough to understand security policy, though. Policy levels complete the picture.

This section will cover the following points about policy levels:

  • The contents of a policy level

  • The four different policy levels

  • How to work with policy levels

Policy Level Contents

First, policy levels are represented by the System.Security.Policy.PolicyLevel class. This class has no public constructor because policy levels cannot be constructed arbitrarily. Rather, the system creates policy levels that can be enumerated by calling the method System.Security.SecurityManager.PolicyHierarchy .

Policy levels are constructed by the system using three different, but related items. The first is a list of named permission sets. The second is a code group hierarchy. The third is a list of "full trust" assemblies.

Named Permission Set List

The list of named permission sets has two kinds of permission sets. The first are immutable permission sets. These are permission sets that the system defined and cannot change. The immutable permission sets are as follows :

  • Nothing ” This permission set is empty. It contains no references to any individual permissions.

  • Execution ” This permission set only contains the Execution flag of the SecurityPermission . Code granted to just this permission set will only be able to execute. It will not be allowed to perform any trusted actions, such as reading files or accessing the network.

  • SkipVerification ” This permission set contains only the SkipVerification flag of the SecurityPermission . Code that is granted this permission is allowed to bypass type safety rules normally enforced by the .NET Framework. Code that can bypass these rules can effectively do anything, so this permission should be granted with care.

  • Internet ” This permission set contains a set of permissions you may judge appropriate for code from the Internet zone. This includes permissions to execute, store a limited amount of information on the client, display UI, access files listed by the user , and print documents.

  • LocalIntranet ” This permission set contains a set of permissions deemed safe by authors of the Common Language Runtime for code loaded from the local intranet. This includes everything from the Internet permission set and the ability to read some environment variables , emit assemblies using reflection APIs, use the event log, use DNS services, and assert permissions.

  • FullTrust ” This permission set is simply a permission set marked as unrestricted. It contains no references to individual permissions. Any permission that implements the IUnrestrictedPermission interface is completely enclosed by this permission set, even if it is not a permission that ships as part of the .NET Framework. The only shipping permissions that do not implement this interface are the identity permissions described in Chapter 6, "Permissions: The Workhorse of Code Access Security."

In addition to these immutable permission sets, there is one default mutable permission set. It is named Everything and contains every permission shipped with the .NET Framework. Each permission it contains is unrestricted except the SecurityPermission . The SecurityPermission in the Everything set is missing the SkipVerification flag. Thus, this permission set should cover everything except the ability to skip verification.

TIP

The Everything permission set can be helpful to compiler writers. It is highly desirable for compilers to emit verifiable code for the security benefits. (See Chapter 11, "Verification and Validation: The Backbone of .NET Framework Security," for details on code verification.) Running " caspol .exe -machine -chggroup MyComputer_Zone Everything " changes the default security policy on a machine so unverifiable code will fail to execute when run from the local machine.


Permission sets can be added to this list. Any added permission sets will always be mutable.

Code Group Hierarchy

The code group hierarchy in a policy level is its primary information. This hierarchy always has one root code group that can have any number of children down to any depth.

Each code group in the hierarchy is exactly the same as the code groups mentioned earlier in this chapter. The permission sets used in the code groups must come from the permission set list. That is, no permission set can be mentioned in a code group unless it is in the permission set list.

When an assembly is evaluated against a code group hierarchy, the root code group will come up with a single permission set based on that assembly's evidence. That permission set is the permission grant for the assembly according to the policy level. By default, an assembly being loaded is assumed to have no permissions. Thus, unless some permission is granted by the policy level, the assembly will not be granted that permission.

"Full Trust" Assembly List

One issue that arises during security policy resolution is that recursive loads may be necessary. Take the permission System.Net.DnsPermission as an example. This permission lies in the assembly System.dll . When a policy level is loaded, all referenced assemblies must be loaded, so if a permission set in the policy level being loaded contains the DnsPermission , the assembly System.dll must be loaded by the policy system. However, when System.dll is being loaded, its granted permission set must be determined, which will cause the policy levels to get loaded again. This is a never-ending cycle between policy level loading and System.dll grant set determination.

To break the recursive policy load problem, policy levels have a list of "fully trusted" assemblies. While policy levels are being loaded and assembly references are being resolved, any assembly in the list is assumed to have been granted all permissions. In the example with DnsPermission , System.dll is assumed to be fully trusted while the policy level is being loaded.

Whenever you create a custom security class (for example, a custom permission) that you want to add to a policy level, you must first add the assembly containing that class to the policy level's full trust assembly list. Skipping this step will cause policy errors whenever a .NET Framework application is launched. If you get into a state where an assembly was not added to the full trust list when it was supposed to have been, you will have to edit or erase the file containing that policy level.

The Four Policy Levels

Now that we know what a policy level contains, it may be perplexing to find out that the .NET Framework has four policy levels: Enterprise, Machine, User, and Application Domain. To understand the reasoning for this, we should look at how the levels work together and the benefits of having four different levels.

How Policy Levels Interact

Each policy level is independent of every other policy level. The permission set list, code group hierarchy, and assembly list could be different in each level. The only way they come together is through the way their results are assessed.

During policy resolution of an assembly, the assembly's evidence is evaluated against each policy level individually. This is done in the SecurityManager.ResolvePolicy method. Each policy level's code group hierarchy has a permission set that it returns. The permission sets from each level are intersected by calling PermissionSet.Intersect to determine the overall allowable permission set for the assembly. By intersecting the permission sets from each policy level, each policy level determines a maximum permission set.

In addition to ResolvePolicy , which calls Resolve on each policy level, SecurityManager has the ResolvePolicyGroups method that calls ResolveMatchingCodeGroups on each policy level. The results are used by administration tools to display all the code groups that match an assembly.

Benefits of Having Four Policy Levels

The reason for having multiple policy levels addresses the problem of how to handle the intentions of disparate parties. Specifically, the network administrator, the administrator of a machine, a .NET Framework application user, and a .NET Framework developer can all apply specific policies to meet different goals. Each party is given an equal part in determining permission grants of .NET Framework assemblies. Every policy level has a "suggested" policy grant, and the system determines the lowest common denominator of all the different suggestions.

As shown in Figure 8.3, the enterprise level, which is administered by network administrators, affects all machines in a organization. The machine level, which is administered by machine administrators, affects all users on a machine. The user level, which is controlled by individual users, affects all app domains in programs run by that user. Developers control app domain policy levels for the programs they write.

Figure 8.3. The scope of the four different policy levels.

graphics/08fig03.gif

The Enterprise, Machine, and User policy levels are loaded from configuration files on the machine. The purpose of the AppDomain level is to allow a developer to restrict the rights of code he or she wants to execute. It doesn't make sense for an administrator or user to be able to do anything with this level, so there are no policy files for the AppDomain level.

For an example of how these different policy levels might be used, take the case of Julie, a company X employee who browses the Web over lunch . To run managed content from the Web, she changed the default security policy to grant the "Internet" permission set to code from the Internet zone. The IT department of company X may only want its employees to be able to execute mobile code if it comes from a small list of software publishers (identified by Authenticode signatures) it deems safe. It can deploy an enterprise policy that makes this restriction on all its employees . So, when Julie executes code from one of these publishers, code runs without problem, although she is not able to run code from any other publisher. Note that she could not add software publishers, as only the least common denominator of the policy levels are taken, and the enterprise policy level was deployed by the IT department to make this restriction.

The LevelFinal PolicyStatementAttribute can be used to restrict what "lower" policy levels can do. The policy levels listed from "highest" to "lowest" are Enterprise, Machine, and User. If an assembly matches a code group with the LevelFinal attribute, no lower policy levels are evaluated for that assembly. The AppDomain level is always evaluated if it exists, regardless of the LevelFinal attribute. In the previous example, if the IT department marked the code group for the safe Web sites with the LevelFinal attribute, Julie would not be able to further restrict code coming from the safe Web sites.

Working with Policy Levels

While there are four different policy levels, only three of them, Enterprise, Machine, and User, are actually persisted to files. The locations of those files are listed in Table 8.3. The AppDomain level is special in that it can only be created programmatically.

Table 8.3. Locations of the Policy Level Files
Policy Level File Location
Enterprise <.NET Framework Version-Specific Root Directory> \config\enterprisesec.config
Machine <.NET Framework Version-Specific Root Directory> \config\security.config
User (Windows NT, Windows 2000, and Windows XP) %userprofile%\Application Data\Microsoft\CLR Security Config\ <.NET Framework Version> \security.config
User (Windows 98 and Windows Me) %windir%\ <username> \Microsoft\CLR Security Config\ <.NET Framework Version> \security.config

Chapter 18 covers the use of the Common Language Runtime Configuration Tool. This GUI tool has some simple ways to modify the Enterprise, Machine, and User policy levels. In addition, it can be used to create MSI files that contain the policy level files. These MSI files can be used to deploy standard policy files to different machines.

Chapter 19 covers the use of caspol.exe , a tool that can script policy changes to the Enterprise, Machine, and User policy levels. This chapter also covers programmatic changes to security policy levels, including the AppDomain level.

If you want to enumerate the PolicyLevel objects that correspond to the different policy levels, you can simply call the System.Security.SecurityManager.PolicyHierarchy method. Each PolicyLevel object in the enumeration can be distinguished by looking at its Label property. This property is a nonlocalized string that contains one of the following: "Enterprise" , "Machine" , "User" , or "AppDomain" . If an application didn't set AppDomain policy, no PolicyLevel object exists for that level. The PolicyLevel objects also have the property StoreLocation that points to the file where the policy level was loaded, if it was loaded from a file.

NOTE

When the .NET Framework is installed, there actually are no policy files installed on the computer. Instead, the Common Language Runtime has some hard-coded defaults for the different policy levels. Whenever a managed program is executed for the first time, the security policy files are written to disk. Thus, if a policy file exists for a given policy level, the .NET Framework will use it. If no policy file exists for a given level, the hard-coded defaults are used.


As mentioned earlier in the chapter, each policy level has a permission set list, a code group hierarchy, and an assembly list. On PolicyLevel objects, these correspond to the NamedPermissionSets property, the RootCodeGroup property, and the FullTrustAssemblies property, respectively.

for RuBoard


. NET Framework Security
.NET Framework Security
ISBN: 067232184X
EAN: 2147483647
Year: 2000
Pages: 235

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net