The host class filter (via org.graalvm.polyglot.Context.Builder#hostClassFilter) is a nice way to restrict the host classes that are accessible by a guest. But it can be easily bypassed using Java reflection.
For example, disallowing java.lang.Runtime via the host-class-filter lets the following JS snippet bark:
Java.type('java.lang.Runtime').getRuntime().exec("/bin/ps);
But the following snippet still works:
var RuntimeClass = Java.type("java.lang.Class").forName("java.lang.Runtime");
var RuntimeGetRuntime = RuntimeClass.getDeclaredMethod("getRuntime");
var RuntimeRaw = RuntimeGetRuntime.invoke(null);
var RuntimeExec = RuntimeClass.getDeclaredMethod("exec");
RuntimeExec.invoke(RuntimeRaw, '/bin/ps');
Nashorn "disables" Java reflection, if a jdk.nashorn.api.scripting.ClassFilter is configured, but Graal does not "disable" Java reflection (for the guest), if a host-class-filter is configured.
It _seems_ to help to disallow java.lang.Class via the host-class-filter. At least, Java.type('SomeAccessibleClass').class and someType.getClass() seem to yield java.lang.Object (at least calling .forName(...) on the returned objects fails with a TypeError: INVOKE on JavaClass[java.lang.Object] failed due to: Unknown identifier: forName. I'm not sure, whether that's because forName() is a static method or because java.lang.Class is forbidden.
It's a surprising behavior, that a class, which is forbidden via the host-class-filter, is still accessible via Java reflection, especially since the javadoc for org.graalvm.polyglot.Context.Builder#hostClassFilter says If the filter returns true, then the class is accessible, otherwise it is not accessible and throws a guest language error when accessed.
Using a SecurityManager and disallowing RuntimePermission("accessDeclaredMembers") might work, but it also lets Truffle fail (e.g. com.oracle.truffle.api.nodes.NodeClassImpl.collectInstanceFields() requires that permission). It's pretty big hammer - and requires additional configuration (at least code + probably config file).
Hi @snazy,
Thanks for the report. We will investigate that and report back here.
-- Christian
@snazy We are aware of this problem and working on a fix already. We will likely introduce a new flag allowHostReflection that needs to be enabled explicitly if reflection access is desired.
In addition to that, we are considering another flag allowHostPublicAccess to control whether all public members should be exposed by default. If this permission is not granted then the exported methods need to be annotated explicitly with a new annotation to expose them to the guest language. If this permission is granted then the annotations would be ignored and all public members would be exposed. This will reduce the likelihood of exposing newly declared methods by accident. Would something like this be useful for you as well?
@chumer awesome! I think, both flags will be very useful!
Since RC15 we changed the default for polyglot contexts to no longer allow reflection. In addition to that all method sthat should be accessible from a context must be marked with HostAccess.Export. All of this can be customized by creating a custom host access configuration (HostAccess.newBuilder()...).
We decided to change the default to HostAccess.EXPLICIT, because it is very easy through for example third party libraries to expose new methods without getting notified. Those methods might expose means to load new classes. We have no means to intercept that on our side. So the best practice is to explicitly mark everything that should be exposed to the guest application.
We also renamed the host class filter to allowHostLookup which now does not allow the lookup of any classes by default (it is set to null).
If you don't care about guest and host isolation and you just want to allow the guest application full access you can use HostAccess.ALL to get to restore the previous behavior (that includes the ability to use reflection).
More info on HostAccess: https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/HostAccess.html
Configure the host class lookup: https://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/Context.Builder.html#allowHostClassLookup-java.util.function.Predicate-
@chumer thanks for fixing this! I tried the recent 1.0.0-rc15 build and it works for me.
Most helpful comment
@chumer awesome! I think, both flags will be very useful!