Documentation Contents

API for Privileged Blocks

This document provides background information about what privileged code is and what it is used for, followed by illustrations of the use of the API. It covers the following topics:

What It Means to Have Privileged Code

The policy for a JDK installation specifies what permissions — which types of system resource accesses — are allowed for code from specified code sources. A code source (of type CodeSource) essentially consists of the code location (URL) and a reference to the certificates containing the public keys corresponding to the private keys used to sign the code (if it was signed).

The policy is represented by a Policy object. More specifically, it is represented by a Policy subclass providing an implementation of the abstract methods in the Policy class (which is in the java.security package).

The source location for the policy information used by the Policy object depends on the Policy implementation. The Policy reference implementation obtains its information from policy configuration files. See Default Policy Implementation and Policy File Syntax for information about the Policy reference implementation and the syntax that must be used in policy files it reads. For information about using the Policy Tool to create a policy file (without needing to know the required syntax), see the Policy Tool documentation (for Unix) (for Windows).

A protection domain encompasses a CodeSource instance and the permissions granted to code from that CodeSource, as determined by the security policy currently in effect. Thus, classes signed by the same keys and from the same URL are typically placed in the same domain, and a class belongs to one and only one protection domain. (However, classes signed by the same keys and from the same URL but loaded by separate class loader instances are typically placed in separate domains.) Classes that have the same permissions but are from different code sources belong to different domains.

Currently, all classes shipped with the JDK are loaded with all permissions (this may change in future releases). Most of these classes are placed in a unique system domain. In addition, the extension class loader loads code from JAR files contained in the $JAVA_HOME/jre/lib/ext directory into separate domains (because the code in these JAR files have unique URLs), but these domains are separate from the unique system domain reserved for classes shipped with the JDK.

Each applet or application runs in its appropriate domain, determined by its code source. For an applet (or an application running under a security manager) to be allowed to perform a secured action (such as reading or writing a file), the applet or application must be granted permission for that particular action.

More specifically, whenever a resource access is attempted, all code traversed by the execution thread up to that point must have permission for that resource access, unless some code on the thread has been marked as privileged. That is, suppose that access control checking occurs in a thread of execution that has a chain of multiple callers. (Think of this as multiple method calls that potentially cross the protection domain boundaries.) When the AccessController.checkPermission method is invoked by the most recent caller, the basic algorithm for deciding whether to allow or deny the requested access is as follows: If the code for any caller in the call chain does not have the requested permission, then an AccessControlException is thrown, unless the following is true: a caller whose code is granted the said permission has been marked as privileged, and all parties subsequently called by this caller (directly or indirectly) have the said permission.

Note that the method AccessController.checkPermission is normally invoked indirectly through invocations of specific SecurityManager methods that begin with the word check such as checkConnect or through the method SecurityManager.checkPermission. Normally, these checks only occur if a SecurityManager has been installed; code checked by the AccessController.checkPermission method first checks if the method System.getSecurityManager returns null.

Marking code as privileged enables a piece of trusted code to temporarily enable access to more resources than are available directly to the code that called it. This is necessary in some situations. For example, an application might not be allowed direct access to files that contain fonts, but the system utility to display a document must obtain those fonts, on behalf of the user. The system utility must become privileged in order to obtain the fonts.

Using the doPrivileged API

The use of the privileged feature is described in the following sections.

No Return Value, No Exception Thrown

If you do not need to return a value from within the privileged block, your call to doPrivileged can look like the following example, which specifies privileged code three ways: in a class that implements the interface PrivilegedAction, in an anonymous class, and in a lambda expression:

import java.security.*;

public class NoReturnNoException {
    
    class MyAction implements PrivilegedAction<Void> {
        public Void run() {
            // Privileged code goes here, for example:
            System.loadLibrary("awt");
            return null; // nothing to return
        }
    }
    
    public void somemethod() {
           
        MyAction mya = new MyAction();
        
        // Become privileged:
        AccessController.doPrivileged(mya);
       
        // Anonymous class
        AccessController.doPrivileged(new PrivilegedAction<Void>() {
            public Void run() {
                // Privileged code goes here, for example:
                System.loadLibrary("awt");
                return null; // nothing to return
            }
        });
        
        // Lambda expression
        AccessController.doPrivileged((PrivilegedAction<Void>)
            () -> {
                // Privileged code goes here, for example:
                System.loadLibrary("awt");
                return null; // nothing to return
            }
        );
    }
    
