On 05/19/2017 12:58 PM, Peter Levart wrote:

It's easy. Take this example:

public class Test {
    public static void main(String[] args) throws Exception {
        Object theUnsafe = Class.forName("jdk.internal.misc.Unsafe")
                                .getMethod("getUnsafe")
                                .invoke(null);
    }
}

Running this on classpath without any additional JVM options produces:

Exception in thread "main" java.lang.IllegalAccessException: class Test cannot access class jdk.internal.misc.Unsafe (in module java.base) because module java.base does not export jdk.internal.misc to unnamed module @63d4e2ba at java.base/jdk.internal.reflect.Reflection.throwIllegalAccessException(Reflection.java:445) at java.base/jdk.internal.reflect.Reflection.throwIllegalAccessException(Reflection.java:436) at java.base/jdk.internal.reflect.Reflection.ensureMemberAccess(Reflection.java:112) at java.base/java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:407) at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:399)
    at java.base/java.lang.reflect.Method.invoke(Method.java:535)
    at Test.main(Test.java:9)

(note that the exception is thrown from Method.invoke)

When run with:

     --add-exports java.base/jdk.internal.misc=ALL-UNNAMED

...the example works (does not throw exception), but when run with:

    --add-opens java.base/jdk.internal.misc=ALL-UNNAMED

...the example still works!!!! OOOPS - this is a bug!!! This is definitely a bug.


If --illegal-access=permit is an alias for opening all modules to ALL-UNNAMED, then we definitely have a problem as above example can be successfully executed even with SecurityManager enabled!!!


...Ok, there's still a SecurityManager.checkPackageAccess() performed when some app class "loads" the jdk.internal.misc.Unsafe class and the caller needs to have a "accessClassInPackage.jdk.internal.misc" runtime permission. So this throws exception with SecurityManager enabled (from Class.forName("...") this time), but this permission should not be sufficient. I think "opens" should not imply "exports" - not even for reflection.

Conceptually "exports" should fall in the same category of access controls as "private", "package-private", "protected" and "public" modifiers on members/classes. If a member is not accessible to a caller due to access modifiers on the member or enclosing class or module lacking "exports", then such member should not be allowed to be accessed:
- during compilation
- during runtime by bytecode instruction
- during runtime by reflection
- during runtime by MethodHandles.Lookup methods

Opening a package to the caller module should only allow the caller to suppress these access checks, but the caller should still be required to request this explicitly either by using AccessibleObject.setAccessible(true) when reflecting; or by using MethodHandles.Lookup.privateLookupIn() when looking up members to get MethodHandles or VarHandles. Those two methods require special "suppressAccessChecks" runtime permission.

Regards, Peter

Reply via email to