A Bug involving MethodHandles, Nestmates, Reflection and @CallerSensitive

Johannes Kuhn info at j-kuhn.de
Tue Dec 8 13:07:45 UTC 2020


On 08-Dec-20 5:40, Mandy Chung wrote:
> Thanks David.  I was about to create one.
>
> This is indeed a gap in injecting this trampoline class for supporting 
> @CallerSensitive methods.  The InjectedInvoker ensures that the 
> InjectedInvoker class has the same class loader as the lookup class.  
> W.r.t. your patch, it seems okay but I have to consider and think 
> through the security implication carefully.
>
> You mentioned "Some old software loves to set static final fields 
> through reflection" - can you share some example libraries about 
> this?   This is really ugly hack!!
>
> Mandy 

Not sure if I read this correctly as "please share some example of code 
that tries to do that" or "please share code that you write to fix that".
So I do both.

Setting static final fields does not work [1]. It probably never really 
did. It usually seems to work - but there is no guarantee that it 
actually does (like undefined behavior).

JPEXS [2] for example used that for it's configuration.
Also some old Minecraft Forge version (a Minecraft mod loader / mod API) 
depends on this. Example use [3], but they do really ugly things.

So, I said I develop agents to get old stuff running on a current Java 
version.
Why? Fun, I guess. I also learn a lot a about what are the main 
comparability problems with newer Java versions.
Pros of writing an agent:
* I don't need the source code.
* I don't need to setup a build environment with all dependencies, 
lombok and who knows what else is required.
In all, it's faster for me. And I then have a list of problems - and how 
they can be solved. I did publish my JPESX agent here [4].
But yeah, it's an ugly hack.

For the nestmate security consideration, the following invariants should 
already hold:
* To call a @CallerSensitive method, the Lookup needs to have full 
privilege access (Lookup.hasFullPrivilegeAccess())
-> Injected Invokers are only created for full privilege lookups.
* The injected invoker is in the same runtime package and has the same 
protection domain.
* It is already possible to obtain a Lookup for the injected invoker by 
calling MethodHandles.lookup() through a MethodHandle (yikes) [5].

This means, we only have to consider what additional privileges the 
injected invoker gets if it is also a nestmate of the lookup class.
I don't see any problem with that, as you already have a full privilege 
lookup when the injected invoker is created.

- Johannes

PS.: JDK-8013527 is mildly related - as the @CallerSensitive methods in 
java.lang.reflect are "hyper-sensitive".

[1]: https://gist.github.com/DasBrain/25c6738610c517ee375aacc86ffebd0c
[2]: 
https://github.com/akx/jpexs-decompiler/blob/6c998254b9d5bdce80be1b92d34836820ee31a1d/libsrc/ffdec_lib/src/com/jpexs/decompiler/flash/configuration/Configuration.java#L869
[3]: 
https://github.com/Chisel-Team/Chisel/blob/1.12/dev/src/main/java/team/chisel/common/init/ChiselBlocks.java#L18
[4]: 
https://github.com/DasBrain/jpex/tree/master/src/pw/dasbrain/jpexs/agent
[5]: https://gist.github.com/DasBrain/142cb8ef9cc16e7469ac519790119e07



More information about the core-libs-dev mailing list