Fix proposal for bug JDK-8221642
Mandy Chung
mandy.chung at oracle.com
Fri Jan 28 19:07:58 UTC 2022
Your proposal is essentially for all JNI code with no caller frame to
default to java.base, which gets all permissions. It means that it
could break encapsulation to access any members. Arguably one could
consider JNI have superpower. In addition, default to java.base may not
make sense for some Java APIs, ResouroceBundle::getBundle(String
bundlename) is one example. It uses the caller class's loader to load
the resource bundle. Default to java.base means it defaults to the
bootstrap loader which can't find the resource bundle on the class path
for example. For the ResourceBundle case, it seems that the unnamed
module defined by the system class loader might be an appropriate default.
The proper way is to examine each caller-sensitive method and
investigate what makes sense when invoked by JNI code with no caller
frame. JDK-8177155 is the RFE for such task. System::getLogger,
Logger::getLogger, and core reflection API are looked at but more to
follow up.
I created https://bugs.openjdk.java.net/browse/JDK-8280902 to follow up
the ResourceBundle::getBundle issue.
Mandy
[1] https://bugs.openjdk.java.net/browse/JDK-8177155
On 1/28/22 3:15 AM, Andreas Rosenberg wrote:
>
> Hi Mandy,
>
> thanks for looking at my problem. Yes, "setAccessible" is one of the
> problems,
>
> but our main issue is related to "ResourceBundle".
>
> I've created a small example that shows the
> problem:https://github.com/anrose00/JniSensitiveCaller
> <https://urldefense.com/v3/__https://github.com/anrose00/JniSensitiveCaller__;!!ACWV5N9M2RV99hQ!YQ77Xchy8f8FZNrtmRPANSCuvfN1KicygQkw2EDl7d-0B1ohBWgs87EWtsw-U84jWQ$>
>
> Any comments on my proposal would be great.
>
> Andreas
>
> *From:*Mandy Chung <mandy.chung at oracle.com>
> *Sent:* Freitag, 28. Januar 2022 02:54
> *To:* Andreas Rosenberg <andreas.rosenberg at apis.de>
> *Cc:* hotspot-dev at openjdk.java.net; 'core-libs-dev'
> <core-libs-dev at openjdk.java.net>
> *Subject:* Re: Fix proposal for bug JDK-8221642
>
> I see how NPE is thrown (from `AccessibleObject::setAccessible` and
> `trySetAccessible`). The proper fix should follow the rule as the
> access check that it can set the accessible flag only on public
> members of a public type that is exported unconditionally.
>
> The fix is straight forward but involves spec change. I'll post PR soon.
>
> Mandy
>
> On 1/27/22 8:45 AM, Mandy Chung wrote:
>
> Hi Andreas,
>
> What methods are you calling that throws NPE? Do you have the
> stack trace to share?
>
> The spec of AccessibleObject was updated for JDK-8221530 if there
> is no caller frame when calling from JNI:
>
> "The check when invoked by JNI code with no Java class on the
> stack only succeeds if the member and the declaring class are
> public, and the class is in a package that is exported to all
> modules."
>
> I think AccessibleObject::canAccess, setAccessible,
> trySetAccessible should follow the same rule.
>
> Mandy
>
> On 1/27/22 2:19 AM, Andreas Rosenberg wrote:
>
> Hi,
>
> this is my first posting regarding to JDK contribution, so this may be the wrong place to ask.
>
> Please point me in the right direction in this case.
>
> We are using Java rather heavily via JNI on a custom application. For a long time we did stick to JRE 1.8
>
> for various reasons. My task is to plan an upgrade to a more recent JDK version and while doing some
>
> test I encountered bugs related to this: JDK-8227491(JNI - caller sensitive methods).
>
> We are parsing Java class files to auto gen the JNI code for our application, and are also using reflection.
>
> The workaround given is clumsy and needs manual intervention, so I was looking for a more elegant solution.
>
> The problem is: a caller sensitive method wants to determine the caller class for security checks. In case of
>
> a JNI call no Java stack frame exists, so the JVM function "jclass JVM_GetCallerClass(JNIEnv* env)" answers NULL
>
> which leads to NPEs.
>
> My idea is this: create an internal proxy class inside "java.base" that reflects this case
>
> (e.g. "java.lang.NativeCall" or "java.lang.NativeCode").
>
> This class is final and implements nothing.
>
> Then "jclass JVM_GetCallerClass(JNIEnv* env)" (jvm.cpp) could be modified and instead of answering NULL
>
> in case of a JNI call, it should do this to answer the class proxy:
>
> return JVM_FindClassFromBootLoader(env, "java/lang/NativeCall");
>
> This would have the following advantages:
>
> - JNI code could again simply call "caller sensitive methods" without the need to make an additional wrapper class
>
> - it would be more a expressive way on the Java side to detect "the callee is native code" than checking for null
>
> - it would fit better into the framework
>
> I already applied this fix on my own copy of the JDK 17 sources and it works pretty well for us.
>
> As there are probably security considerations involved, advice from experts is required.
>
> But from my understanding the Java security model is designed for the main app being writing in Java.
>
> In this case there are always Java stacks frames available as parents for caller sensitive methods, so
>
> the proposed fix would not affect the behavior. This assumes that "GetCallerClass" only answers
>
> NULL for the JNI case. This needs verification.
>
> If the main app is native code which uses JNI, the Java security model can only affect the Java part and
>
> as soon as an additional Java stack frame has been generated a regular Java class will be found and
>
> the "standard behavior" should apply again.
>
> Comments appreciated.
>
> It this fix looks reasonable, what are the steps to get it implemented and integrated into the official
>
> source tree?
>
> Best regards,
>
> Andy
>
More information about the core-libs-dev
mailing list