harmony-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Leo Li" <liyilei1...@gmail.com>
Subject [classlib][URLClassLoader]Recursively loading class problem.
Date Thu, 08 Mar 2007 05:24:17 GMT
Hi, all:
     URLClassLoader might recursively loading class which is in a signed
jar and the class is one of the security provider
     For example,when URLClassLoader tries to load the class
org.bouncycastle.jce.provider.BouncyCastleProvider, which is a security
provider of Harmony and is in a signed jar bcprov.jar:

     *public static void main(String[] args) throws Exception{
       URLClassLoader urlClassLoader = (URLClassLoader) Thread.currentThread
().getContextClassLoader();
       urlClassLoader.loadClass("
org.bouncycastle.jce.provider.BouncyCastleProvider");
    }*

     Harmony will fail with such stacktrace:

   *  Exception in thread "main" java.lang.NullPointerException
 at java.util.jar.JarVerifier.verifyCertificate(JarVerifier.java:316)
 at java.util.jar.JarVerifier.readCertificates(JarVerifier.java:246)
 at java.util.jar.JarFile.getInputStream(JarFile.java:349)
 at java.net.URLClassLoader.findClassImpl(URLClassLoader.java:188)
 at java.net.URLClassLoader$4.run(URLClassLoader.java:624)
 at java.net.URLClassLoader$4.run(URLClassLoader.java:1)
 at java.security.AccessController.doPrivileged(AccessController.java:21)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:621)
 at com.ibm.oti.vm.URLSystemClassLoader.findClass(URLSystemClassLoader.java
:27)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:637)
 at com.ibm.oti.vm.URLSystemClassLoader.loadClass(URLSystemClassLoader.java
:60)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:620)
 at com.ibm.oti.vm.URLSystemClassLoader.loadClass(URLSystemClassLoader.java
:60)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:594)
 at Test.main(Test.java:7)*

     After digging into it, I found that it is because when the
URLClassLoader tries to open bcprov.jar to get the
org.bouncycastle.jce.provider.BouncyCastleProvider class, in

     * is = jf.getInputStream(entry);  //URLClassLoader.java:188*
**
     JarFile found that the bcprov.jar is signed by SHA1withDSA(
1.3.14.3.2.26with1.2.840.10040.4.1) and incurs the security providers to be
loaded. During this procedure,
org.bouncycastle.jce.provider.BouncyCastleProvider, as a security provider
should also be loaded. Then in the calling stack we can see that:

    URLClassLoader to load
org.bouncycastle.jce.provider.BouncyCastleProvider -> open signed bcprov.jar->
JarVerifier.verifyCertificate ->Signature.getInstance ->
org.apache.harmony.security.fortress.Services to load all security providers
in -> URLClassLoader load
org.bouncycastle.jce.provider.BouncyCastleProvider->open signed bcprov.jar->
JarVerifier.verifyCertificate->Signature.getInstance

    Although the loop is not infinite, since
org.apache.harmony.security.fortress.Services will break the loop by stop
further searching by
    *needRefresh = false*
   as a flag, but URLClassLoader adopts a JarFile caching mechanism so that
the first call to open signed bcprov.jar and the second one use the same
JarFile object and subsequent the same JarVerifier. Since the
JarVerifier.verifyCertificate() is not designed to be capable of
reentering thus some internal data, such as the metaEntries is corrupted
thus leads to exception.

    In my opinion, to cancel the caching mechanism in URLClassLoader or
overthrow the archive module design is not wise. Aside from all the
troubles, it will let us pay in performance. Besides, I will mention later,
even this will not sovle the problem: the current vms, both j9 and drlvm, do
not permit recursive class loading in URLClassLoader.findClassImpl().

   So my solution is :
          1. In JarVerifier.verifiCertificate, if the metaData is null, we
can deduce that an recursive loading class occurs and then just return since
the verification has been done in the completed recursive call.
          2. Another issue is in URLClassLoader.findClassImpl, if duplicate
or recursive calling defineClassImpl() to define the same class in a
single findClassImpl(), VM sill throw LinkageError. So after getting the
JarInputStream, we can test if the  class has already been loaded by
findLoadedClass(). If so, we can conclude that a recursive class loading
has occured and just return the loaded class to the caller.

   I have reported it as HARMONY-3332 and if there is no object I will give
a patch for it.
-- 
Leo Li
China Software Development Lab, IBM

Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message