Name: js151677 Date: 04/19/2004
FULL PRODUCT VERSION :
java version "1.4.2"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.4.2-b28)
Java HotSpot(TM) Client VM (build 1.4.2-b28, mixed mode)
java version "1.5.0-beta"
Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0-beta-b32c)
Java HotSpot(TM) Client VM (build 1.5.0-beta-b32c, mixed mode)
FULL OS VERSION :
SuSE Linux 7.1 (i386)
VERSION = 7.1
Kernel: 2.2.18
Can be reproducible on WindowsXP,Solaris.
A DESCRIPTION OF THE PROBLEM :
The cause of the problem is a call to ProtectionDomain.toString() inside the method implies() of a custom java.security.Policy implementation. If this method returns false, then an infinite recursion starts:
ProtectionDomain.toString() calls ProtectionDomain.seeAllp() which in turn checks permissions and thus ends up in calling Policy.implies().
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Compile PolicyTest.java
2. Put PolicyTest.class and test.policy into one directory
3. run:
java -Djava.security.manager -Djava.security.auth.policy=test.policy PolicyTest
wait for the StackOverflowError.
Alternatively you can run this through a debugger, putting breakpoints at lines 17 and 28 (17: System.getProperty(), 28: ProtectionDomain.toString()) of PolicyTest.java.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Of course, an empty Policy implementation makes no sense, but I am planning to implement a custom Policy so I will need logging information. Calling toString() is quite natural for that purpose so it should be fail-safe in any case.
ACTUAL -
The result is a recursion between ProtectionDomain.toString() and Policy.implies() (and other methods inbetween).
ERROR MESSAGES/STACK TRACES THAT OCCUR :
This is the output from the debugger showing the stack with one recursion:
implies():28, PolicyTest$EmptyPolicy
implies():189, java.security.ProtectionDomain
checkPermission():254, java.security.AccessControlContext
checkPermission():401, java.security.AccessController
checkPermission():524, java.lang.SecurityManager
seeAllp():241, java.security.ProtectionDomain
toString():220, java.security.ProtectionDomain
valueOf():2131, java.lang.String
append():361, java.lang.StringBuffer
implies():28, PolicyTest$EmptyPolicy
implies():189, java.security.ProtectionDomain
checkPermission():254, java.security.AccessControlContext
checkPermission():401, java.security.AccessController
checkPermission():524, java.lang.SecurityManager
checkPropertyAccess():1276, java.lang.SecurityManager
getProperty():573, java.lang.System
main():17, PolicyTest
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
You need PolicyTest.java and test.policy:
/*
* PolicyTest.java
*/
import java.security.*;
import java.io.*;
/**
* Calling ProtectionDomain.toString() on a Policy that returns false from
* implies(), causes a stack overflow.
*/
public class PolicyTest
{
public static void main(String[] args) throws Exception
{
EmptyPolicy.setPolicy(new EmptyPolicy());
System.out.println("Installed empty policy");
System.out.println("Your home directory is " + System.getProperty("user.home"));
}
static class EmptyPolicy extends Policy
{
public EmptyPolicy()
{
}
public boolean implies(ProtectionDomain domain, Permission permission)
{
System.out.println("implies called with ProtectionDomain " + domain + " Permission " + permission);
//return deferredPolicy.implies(domain, permission);
return false;
}
public PermissionCollection getPermissions(CodeSource codesource)
{
System.out.println("getPermissions called for codesource " + codesource);
//PermissionCollection pc = deferredPolicy.getPermissions(codesource);
System.out.println("returning " + null);
return null;
}
public PermissionCollection getPermissions(ProtectionDomain domain)
{
System.out.println("getPermissions called for ProtectionDomain " + domain);
//PermissionCollection pc = deferredPolicy.getPermissions(domain);
System.out.println("returning " + null);
return null;
}
public void refresh()
{
System.out.println("refreshing policy (no implementation)");
}
}
}
--------------------------------------------------------------------------
/*
* test.policy
*/
grant codeBase "file:."
{
permission java.security.SecurityPermission "setPolicy";
};
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Don't call ProtectionDomain.toString():
public boolean implies(ProtectionDomain domain, Permission permission)
{
// causes StackOverflowError:
//System.out.println("ProtectionDomain " + domain
// + " Permission " + permission);
System.out.println("ProtectionDomain " + domain.getCodeSource()
+ " Permission " + permission);
return false;
}
(Incident Review ID: 191392)
======================================================================