-
Bug
-
Resolution: Fixed
-
P3
-
1.2.1
-
beta
-
generic
-
generic
When a new policy is set at runtime ,by calling setPolicy, you would
expect it to have immediate and full effect. However, protection domains
from which classes where already loaded (via the SecureClassLoader)
continue to have privileges derived from the old policy. If the new
policy is stricter, a security hole may result without any indication
given. This results from the fact that SecureClassLoader has
a cache for protection domains, and so it consults the policy
only once per code-source, for the first time it loads a class
from that code source. Any changes in the policy afterwards
will not be reflected in the cache, even if a NEW class is
loaded from that code-source. Needless to say, classes which
were already loaded before the policy-change - continue to have
the old privileges. So actually there are 2 problems here:
1. Even if a new class is loaded after the policy change, from a code-source
from which another class has been loaded before the policy change - the new
class would still get the old privileges. This stems from the cache
in the SecureClassLoader. This is the more severe problem.
2. A class which was loaded before the policy-change, would continue to have
its privileges based on the old policy, because its protection domain
was already computed and a reference to it put in its Class class.
This is also a problem, and should either be fixed or at least
documented.
The following sources exemplify the first problem.
DynamicPolicy.java implements the dynamic policy. It simply
allows everything initially, and after it is refreshed -
allows nothing.
DynamicPolicy.java
------------------
import java.security.*;
import java.lang.*;
public class DynamicPolicy extends Policy{
static boolean refreshed=false;
public DynamicPolicy() {
System.out.println("Dynamic policy constructed...");
}
public PermissionCollection getPermissions(CodeSource cs) {
System.out.println("DynamicPolicy consulted...");
Permissions perms=new Permissions();
// Everything is allowed in the beginning...
// But after the refresh - everything should be prohibited...
if (!refreshed)
perms.add(new AllPermission());
return perms;
}
public void refresh() {
refreshed=true;
}
}
-----------------------------------------
There are 2 code-sources used for this test. The first is a JAR file containing TryAllPermission and
TryAllPermission1 classes (and their inner classes), and the second is a JAR file containing
SecondTryAllPermission class (and its inner class).
TestDynamicPolicy sets the new policy. It then causes TryAllPermission class to be called, and verifies
that it has all permissions allowed to it. Then, it calls the refresh method of the dynamic policy, which
now causes the policy to allow NOTHING. And indeed, for a new code-source - SecondTryAllPermission - which
is now loaded - nothing is allowed. But for TryAllPermission1, whose protection-domain is already cached -
still everything is allowed!! Note, that the launcher should be run with a security manager
enabled, and with a policy that enables the code to set and get the policy. javatest.jar should be
on the CLASSPATH.
TestDynamicPolicy.java
--------------------------------------
import java.io.PrintStream;
import java.io.IOException;
import javasoft.sqe.harness.Status;
import javasoft.sqe.harness.Test;
import java.lang.System;
import java.security.Policy;
public class TestDynamicPolicy implements Test {
public Status run(String args[], PrintStream log, PrintStream out) {
// A security manager must be installed
SecurityManager sm=System.getSecurityManager();
if (sm==null)
return Status.failed("Test must be run with a security manager installed");
// Instantiate and set the new policy
DynamicPolicy dp = new DynamicPolicy();
Policy.setPolicy(dp);
// Verify that policy has been set
if (dp != Policy.getPolicy())
return Status.failed("Policy was not set!!");
// Verify the TryALlPermission can do anything
TryAllPermission tap=new TryAllPermission();
if (tap.hasAllPermissions() != true)
// This should not happen
return Status.failed("Didn't get all permissions in the beginning!");
// Now, make policy prohibit everything
dp.refresh();
// Verify that a class at another URL cannot do anything
SecondTryAllPermission stap=new SecondTryAllPermission();
if (stap.hasAllPermissions() != false)
// This should not happen
return Status.failed("Everything should be prohibited, but is allowed for second protection domain");
// Now, verify that a class from a code source whose protection-domain
// WAS ALREADY CACHED has no permissions
TryAllPermission1 tap1=new TryAllPermission1();
if (tap1.hasAllPermissions() != false)
return Status.failed("Oops, a NEW class from first protection domain has all permissions which it shouldn't!");
return Status.passed("Passed the test");
}
public static void main(String args[]) {
Status s;
TestDynamicPolicy jstest = new TestDynamicPolicy();
s = jstest.run(args, System.err, System.out);
s.exit();
}
}
--------------------------------------------------------
When TestDynamicPolicy is run, the result is:
FAILED: Oops, a NEW class from first protection domain has all permissions which it shouldn't!
TryAllPermission.java
--------------------------------------------------------
import java.security.*;
import java.lang.System;
public class TryAllPermission {
public boolean hasAllPermissions() {
final AllPermission ap=new AllPermission();
final SecurityManager sm=System.getSecurityManager();
try {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// privileged code goes here, for example:
sm.checkPermission(ap);
return null; // nothing to return
}
});
return true;
} catch (SecurityException se) {
return false;
}
}
}
--------------------------------------------------------
TryAllPermission1.java
--------------------------------------------------------
import java.security.*;
import java.lang.System;
public class TryAllPermission1 {
public boolean hasAllPermissions() {
final AllPermission ap=new AllPermission();
final SecurityManager sm=System.getSecurityManager();
try {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// privileged code goes here, for example:
sm.checkPermission(ap);
return null; // nothing to return
}
});
return true;
} catch (SecurityException se) {
return false;
}
}
}
SecondTryAllPermission.java
--------------------------------------------------------
import java.security.*;
import java.lang.System;
public class SecondTryAllPermission {
public boolean hasAllPermissions() {
final AllPermission ap=new AllPermission();
final SecurityManager sm=System.getSecurityManager();
try {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// privileged code goes here, for example:
sm.checkPermission(ap);
return null; // nothing to return
}
});
return true;
} catch (SecurityException se) {
return false;
}
}
}
--------------------------------------------------------------
The test should be given the following permissions:
grant codeBase "file:testPath" {
permission java.security.SecurityPermission "setPolicy";
permission java.security.SecurityPermission "getPolicy";
};
expect it to have immediate and full effect. However, protection domains
from which classes where already loaded (via the SecureClassLoader)
continue to have privileges derived from the old policy. If the new
policy is stricter, a security hole may result without any indication
given. This results from the fact that SecureClassLoader has
a cache for protection domains, and so it consults the policy
only once per code-source, for the first time it loads a class
from that code source. Any changes in the policy afterwards
will not be reflected in the cache, even if a NEW class is
loaded from that code-source. Needless to say, classes which
were already loaded before the policy-change - continue to have
the old privileges. So actually there are 2 problems here:
1. Even if a new class is loaded after the policy change, from a code-source
from which another class has been loaded before the policy change - the new
class would still get the old privileges. This stems from the cache
in the SecureClassLoader. This is the more severe problem.
2. A class which was loaded before the policy-change, would continue to have
its privileges based on the old policy, because its protection domain
was already computed and a reference to it put in its Class class.
This is also a problem, and should either be fixed or at least
documented.
The following sources exemplify the first problem.
DynamicPolicy.java implements the dynamic policy. It simply
allows everything initially, and after it is refreshed -
allows nothing.
DynamicPolicy.java
------------------
import java.security.*;
import java.lang.*;
public class DynamicPolicy extends Policy{
static boolean refreshed=false;
public DynamicPolicy() {
System.out.println("Dynamic policy constructed...");
}
public PermissionCollection getPermissions(CodeSource cs) {
System.out.println("DynamicPolicy consulted...");
Permissions perms=new Permissions();
// Everything is allowed in the beginning...
// But after the refresh - everything should be prohibited...
if (!refreshed)
perms.add(new AllPermission());
return perms;
}
public void refresh() {
refreshed=true;
}
}
-----------------------------------------
There are 2 code-sources used for this test. The first is a JAR file containing TryAllPermission and
TryAllPermission1 classes (and their inner classes), and the second is a JAR file containing
SecondTryAllPermission class (and its inner class).
TestDynamicPolicy sets the new policy. It then causes TryAllPermission class to be called, and verifies
that it has all permissions allowed to it. Then, it calls the refresh method of the dynamic policy, which
now causes the policy to allow NOTHING. And indeed, for a new code-source - SecondTryAllPermission - which
is now loaded - nothing is allowed. But for TryAllPermission1, whose protection-domain is already cached -
still everything is allowed!! Note, that the launcher should be run with a security manager
enabled, and with a policy that enables the code to set and get the policy. javatest.jar should be
on the CLASSPATH.
TestDynamicPolicy.java
--------------------------------------
import java.io.PrintStream;
import java.io.IOException;
import javasoft.sqe.harness.Status;
import javasoft.sqe.harness.Test;
import java.lang.System;
import java.security.Policy;
public class TestDynamicPolicy implements Test {
public Status run(String args[], PrintStream log, PrintStream out) {
// A security manager must be installed
SecurityManager sm=System.getSecurityManager();
if (sm==null)
return Status.failed("Test must be run with a security manager installed");
// Instantiate and set the new policy
DynamicPolicy dp = new DynamicPolicy();
Policy.setPolicy(dp);
// Verify that policy has been set
if (dp != Policy.getPolicy())
return Status.failed("Policy was not set!!");
// Verify the TryALlPermission can do anything
TryAllPermission tap=new TryAllPermission();
if (tap.hasAllPermissions() != true)
// This should not happen
return Status.failed("Didn't get all permissions in the beginning!");
// Now, make policy prohibit everything
dp.refresh();
// Verify that a class at another URL cannot do anything
SecondTryAllPermission stap=new SecondTryAllPermission();
if (stap.hasAllPermissions() != false)
// This should not happen
return Status.failed("Everything should be prohibited, but is allowed for second protection domain");
// Now, verify that a class from a code source whose protection-domain
// WAS ALREADY CACHED has no permissions
TryAllPermission1 tap1=new TryAllPermission1();
if (tap1.hasAllPermissions() != false)
return Status.failed("Oops, a NEW class from first protection domain has all permissions which it shouldn't!");
return Status.passed("Passed the test");
}
public static void main(String args[]) {
Status s;
TestDynamicPolicy jstest = new TestDynamicPolicy();
s = jstest.run(args, System.err, System.out);
s.exit();
}
}
--------------------------------------------------------
When TestDynamicPolicy is run, the result is:
FAILED: Oops, a NEW class from first protection domain has all permissions which it shouldn't!
TryAllPermission.java
--------------------------------------------------------
import java.security.*;
import java.lang.System;
public class TryAllPermission {
public boolean hasAllPermissions() {
final AllPermission ap=new AllPermission();
final SecurityManager sm=System.getSecurityManager();
try {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// privileged code goes here, for example:
sm.checkPermission(ap);
return null; // nothing to return
}
});
return true;
} catch (SecurityException se) {
return false;
}
}
}
--------------------------------------------------------
TryAllPermission1.java
--------------------------------------------------------
import java.security.*;
import java.lang.System;
public class TryAllPermission1 {
public boolean hasAllPermissions() {
final AllPermission ap=new AllPermission();
final SecurityManager sm=System.getSecurityManager();
try {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// privileged code goes here, for example:
sm.checkPermission(ap);
return null; // nothing to return
}
});
return true;
} catch (SecurityException se) {
return false;
}
}
}
SecondTryAllPermission.java
--------------------------------------------------------
import java.security.*;
import java.lang.System;
public class SecondTryAllPermission {
public boolean hasAllPermissions() {
final AllPermission ap=new AllPermission();
final SecurityManager sm=System.getSecurityManager();
try {
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
// privileged code goes here, for example:
sm.checkPermission(ap);
return null; // nothing to return
}
});
return true;
} catch (SecurityException se) {
return false;
}
}
}
--------------------------------------------------------------
The test should be given the following permissions:
grant codeBase "file:testPath" {
permission java.security.SecurityPermission "setPolicy";
permission java.security.SecurityPermission "getPolicy";
};
- relates to
-
JDK-4364704 SubjectDomainCombiner should not cache Policy object
-
- Resolved
-
-
JDK-4364705 SubjectDomainCombiner assumes Subjects are immutable
-
- Resolved
-
-
JDK-4407532 java policy file is not recognised by Java Plugin Merlin build 48
-
- Closed
-
-
JDK-4412246 Wrong permissions assigned to javaws.jar
-
- Closed
-
-
JDK-4348484 RFE - delay loading PermissionCollection until needed
-
- Resolved
-