-
1. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
alesj Jan 11, 2010 3:42 PM (in response to samz)To solve my deadlock and infinite loop issue, I'd like to know if it's configurable to disable the dependency on java.security.Policy, or specify a different Java Policy for VFSClassLoaderPolicy.
You can change the CLPolicy, by changing the CLDeployer.
See VFSClassLoaderDescribeDeployer in conf/bootstrap/deployers.xml.
Can you provide a thread snapshot of this lock and post it here?
-
2. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
samz Jan 11, 2010 6:43 PM (in response to alesj)See the attached log files-
infiniteloop.txt.zip 1.8 KB
-
dealock.txt.zip 1.9 KB
-
-
3. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
samz Jan 11, 2010 6:41 PM (in response to alesj)
In the following bean descriptor of conf/bootstrap/deployers.xml,
<bean name="ClassLoaderDescribeDeployer" class="org.jboss.deployers.vfs.plugins.classloader.VFSClassLoaderDescribeDeployer">
<property name="classLoading"><inject bean="ClassLoading"/></property>
</bean>
Is it possible to specify a different ClassLoaderPolicy to replace the default VFSClassLoaderPolicy for the system classloader? -
4. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
adrian.brock Jan 12, 2010 11:17 AM (in response to samz)I don't think this is a JBoss issue.
I can reproduce the problem with a slightly modified URLClassLoader - the modification is only to move the test.support.* classes(including the policy implementation) outside the bootstrap classloader.
package test; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.net.URL; import java.net.URLClassLoader; import java.security.CodeSource; import java.security.PermissionCollection; import java.security.Policy; import java.security.ProtectionDomain; public class EmulateNonBootstrapClassLoader extends URLClassLoader { public EmulateNonBootstrapClassLoader() { super(new URL[0]); } protected synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { System.out.println ("loadClass: " + name); if (name.startsWith("test.support")) { byte[] buffer = loadByteCode(name); ProtectionDomain pd = getProtectionDomain(); return defineClass(name, buffer, 0, buffer.length, pd); } return super.loadClass(name, resolve); } private byte[] loadByteCode(String name) throws ClassNotFoundException { try { String resourceName = name.replace('.', '/') + ".class"; InputStream stream = getResourceAsStream(resourceName); ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] buffer = new byte[1024]; int bytes = stream.read(buffer); while (bytes >= 0) { baos.write(buffer, 0, bytes); bytes = stream.read(buffer); } return baos.toByteArray(); } catch (Exception e) { throw new ClassNotFoundException("CNFE: " + name, e); } } private ProtectionDomain getProtectionDomain() { // The actual codesource doesn't matter it is in the classloading in getPermissions that causes the problem CodeSource cs = getClass().getProtectionDomain().getCodeSource(); PermissionCollection pc = Policy.getPolicy().getPermissions(cs); return new ProtectionDomain(cs, pc); } }
The key issue is that the policy is loading classes from the non-bootstrap classloader which leads to recursion/deadlock
i.e. it can't define the policy for the new class until it can load the new class.
So I created a simple policy that does a classloading request from the same classloader during getPermissions().
package test.support; import java.security.CodeSource; import java.security.PermissionCollection; import java.security.Policy; public class TestPolicyProvider extends Policy { public PermissionCollection getPermissions(CodeSource cs) { try { getClass().getClassLoader().loadClass("test.support.B"); } catch (ClassNotFoundException e) { throw new Error("Error loading B", e); } return super.getPermissions(cs); } }
The test driver is the following
package test; import java.security.Policy; public class Main { public static void main(String[] args) throws Exception { // Create a non-bootstrap classloader ClassLoader cl = new EmulateNonBootstrapClassLoader(); // Load the policy provider from it Class<?> clazz = cl.loadClass("test.support.TestPolicyProvider"); dumpClass(clazz); // Create a new instance and install it Policy policy = (Policy) clazz.newInstance(); Policy.setPolicy(policy); // Now try to load a class, it will loop when the policy tries to load test.support.B clazz = cl.loadClass("test.support.A"); dumpClass(clazz); } public static void dumpClass(Class<?> clazz) { System.out.println(clazz.getName() + " cl=" +clazz.getClassLoader() + " pd=" + clazz.getProtectionDomain()); } }
The classes A and B are just simple empty classes. The important part is they are not in the bootstrap classloader.
CONCLUSION:
None of the code above contains any jboss specific code. The issue is caused by where the Policy's support classes are located.
This is only works out of the box if the Policy implementation and its support classes are in the bootstrap classloader, i.e. the classpath.
You can see this if you change the first line of Main to use ClassLoader.getSystemClassLoader().
Presumably the bootstrap classloader is doing something special to avoid the problem?
-
5. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
adrian.brock Jan 12, 2010 11:32 AM (in response to adrian.brock)A simple workaround would be to preload the Policy's support classes before installing it.
In this case, it looks to be a custom principal class from the stack trace?
-
6. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
samz Jan 12, 2010 6:33 PM (in response to adrian.brock)Thank you for reproducing this issue clearly. I agreed the simplest and best solution is to use bootstrap classloader for custom policy povider and its dependent classes. On the flip side, it also points out that JBoss classloader has issue with custom policy provider in Java policy classloading, if the policy provider is loaded by system classloader and the policies with new class instances are not loaded at server startup before it's set as the default policy provider, the infinite loop problem may occur.
-
7. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
samz Feb 9, 2010 12:55 AM (in response to alesj)Any docs for configuring VFSClassLoaderDescribeDeployer in bootstrap/deployers.xml with regard to ClassLoaderPolicy? -
8. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
alesj Feb 9, 2010 7:58 AM (in response to samz)Any docs for configuring VFSClassLoaderDescribeDeployer in bootstrap/deployers.xml with regard to ClassLoaderPolicy?
I played around this in my demos and DZone article:
* http://java.dzone.com/articles/jboss-microcontainer-classloading
-
9. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
samz Feb 10, 2010 12:50 AM (in response to alesj)Thank you for the reply. I'm following your example and looking into the approach to create custom ClassLoaderPolicyModule, ClassLoaderDescribeDeployer and ClassLoaderPolicy and by-pass the getProtectionDomain() and fix this issue.
In method determinePolicy() of DecrypterClassLoaderPolicyModule which inherits VFSDeploymentClassLoaderPolicyModule, it calls getRoots() and getExcludedRoots() when instantiating CrypterClassLoaderPolicy, it doesn't seem that both methods are part of VFSDeploymentClassLoaderPolicyModule or its parent classes.
CrypterClassLoaderPolicy(getContextName(), getRoots(), getExcludedRoots(), decrypter);
Am I miss anything here?
-
10. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
alesj Feb 10, 2010 4:45 AM (in response to samz)In method determinePolicy() of DecrypterClassLoaderPolicyModule which inherits VFSDeploymentClassLoaderPolicyModule, it calls getRoots() and getExcludedRoots() when instantiating CrypterClassLoaderPolicy, it doesn't seem that both methods are part of VFSDeploymentClassLoaderPolicyModule or its parent classes.
CrypterClassLoaderPolicy(getContextName(), getRoots(), getExcludedRoots(), decrypter);
Am I miss anything here?
You're probably looking at an older version:
-
11. Re: Deadlock and infinite loop between BaseClassLoader and Java Policy Provider
samz Feb 16, 2010 3:36 PM (in response to adrian.brock)In JDK 1.4 or later, it introduced a new constructor of ProtectionDomain to defer Policy.getPermissions(Codesource) until evaluating Java 2 policies in security contexts, see ProtectionDomain(CodeSource codesource, PermissionCollection permissions, ClassLoader classloader, Principal[] principals), which was desigend to support dynamic policy loading.
With this approach, I created a custom ClassLoaderPolicy and replaced the default one in bootstrap/deployers.xml, and it solves the deadlock and infinite loop issue I have on JBoss. I think JBoss should take the advantage of this approach in the default ClassLoaderPolicy VFSClassLoaderPolicy, and support dynamical policy loading and refreshing.