United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
Bug ID: JDK-6552236 PolicyFile not synchronized during refresh
JDK-6552236 : PolicyFile not synchronized during refresh

Details
Type:
Bug
Submit Date:
2007-05-01
Status:
Closed
Updated Date:
2011-05-02
Project Name:
JDK
Resolved Date:
2011-05-02
Component:
security-libs
OS:
generic
Sub-Component:
java.security
CPU:
generic
Priority:
P3
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Backport:
Backport:

Sub Tasks

Description
sun.security.provider.PolicyFile assumes that the internal policy state is read-only (that it can not change once the policy data has been read in).  In a multi-threaded environment, however, asynchronous refreshes can affect policy state.

The following is a rudimentary way to reproduce the problem:

1. Change PolicyFile.getPermissions:

  private Permissions getPermissions(Permissions perms,
                                     final CodeSource cs,
                                     Principal[] principals) {
    int numEntries = policyInfo.policyEntries.size();
    try {
        Thread.currentThread().sleep(5000);
    } catch (Exception e) {
    }
    PolicyEntry entry;
    for (int i = 0; i < numEntries; i++) {

    // remainder is the same

2. Run this test program:

  import java.security.AllPermission;
  import java.security.Policy;

  public class Refresh extends Thread {

    private boolean refresh;    // call Policy.refresh versus Policy.implies

    public Refresh(boolean refresh) {
        this.refresh = refresh;
    }

    public void run() {
        if (refresh) {
            while (true) {
                Policy.getPolicy().refresh();
            }
        } else {
            while (true) {
                Policy.getPolicy().implies
                                (getClass().getProtectionDomain(),
                                new AllPermission());
            }
        }
    }

    public static void main(String[] args) throws Exception {
        Refresh implies = new Refresh(false);
        implies.start();

        Refresh refresh = new Refresh(true);
        refresh.start();
    }
  }

3. During the 5 seconds PolicyFile puts the "implies" thread to sleep, update:
  ~/lib/security/java.policy

  Remove one of the grant entries.
  Save the file.

4. Observe this exception:

  angeles(218):java Refresh
  Exception in thread "Thread-0" java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
     at java.util.ArrayList.RangeCheck(ArrayList.java:547)
     at java.util.ArrayList.get(ArrayList.java:322)
     at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1261)
     at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1223)
     at sun.security.provider.PolicyFile.getPermissions(PolicyFile.java:1165)
     at sun.security.provider.PolicyFile.implies(PolicyFile.java:1120)
     at Refresh.run(Refresh.java:19)

                                    

Comments
SUGGESTED FIX

See attached webrev.refresh.zip for a very lightly tested fix.

This fix has performance implications because causes more synchronization (contention) on a shared object.  One potential alternative solution is to use a java.util.concurrent.lock.ReadWriteLock instead of a mutual exclusive lock.


*** (#1 of 1): [ UNSAVED ] ###@###.###
                                     
2007-05-01
EVALUATION

The race condition was caused by the code accessing different fields of
the shared PolicyInfo object without locking it. During a refresh,
another thread could replace the PolicyInfo object, causing
unpredictable behavior.

The fix I came up was to store the PolicyInfo in an AtomicReference
object, which doesn't use locks. This fix performed much better than
the suggested fix using locks, which caused a 5-10% drop in my
tests with large number of threads (due to the lock contention).

I also cleaned up the rest of the synch code a little:

- I wrapped the aliasMapping and identityPolicyEntries fields of the
PolicyInfo class in synchronized collections. This delegated the locking
to the collections and I was able to remove some of the locking
(synchronized blocks) in the PolicyFile code, although a lock is still
needed when iterating over the entries.
                                     
2007-08-03



Hardware and Software, Engineered to Work Together