-
Notifications
You must be signed in to change notification settings - Fork 175
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Access to default methods in @JImplements
#1182
base: master
Are you sure you want to change the base?
Conversation
Will be hard to get this to work as the jar file must be loaded into the base classloader. It may be doable, but will require serious effort. |
sorry I cannot estimate if it'd be worth the effort? How common are these "default methods"? |
Default methods are a newer feature of Java in which the programmers adds some functionality to an interface which will automatically be available to the implemented classes. They are common in newer code, but most of the Java library classes currently don't use them. They are difficult to access because they didn't exist when JNI was written so there is no "call the default" method and the proxy system works against them. The issue here is that the newer java security methods prevent calling code from arbitrary modules, and our jar is not located in a position of any privilege as we are not in the boot loader. About the only way I can make this happen would be to make my own Jar loader which uses the JNI special under the table class definition method which in theory would get the JPype into a lower level. However, JNI doesn't really have any support for modules or module definition so I have no idea if I can actually get to the level required to make this type of access. Making a jar side loader would require access to gzip and tar access. There may be severe technical issues if I need to load the class files in a particular order. One can expect that many libraries will have default method if they use interfaces at some point. Thus there is some value, but it is a large lift (and given I am underwater until July it won't happen soon.) |
Bypassing JVMs security mechanisms does not seem right. If these extended Interfaces do not posses a mechanism in JNI, we should request them upstream. It does not make any sense for them to be inacessible, right? Why are default methods not already handled by the MRO, e.g. calling the parents implementation? Actually it should, should it not? |
The problem is more complex than that. The issue you sighted is regarding calling dynamics from JNI without the presence of a proxy.
See this posting which is more relevant…
https://stackoverflow.com/questions/37812393/how-to-explicitly-invoke-default-method-from-a-dynamic-proxy
We do see default methods in the MRO and we can try to invoke them. The issue occurs because our methods are a proxy. All methods called on a proxy, the proxy then redirects to Python or back to Java. But because of the way that defaults are implemented that just goes back to the proxy again. For normal interface method this isn’t a problem as there is nothing to call back to so we just throw UnsupportedOperation exception and the guard code prevents the user from doing this when a JProxy was declared. We can’t redirect it back to Java through the JNI because defaults don’t have an invoke method other than the one that routes to the proxy. Java can redirect to the method, but because of the new security model you must be in the same module (or be a privileged class) to access the MethodHandle. Thus the catch 22. There is no security violation to call a default method (it is public) but there is no way to access the method outside of using a secure path.
This means the only way to implement this feature is to place org.jpype in a privileged state such that it can call a public method (and be trusted to check that). This is a typical problem with the patching in of new features without considering the native interface. We faced the same issue when they started checking the module called from, without considering that JNI calls have no module. The correct solution would be to have JNI register itself to have a module presence that use that module to determine the access.
Solutions….
1. Use the JNI loadClass interface to load our jar into the bootstrap loader such that we live at the same level as core libraries. Of course this has the downside that calls through our jar may be able to access private methods introducing security flaws (through the total number of paths is small.).
2. Use the JNI loadClass interface to load only the Proxy code required to make the request. If the call checks for public access and is bullet proof, then it is better than placing our whole jar file at a privileged level.
3. Try to convert our entire infrastructure to a module and then set the module privilege flags when calling the start JVM to elevate our module. Same issue as 1.
4. Abandon old versions of the JDK…. (Please pick me! Pick me!) These problems all stem from poorly thought through patches. They eventually got reported and thus added support methods that solve the issue. The problem is those support methods don’t exist and thus I have to go through very large hoops to make us work in only versions. In any sane world JDK 1.8 would long since have hit the dust bin and only the latest LTS would need to be dealt with. As each is retired we could remove the kludges.
All of these are a lift because it means we can’t insert jar files through the typical DynamicClassLoader (which places us at a lower that typical security level) but instead must use an entirely different loading scheme.
I should note that this patch works perfectly if we simply place the org.jpype.jar on the classpath of jpype.startJVM(). The difference is that when we enter at the classpath we get loaded by the System loader rather than by the Dynamic loader. To have truly elevated privileges we have to load our classes in the bootloader.
|
Default methods are a pain because the proxy to interfaces always redirects and there is no "normal" method of accessing such a method via reflection. The PR uses MethodHandles to perform the redirect. It is no clear if this works in Java 8 though as some of the comments regarding this method indicate that it may be a Java 9 feature. I added test cases to see if this is true. If it is only a Java 9 feature we can try to implement a mixed mode jar file, but that will get more complicated.
Fixes #1181