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