Permission scoping prevents permissions granted to a trusted component from being misused (either inadvertently or intentionally) by a less trusted component. A trusted class can precisely limit the range of code for which a granted permission is enabled. This is an important issue because some methods that use enhanced permissions are designed to be safely called by anyone, while other methods are designed to be used internally by trusted callers only and should not expose their permissions to less trusted callers.
Trust-based security distinguishes between permissions that have been granted to a class and permissions that are actually enabled at a particular time. The granted permissions are determined by the administrative options for a class's zone and by the permissions with which the class was signed. In contrast, enabled permissions are determined by the permissions granted to other callers on the call stack and by any calls that were made to the assertPermission, denyPermission, and revertPermission methods. If there are any less trusted callers on the call stack, the enabled permissions can be more restrictive than the granted permissions.
When the Microsoft VM implements permission scoping, two rules are followed. The first rule is that permissions are never inherited from the caller. If a class has not been directly granted a permission, it can never make use of that permission, regardless of what permissions its callers may have. This makes trust-based security invulnerable to "luring" attacks, in which an untrusted class "lures" a trusted class into calling it so that the untrusted class is allowed to make use of the expanded permissions of its caller.
The second rule is that even if a class has been granted a permission, its methods must explicitly enable that permission using the assertPermission method whenever there is a caller on the call stack that has not been granted that permission. In other words, permission P is enabled only if either statement 1 or 2 listed below is true, and if statement 3 is true.
The deep security checks of the PolicyEngine class perform the stack crawl that follows the above rules. The Java APIs contain calls to the StandardSecurityManager checkXX methods, which in turn call the PolicyEngine.checkPermission methods to check for a particular permission.
The methods of the PolicyEngine class allows you to control which permissions are enabled. For example, the following code sample asserts the right to access scratch space through the com.ms.io.clientstorage APIs, then reverts this right.
import com.ms.security.*; import com.ms.io.clientstorage.*; // Assert the right to access the // com.ms.io.clientstorage APIs. PolicyEngine.assertPermission(PermissionID.CLIENTSTORE); // Now open a file for writing. Because rights have been // asserted, this check will succeed even if the callers // do not possess the CLIENTSTORE permission. OutputStream os = ClientStorageManager.openWritable("Scratch1.txt"); ... // Remove the scratch space assertion. PolicyEngine.revertPermission(PermissionID.CLIENTSTORE); ... // Open a file for reading. // This time the callers will be included in the // security check because the right to access the // com.ms.io.clientstorage APIs is no longer asserted. // The security check will succeed only if all callers // have the appropriate CLIENTSTORE permission. InputStream is = ClientStorageManager.openReadable("Scratch2.txt"); ...
For more information on asserting, denying, and reverting permissions, see the com.ms.security overview. For more information about how the stack crawl for security checks is implemented, see the overview for the PolicyEngine class.