    public static void main(String... args) {
        NoReturnNoException myApplication = new NoReturnNoException();
        myApplication.somemethod();
    }
}

The AccessController.doPrivileged method takes an object of type java.security.PrivilegedAction and invokes its run method in privileged mode. The implementation guarantees that privileges will be revoked after the run method is executed, even if execution of doPrivileged is interrupted by an asynchronous exception. Note that the invocation of doPrivileged with a lambda expression explicitly casts the lambda expression as of type PrivilegedAction<Void>. Another version of the method doPrivileged exists that takes an object of type PrivilegedExceptionAction; see Handling Exceptions for more information about this version.

PrivilegedAction is a functional interface with a single abstract method, named run, that returns a value of type specified by its type parameter.

Note that this example ignores the return value of the run method. Also, depending on what privileged code actually consists of, you might have to make some changes due to the way inner classes work. For example, if privileged code throws an exception or attempts to access local variables, then you will have to make some changes, which is described later.

Be very careful in your use of the privileged construct, and always remember to make the privileged code section as small as possible. That is, try to limit the code within the run method to only what needs to be run with privileges, and do more general things outside the run method. Also note that the call to doPrivileged should be made in the code that wants to enable its privileges. Do not be tempted to write a utility class that itself calls doPrivileged as that could lead to security holes. You can write utility classes for PrivilegedAction classes though, as shown in the preceding example. See Guideline 9-3: Safely invoke java.security.AccessController.doPrivileged in Secure Coding Guidelines for the Java Programming Language for more information.

Returning Values

If you need to return a value, then you can do something like the following:

System.out.println(
    AccessController.doPrivileged((PrivilegedAction<String>)
        () -> System.getProperty("user.name")
    )
);

Accessing Local Variables

If you are using a lambda expression or anonymous inner class, then any local variables you access must be final or effectively final. For example:

String lib = "awt";
AccessController.doPrivileged((PrivilegedAction<Void>)
    () -> {
        System.loadLibrary(lib);
        return null; // nothing to return
    }
); 
   
AccessController.doPrivileged(new PrivilegedAction<Void>() {
    public Object run() {
        System.loadLibrary(lib);
        return null; // nothing to return
    }        
});

The variable lib is effectively final because its value has not been modified. For example, suppose you add the following assignment statement after the declaration of the variable lib:

lib = "swing";

The compiler generates the following errors when it encounters the invocation System.loadLibrary both in the lambda expression and the anonymous class:

See Accessing Members of an Enclosing Class in Local Classes for more information.

If there are cases where you cannot make an existing variable effectively final (because it gets set multiple times), then you can create a new final variable right before invoking the doPrivileged method, and set that variable equal to the other variable. For example:

String lib;
    
// The lib variable gets set multiple times so you can't make it
// effectively final.
  
// Create a final String that you can use inside of the run method
final String fLib = lib;
    
AccessController.doPrivileged((PrivilegedAction<Void>)
    () -> {
        System.loadLibrary(fLib);
        return null; // nothing to return
    }
);

Handling Exceptions

If the action performed in your run method could throw a checked exception (one that must be listed in the throws clause of a method), then you need to use the PrivilegedExceptionAction interface instead of the PrivilegedAction interface:

public void processSomefile() throws IOException {

    try {
        Path path = FileSystems.getDefault().getPath("somefile");
        BufferedReader br = AccessController.doPrivileged(
            (PrivilegedExceptionAction<BufferedReader>)
                () -> Files.newBufferedReader(path)
        );
        // ... read from file and do something
    } catch (PrivilegedActionException e) {
    
        // e.getException() should be an instance of IOException
        // as only checked exceptions will be wrapped in a
        // PrivilegedActionException.
        throw (IOException) e.getException();
    }
}

If a checked exception is thrown during execution of the run method, then it is placed in a PrivilegedActionException wrapper exception that is then thrown and should be caught by your code, as illustrated in this example.

Asserting a Subset of Privileges

As of JDK 8, a variant of AccessController.doPrivileged is available that enables code to assert a subset of its privileges, without preventing the full traversal of the stack to check for other permissions. This variant of the doPrivileged variant has three parameters, one of which you use to specify this subset of privileges. For example, the following excerpt asserts a privilege to retrieve system properties:

