java jre 7u45 breaks classloader.getResources()?
Asked Answered
F

4

8

I have code to iterate over the results of classLoader.getResources("META-INF/MANIFEST.MF") to return the list of jars on the class path. This worked fine from 1.6.0_18 all the way to 1.7.0_40. Now 1.7.0_45 breaks this by showing a security warning popup about mixed signed/unsigned code.

Small self contained testcase to demonstrate problem:

package testcase;
import java.io.*;
import java.net.*;
import java.util.Enumeration;
import java.util.logging.*;
public class TestCase {
    public static void main(String[] args) {
        getAllJarUrls();
    }

    public static void getAllJarUrls() {
        try {
            final Enumeration<URL> mfUrls = Thread.currentThread().getContextClassLoader().getResources("META-INF/MANIFEST.MF");
            while (mfUrls.hasMoreElements()) {
                URL jarUrl = mfUrls.nextElement();
                if (!jarUrl.getProtocol().equals("jar")) {
                    continue;
                }
                try {
                    System.out.println(jarUrl.toURI());
                } catch (URISyntaxException ex) {
                    Logger.getLogger("testcase").log(Level.SEVERE, null, ex);
                }
            }
        } catch (IOException e) {
            Logger.getLogger("testcase").log(Level.SEVERE, null, e);
        }
    }
}

Launch this with a jnlp (jar signed with a valid certificate) as:

<?xml version="1.0" encoding="UTF-8"?>
<jnlp spec="1.0+" codebase="http://localhost/test" href="test.jnlp">
    <information>
        <title>test</title>
        <vendor>test</vendor>
      </information>
    <security><all-permissions/></security>
    <resources>
        <jar href="testcase.jar" main="true" download="eager"/>
    </resources>
    <application-desc main-class="testcase.TestCase"/>
</jnlp>

When run, have the console visible, and hit '5' for verbose output. then click 'block' on the security prompt to see the exception. Clicking allow will let the code run normally, but this is not an acceptable user experience. especially since our application has to be able to start without user input.

Output under 1.7.0_45 is as follows:

CacheEntry[http://localhost/test/testcase.jar]: updateAvailable=true,lastModified=Tue Oct 15 21:09:21 CDT 2013,length=6314
jar:file:/C:/jre32/1.7.0_45/lib/javaws.jar!/META-INF/MANIFEST.MF
jar:file:/C:/jre32/1.7.0_45/lib/deploy.jar!/META-INF/MANIFEST.MF
jar:file:/C:/jre32/1.7.0_45/lib/plugin.jar!/META-INF/MANIFEST.MF
jar:file:/C:/jre32/1.7.0_45/lib/deploy.jar!/META-INF/MANIFEST.MF
Trace level set to 5: all ... completed.Trace level set to 5: all ... completed.
security: resource name "META-INF/MANIFEST.MF" in http://localhost/test/testcase.jar : java.lang.SecurityException: trusted loader attempted to load sandboxed resource from http://localhost/test/testcase.jar

The testcase.jar is signed. It even has all the new manifest attributes included: Application-Name: testcase Permissions: all-permissions Codebase: *

A diff of the decompiled CPCallBackHandler from deploy.jar from 7u40 to 7u45 shows significant changes. It looks like the changes for LiveConnect have borked the existing functionality. And no, there's no LiveConnect involved here.

Has anyone else run into this? Suggestions for a workaround? File a bug?

(note: also posted on the OTN java forums, but I'm hoping for a faster answer here :).

Thanks, Chris

Foehn answered 16/10, 2013 at 3:8 Comment(6)
Surprisingly, OTN came through!! Just add 'Trusted-Library: true' to the manifest and all works as before.Foehn
I've filed java bug #9007507 for this.Foehn
can you provide a link for the bug?Cleghorn
It should be bugs.sun.com/view_bug.do?bug_id=9007507 but oracle hasn't made it public yet. I don't know how you get a bug made public. That's the first of 2 I've submitted in regards to this mess (7u45). The other was 9007571, which is a deadlock introduced in 7u45 webstart class loader.Foehn
Man, that sucks. I've reverted back to _40 for now. We have an older OSGi based application that is broken because of this. I guess there aren't that many OSGi + web start apps out there, or maybe they'd noticed it :)Cleghorn
Yes. 7u45 is one of the worst of the update rounds since 6u19. And that's saying something.Foehn
F
7

Add this to the manifest of the jar:

Trusted-Library: true

Documented here.

Foehn answered 16/10, 2013 at 5:37 Comment(1)
We too are experiencing the problem. All of our jars are signed and we are not using any unsigned code. Chris's solution seems to work, the only thing to note is that the Trusted-Libary:true Attribute changes the Classloader that is used to load the jar. Which may impact any jars that are not trusted (changes the classpath hierarchy) however if you do this to all of your jars, it should be okay. Though customer classloaders might have problemsHarragan
M
0

A warning though about the Trusted-Location - from the linked documentation -

The Trusted-Library attribute is used for applications and applets that are designed to allow untrusted components. No warning dialog is shown and an application or applet can load JAR files that contain untrusted classes or resources

So use this if you want to allow untrusted resources (is the way I read this).

The root of the problem is that the manifest iteration is including the unsigned resources associated with web-start itself (javaws.jar, deploy.jar).

I resolved my problem by using - JARDesc[] jars = JNLPClassLoader.getLaunchDesc().getResources().getEagerOrAllJarDescs(true);

Misconceive answered 16/10, 2013 at 20:12 Comment(1)
Adrian, Unfortunately, I have to get more than just the list of jars. This is in code that's a workaround for a more insidious webstart bug related to caching of jars within the webstart class loader. See java bug 6967414. They've claimed it's fixed in various releases, but they never really fixed it. The workaround is to convert soft references to hard references via a bunch of reflection. It's, in my opinion, one of the most troublesome java bugs I've run into in 15 years. By far.Foehn
S
0

We started experiencing a problem with classloader.getResourceAsStream() with 7u45. We had been getting by with signing the JARs but not embedding JNLP-INF/{APPLICATION.JNLP,APPLICATION_TEMPLATE.JNLP} (because we needed two unsigned application.jnlp variants, with different heap settings).

Anyway we fixed this problem by embedding JNLP-INF/APPLICATION_TEMPLATE.JNLP. Just posting in case anyone else has this particular problem.

Sailer answered 19/10, 2013 at 17:19 Comment(1)
I tried embedding the JNLP-INF/APPLICATION.JNLP but that actually didn't help in my case. But thanks for the tip. We're going to start embedding the application_template.jnlp just to have all our bases covered anyway as it may become required in a future update (like the Permission manifest attribute will in 7u51).Foehn
L
0

We have this Problem with an application based on Netbeans RCP. Netbeans loads every Manifest-File to read its own entrys. That leads to a Security-Exception for every JAR included in the application. It seems to us that Java considers the Manifest-File itself to be an untrusted resource. Don't know if this is intended or bug.

Lexicography answered 18/12, 2013 at 12:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.