8166304: Skipping access check for classes generated by core reflection
authorhseigel
Thu, 17 Nov 2016 14:23:29 -0500
changeset 42574 25ff9171b28b
parent 42573 a20695c30be5
child 42576 9ec0a0239c8a
8166304: Skipping access check for classes generated by core reflection Summary: Only allow boot and reflection class loader to load sub-types of jdk.internal.reflect Reviewed-by: acorn, lfoltan, rehn
hotspot/src/share/vm/classfile/classFileParser.cpp
hotspot/src/share/vm/classfile/javaClasses.cpp
hotspot/src/share/vm/classfile/javaClasses.hpp
hotspot/src/share/vm/classfile/vmSymbols.hpp
hotspot/test/runtime/classFileParserBug/FakeMethodAcc.java
hotspot/test/runtime/classFileParserBug/fakeMethodAccessor.jasm
--- a/hotspot/src/share/vm/classfile/classFileParser.cpp	Thu Nov 17 15:54:48 2016 +0300
+++ b/hotspot/src/share/vm/classfile/classFileParser.cpp	Thu Nov 17 14:23:29 2016 -0500
@@ -4349,13 +4349,34 @@
   assert(this_klass != NULL, "invariant");
   const Klass* const super = this_klass->super();
   if (super != NULL) {
+
+    // If the loader is not the boot loader then throw an exception if its
+    // superclass is in package jdk.internal.reflect and its loader is not a
+    // special reflection class loader
+    if (!this_klass->class_loader_data()->is_the_null_class_loader_data()) {
+      assert(super->is_instance_klass(), "super is not instance klass");
+      PackageEntry* super_package = super->package();
+      if (super_package != NULL &&
+          super_package->name()->fast_compare(vmSymbols::jdk_internal_reflect()) == 0 &&
+          !java_lang_ClassLoader::is_reflection_class_loader(this_klass->class_loader())) {
+        ResourceMark rm(THREAD);
+        Exceptions::fthrow(
+          THREAD_AND_LOCATION,
+          vmSymbols::java_lang_IllegalAccessError(),
+          "class %s loaded by %s cannot access jdk/internal/reflect superclass %s",
+          this_klass->external_name(),
+          this_klass->class_loader_data()->loader_name(),
+          super->external_name());
+        return;
+      }
+    }
+
     Reflection::VerifyClassAccessResults vca_result =
       Reflection::verify_class_access(this_klass, super, false);
     if (vca_result != Reflection::ACCESS_OK) {
       ResourceMark rm(THREAD);
       char* msg =  Reflection::verify_class_access_msg(this_klass, super, vca_result);
       if (msg == NULL) {
-        ResourceMark rm(THREAD);
         Exceptions::fthrow(
           THREAD_AND_LOCATION,
           vmSymbols::java_lang_IllegalAccessError(),
--- a/hotspot/src/share/vm/classfile/javaClasses.cpp	Thu Nov 17 15:54:48 2016 +0300
+++ b/hotspot/src/share/vm/classfile/javaClasses.cpp	Thu Nov 17 14:23:29 2016 -0500
@@ -3525,17 +3525,24 @@
   return false;
 }
 
-oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) {
+// Return true if this is one of the class loaders associated with
+// the generated bytecodes for reflection.
+bool java_lang_ClassLoader::is_reflection_class_loader(oop loader) {
   if (loader != NULL) {
-    // See whether this is one of the class loaders associated with
-    // the generated bytecodes for reflection, and if so, "magically"
-    // delegate to its parent to prevent class loading from occurring
-    // in places where applications using reflection didn't expect it.
     Klass* delegating_cl_class = SystemDictionary::reflect_DelegatingClassLoader_klass();
     // This might be null in non-1.4 JDKs
-    if (delegating_cl_class != NULL && loader->is_a(delegating_cl_class)) {
-      return parent(loader);
-    }
+    return (delegating_cl_class != NULL && loader->is_a(delegating_cl_class));
+  }
+  return false;
+}
+
+oop java_lang_ClassLoader::non_reflection_class_loader(oop loader) {
+  // See whether this is one of the class loaders associated with
+  // the generated bytecodes for reflection, and if so, "magically"
+  // delegate to its parent to prevent class loading from occurring
+  // in places where applications using reflection didn't expect it.
+  if (is_reflection_class_loader(loader)) {
+    return parent(loader);
   }
   return loader;
 }
--- a/hotspot/src/share/vm/classfile/javaClasses.hpp	Thu Nov 17 15:54:48 2016 +0300
+++ b/hotspot/src/share/vm/classfile/javaClasses.hpp	Thu Nov 17 14:23:29 2016 -0500
@@ -1243,6 +1243,10 @@
 
   static bool is_trusted_loader(oop loader);
 
+  // Return true if this is one of the class loaders associated with
+  // the generated bytecodes for reflection.
+  static bool is_reflection_class_loader(oop loader);
+
   // Fix for 4474172
   static oop  non_reflection_class_loader(oop loader);
 
--- a/hotspot/src/share/vm/classfile/vmSymbols.hpp	Thu Nov 17 15:54:48 2016 +0300
+++ b/hotspot/src/share/vm/classfile/vmSymbols.hpp	Thu Nov 17 14:23:29 2016 -0500
@@ -228,6 +228,7 @@
                                                                                                   \
   /* Support for reflection based on dynamic bytecode generation (JDK 1.4 and above) */           \
                                                                                                   \
+  template(jdk_internal_reflect,                      "jdk/internal/reflect")                     \
   template(reflect_MagicAccessorImpl,                 "jdk/internal/reflect/MagicAccessorImpl")       \
   template(reflect_MethodAccessorImpl,                "jdk/internal/reflect/MethodAccessorImpl")      \
   template(reflect_ConstructorAccessorImpl,           "jdk/internal/reflect/ConstructorAccessorImpl") \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/FakeMethodAcc.java	Thu Nov 17 14:23:29 2016 -0500
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8166304
+ * @summary Skipping access check for classes generated by core reflection
+ * @compile fakeMethodAccessor.jasm
+ * @run main FakeMethodAcc
+ */
+
+/*
+ * Test that trying to create a sub-type of a 'magic' jdk.internal.reflect
+ * class should fail with an IllegalAccessError exception.
+*/
+public class FakeMethodAcc {
+    public static void main(String args[]) throws Throwable {
+
+        System.out.println("Regression test for bug 8166304");
+        try {
+            Class newClass = Class.forName("fakeMethodAccessor");
+            throw new RuntimeException(
+                "Missing expected IllegalAccessError exception");
+        } catch (java.lang.IllegalAccessError e) {
+        }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/runtime/classFileParserBug/fakeMethodAccessor.jasm	Thu Nov 17 14:23:29 2016 -0500
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ // This is the Java representation of the below jasm code.  The test tries
+ // to create a sub-type of jdk.internal.reflect.MethodAccessorImpl in order
+ // to bypass Reflection.getCallerClass.  That should fail with an IAE.
+ //
+ import java.lang.reflect.Module;
+ class fakeMethodAccessor extends jdk.internal.reflect.MethodAccessorImpl {
+     public static void main(String[] a) throws Exception {
+        fakeMethodAccessor f = new fakeMethodAccessor();
+        System.out.println(String.class.getModule()
+           .isExported("jdk.internal.misc", fakeMethodAccessor.class.getModule()));
+     }
+ }
+*/
+
+super class fakeMethodAccessor
+    extends jdk/internal/reflect/MethodAccessorImpl
+    version 53:0
+{
+
+
+Method "<init>":"()V"
+    stack 1 locals 1
+{
+        aload_0;
+        invokespecial    Method jdk/internal/reflect/MethodAccessorImpl."<init>":"()V";
+        return;
+}
+
+public static Method main:"([Ljava/lang/String;)V"
+    throws java/lang/Exception
+    stack 4 locals 2
+{
+        new    class FakeMethodAccessor;
+        dup;
+        invokespecial    Method "<init>":"()V";
+        astore_1;
+        getstatic    Field java/lang/System.out:"Ljava/io/PrintStream;";
+        ldc    class java/lang/String;
+        invokevirtual    Method java/lang/Class.getModule:"()Ljava/lang/reflect/Module;";
+        ldc    String "jdk.internal.misc";
+        ldc    class FakeMethodAccessor;
+        invokevirtual    Method java/lang/Class.getModule:"()Ljava/lang/reflect/Module;";
+        invokevirtual    Method java/lang/reflect/Module.isExported:"(Ljava/lang/String;Ljava/lang/reflect/Module;)Z";
+        invokevirtual    Method java/io/PrintStream.println:"(Z)V";
+        return;
+}
+
+} // end Class FakeMethodAccessor