// Returns the value of the specified property. All code
// is allowed to read the app.version and app.vendor
// properties.

public String getProperty(final String prop) {
    return AccessController.doPrivileged(
        (PrivilegedAction<String>) () -> System.getProperty(prop),
        null,
        new java.util.PropertyPermission("app.version", "read"),
        new java.util.PropertyPermission("app.vendor", "read")
    );
}

The first parameter of this version of doPrivileged is of type java.security.PrivilegedAction. In this example, the first parameter is a lambda expression that implements the functional interface PrivilegedAction whose run method returns the value of the system property specified by the parameter prop.

The second parameter of this version of doPrivileged is of type AccessControlContext. Sometimes you need to perform an additional security check within a different context, such as a worker thread. You can obtain an AccessControlContext instance from a particular calling context with the method AccessControlContext.getContext. If you specify null for this parameter (as in this example), then the invocation of doPrivileged does not perform any additional security checks.

The third parameter of this version of doPrivileged is of type Permission..., which is a varargs parameter. This means that you can specify one or more Permission parameters or an array of Permission objects, as in Permission[]. In this example, the invocation of doPrivileged can retrieve the properties app.version and app.vendor.

You can use this three parameter variant of doPrivileged in a mode of least privilege or a mode of more privilege.

Least Privilege

The typical use case of the doPrivileged method is to enable the method that invokes it to perform one or more actions that require permission checks without requiring the callers of the current method to have all the necessary permissions. For example, the current method might need to open a file or make a network request for its own internal implementation purposes.

Before JDK 8, calls to doPrivileged methods had only two parameters. They worked by granting temporary privileges to the calling method and stopping the normal full traversal of the stack for access checking when it reached that class, rather than continuing up the call stack where it might reach a method whose defining class does not have the required permission. Typically, the class that is calling doPrivileged might have additional permissions that are not required in that code path and which might also be missing from some caller classes.

Normally, these extra permissions are not exercised at runtime. Not elevating them through use of doPrivileged helps to block exploitation of any incorrect code that could perform unintended actions. This is especially true when the PrivilegedAction is more complex than usual, or when it calls code outside the class or package boundary that might evolve independently over time.

The three-parameter variant of doPrivileged is generally safer to use because it avoids unnecessarily elevating permissions that are not intended to be required. However, it executes less efficiently so simple or performance-critical code paths might choose not to use it.

More Privilege

Sometimes when coding the current method, you want to temporarily extend the permission of the calling method to perform an action. For example, a framework I/O API might have a general purpose method for opening files of a particular data format. This API would take a normal file path parameter and use it to open an underlying FileInputStream using the calling code's permissions. However, this might also allow any caller to open the data files in a special directory that contains some standard demonstration samples.

The callers of this API could be directly granted a FilePermission for read access. However, it might not be convenient or possible for the security policy of the calling code to be updated. For example, the calling code could be a sandboxed applet.

One way to implement this is for the code to check the incoming path and determine if it refers to a file in the special directory. If it does, then it would call doPrivileged, enabling all permissions, then open the file inside the PrivilegedAction. If the file was not in the special directory, the code would open the file without using doPrivileged.

This technique requires the implementation to carefully handle the requested file path to determine if it refers to the special shared directory. The file path must be canonicalized before calling doPrivileged so that any relative path will be processed (and permission to read the user.dir system property will be checked) prior to determining if the path refers to a file in the special directory. It must also prevent malicious "../" path elements meant to escape out of the special directory.

A simpler and better implementation would use the variant of doPrivileged with the third parameter. It would pass a FilePermission with read access to the special directory as the third parameter. Then any manipulation of the file would be inside the PrivilegedAction. This implementation is simpler and much less prone to contain a security flaw.

Reflection

One subtlety that must be considered is the interaction of this API with reflection. The doPrivileged method can be invoked reflectively using java.lang.reflect.Method.invoke. In this case, the privileges granted in privileged mode are not those of Method.invoke but of the non-reflective code that invoked it. Otherwise, system privileges could erroneously (or maliciously) be conferred on user code. Note that similar requirements exist when using reflection in the existing API.


Oracle and/or its affiliates Copyright © 1993, 2022, Oracle and/or its affiliates. All rights reserved.
Contact Us