Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JNI cannot find class in signed JAR since JRE 8u232

I have a Java application with a signed JAR that contains all the class files and resources. The application is shipped with a bundled JRE and an executable. This executable is written with C++ and uses JNI to load a VM and launch the application. This worked flawlessly in the past.

Starting with JRE 8u232 (e.g. Azul, but also 8u231 from Oracle) the application no longer runs because the specified main class cannot be found with JNI's FindClass() function. It returns a null pointer and when I then call the ExceptionDescribe() function it shows a NPE occuring in the Java method JarVerifier::processEntry:

Exception in thread "main" java.lang.NullPointerException
    at java.util.jar.JarVerifier.processEntry(JarVerifier.java:303)
    at java.util.jar.JarVerifier.update(JarVerifier.java:230)
    at java.util.jar.JarFile.initializeVerifier(JarFile.java:383)
    at java.util.jar.JarFile.ensureInitialization(JarFile.java:612)
    at java.util.jar.JavaUtilJarAccessImpl.ensureInitialization(JavaUtilJarAccessImpl.java:69)
    at sun.misc.URLClassPath$JarLoader$2.getManifest(URLClassPath.java:991)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:451)
    at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:351)

When I remove the *.RSA and *.SF files from the JAR's META-INF folder it works again. It also works when I call the "java" executable from the JRE's "bin" folder, like so:

java -cp "path/to/my/jar" org.company.name.MyMainclass

It looks to me, that something has changed regarding Java 8 (or newer) that is causing this problem. However I cannot find the cause. What could be the issue here?

Update:

I did some remote debugging with the JarVerifier class and observed the following:

  • JarVerifier::process accesses the hashmap sigFileData multiple times (line no. 303) with get()
  • at some point JarVerifier::doneWithMeta is called which sets the map to null before its get() method is called again
  • this only happens when launching the application via JNI

Update 2:

I found out what causes the problem and got my application to work again, but I do not understand why. The executable that starts the application reads a text file with several parameters to pass to the VM (e.g. system properties, main class name, etc). One parameter sets the system property java.util.logging.config.file to a logging.properties file in the same directory. That property file begins like this:

handlers = org.mycompany.juli2log4j.JuliToLog4jHandler
.handlers = org.mycompany.juli2log4j.JuliToLog4jHandler

These statements and the handler class were written 10 years ago. When I remove the ".handlers" statement, my application works and logging still seems to be working fine.

What puzzles me the most is how this line would cause the NullPointerException in the JarVerifier class on application start. How can that be? What is the connection?

like image 431
Andreas N Avatar asked Jan 16 '20 21:01

Andreas N


1 Answers

The LogManager documentation suggests .handlers is invalid because it is missing the logger specifier:

A property "<logger>.handlers". This defines a whitespace or comma separated list of class names for handlers classes to load and register as handlers to the specified logger. Each class name must be for a Handler class which has a default constructor. Note that these Handlers may be created lazily, when they are first used.

My guess is 8u232 introduced a change that no longer handles (or infers) a missing logger name. Either there is likely a mapping to null that didn't used to exist and/or a new reference to the null keyed logger.

like image 158
Scott Avatar answered Nov 05 '22 11:11

Scott