Hakanai
Hakanai

Reputation: 12670

How do I give a CodeSource to scripts which I evaluate through nashorn?

I have a problem where some fairly trivial code running under nashorn is looking up a system property. Looking up the system property fails with an AccessControlException.

My security policy already permits:

grant {
    permission java.util.PropertyPermission "*", "read, write";
};

On debugging with -Djava.security.debug=access,failure, I found that the CodeSource was null for the offending ProtectionDomain.

I moved breakpoints into the constructor for that and after a few more layers of indirection, I eventually managed to track my issue down to jdk.nashorn.internal.runtime.Source.

private Source(String name, String base, char[] content, URL url) {
    this.name = name;
    this.base = base;
    this.content = content;
    this.length = content.length;
    this.url = url;
}

There is a public constructor which NashornScriptEngine is calling which ultimately sets the url to null, which is the constructor I see my code passing through.

public Source(String name, char[] content) {
    this(name, baseName(name, (String)null), content, (URL)null);
}

public Source(String name, String content) {
    this(name, content.toCharArray());
}

Although we do pass the script in as a string, it's extracted from the code blocks of an HTML file, so theoretically I could provide it a CodeSource. Then hopefully the access control code would at least give it the minimum level of trust and looking up system properties should hopefully work.

I see other constructors which do pass a URL along. e.g.:

public Source(String name, URL url, Charset cs) throws IOException {
    this(name, baseURL(url, (String)null), readFully(url, cs), url);
}

For the life of me, I can't figure out how I would interact with ScriptEngine to encourage the nashorn engine to call one of these better constructors. ScriptEngine#eval only has methods which take String or Reader. Is there a way to do this? Is there another way to ensure the CodeSource is properly set when nashorn creates code?

I know what it isn't - setting the FILENAME in the script context. That seems to be completely ignored.

Oddly, we also run all the same sorts tests under JRuby, but we don't see the same problems over there. So whatever is going on here, this must be particular to nashorn. (FWIW, we never saw this happen under Rhino, either.)

Upvotes: 0

Views: 237

Answers (3)

A. Sundararajan
A. Sundararajan

Reputation: 4405

File: Main.java

import javax.script.*;

public class Main {
    public static void main(String[] ar) throws Exception {
        ScriptEngineManager m = new ScriptEngineManager();
        ScriptEngine e = m.getEngineByName("nashorn");
        System.out.println(e.eval("java.lang.System.getProperty('foo.bar')"));
    }
}

File: foo.policy

grant {
    permission java.util.PropertyPermission "*", "read, write";
};

Command:

javac Main.java

java -Djava.security.manager -Dfoo.bar=sss -Djava.security.policy=foo.policy Main

"sss" is printed as expected (with jdk 1.8.0 update 40)

Upvotes: 1

A. Sundararajan
A. Sundararajan

Reputation: 4405

You can use jdk.nashorn.api.scripting.URLReader ( https://docs.oracle.com/javase/8/docs/jdk/api/nashorn/jdk/nashorn/api/scripting/URLReader.html ) which wraps a URL as a Reader. With a URLReader, nashorn will load script from that URL and associate proper CodeSource - so that your security policy for that URL will be effective.

Upvotes: 1

Attila Szegedi
Attila Szegedi

Reputation: 4565

Providing a CodeSource is a security capability. Attackers could use that to falsely claim that the JS code comes from a privileged location and thus put it into any protection domain. Nashorn will only associate a CodeSource with code it loads itself through a URL (and thus can be certain where it came from). Even in Java, associating code with its source is something that only class loaders are allowed to do, hence it is guarded by the createClassLoader runtime permission. Its documentation even says:

"This is an extremely dangerous permission to grant. Malicious applications that can instantiate their own class loaders could then load their own rogue classes into the system. These newly loaded classes could be placed into any protection domain by the class loader, thereby automatically granting the classes the permissions for that domain."

Replace "class" with "script" and you have the same concern here. I could sort-of see Nashorn having a constructor that takes both a CodeSource and a char[], but it'd have to do either a permission check for createClassLoader or a new bespoke runtime permission.

Upvotes: 2

Related Questions