changeset 11632:cc8d0d6c6f95 jdk8u92-b13

Merge
author asaha
date Tue, 22 Mar 2016 11:33:41 -0700
parents 67016cdc6a46 f8725698a870
children e481b892013e
files .hgtags
diffstat 5 files changed, 88 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Thu Mar 17 08:18:35 2016 -0700
+++ b/.hgtags	Tue Mar 22 11:33:41 2016 -0700
@@ -553,6 +553,12 @@
 e6f4eb91a1fa895c2f4520e4cca0ae6f2ca14fbb jdk8u75-b09
 93ea7fd6a5a26940d5a2b020c4e9012a85685a5a jdk8u75-b10
 748ca164767d268e1739748f4df02b623397446c jdk8u75-b12
+02e1209648050922a5a9f2789d9d359795f6f834 jdk8u77-b00
+f08584a0fde9344b0aa4766984266ca68b9a5018 jdk8u77-b01
+1a3e81c05703bb36def80a57681e1692c866f621 jdk8u77-b02
+c44179bce874a97e93ffd7b76a226af417e017a4 jdk8u77-b03
+71f59a00df6c8f3bd5c6d6631a4988a431adab56 jdk8u91-b00
+7ade7a1ab10ff893f62cce9440b4a839aa19c250 jdk8u91-b13
 39baa472e20c13c0eb1243eb5dce589e82f78143 jdk8u76-b00
 6ea3aea950d19d803475b3f4d704a2942e71b302 jdk8u76-b01
 4de4cffb5988cd68959ce4bbd14c6d4547078c91 jdk8u76-b02
--- a/src/share/classes/java/lang/ClassLoader.java	Thu Mar 17 08:18:35 2016 -0700
+++ b/src/share/classes/java/lang/ClassLoader.java	Tue Mar 22 11:33:41 2016 -0700
@@ -653,6 +653,9 @@
         if (!checkName(name))
             throw new NoClassDefFoundError("IllegalName: " + name);
 
+        // Note:  Checking logic in java.lang.invoke.MemberName.checkForTypeAlias
+        // relies on the fact that spoofing is impossible if a class has a name
+        // of the form "java.*"
         if ((name != null) && name.startsWith("java.")) {
             throw new SecurityException
                 ("Prohibited package name: " +
--- a/src/share/classes/java/lang/invoke/MemberName.java	Thu Mar 17 08:18:35 2016 -0700
+++ b/src/share/classes/java/lang/invoke/MemberName.java	Tue Mar 22 11:33:41 2016 -0700
@@ -783,7 +783,7 @@
         assert(isResolved() == isResolved);
     }
 
-    void checkForTypeAlias() {
+    void checkForTypeAlias(Class<?> refc) {
         if (isInvocable()) {
             MethodType type;
             if (this.type instanceof MethodType)
@@ -791,16 +791,16 @@
             else
                 this.type = type = getMethodType();
             if (type.erase() == type)  return;
-            if (VerifyAccess.isTypeVisible(type, clazz))  return;
-            throw new LinkageError("bad method type alias: "+type+" not visible from "+clazz);
+            if (VerifyAccess.isTypeVisible(type, refc))  return;
+            throw new LinkageError("bad method type alias: "+type+" not visible from "+refc);
         } else {
             Class<?> type;
             if (this.type instanceof Class<?>)
                 type = (Class<?>) this.type;
             else
                 this.type = type = getFieldType();
-            if (VerifyAccess.isTypeVisible(type, clazz))  return;
-            throw new LinkageError("bad field type alias: "+type+" not visible from "+clazz);
+            if (VerifyAccess.isTypeVisible(type, refc))  return;
+            throw new LinkageError("bad field type alias: "+type+" not visible from "+refc);
         }
     }
 
@@ -959,10 +959,25 @@
             MemberName m = ref.clone();  // JVM will side-effect the ref
             assert(refKind == m.getReferenceKind());
             try {
+                // There are 4 entities in play here:
+                //   * LC: lookupClass
+                //   * REFC: symbolic reference class (MN.clazz before resolution);
+                //   * DEFC: resolved method holder (MN.clazz after resolution);
+                //   * PTYPES: parameter types (MN.type)
+                //
+                // What we care about when resolving a MemberName is consistency between DEFC and PTYPES.
+                // We do type alias (TA) checks on DEFC to ensure that. DEFC is not known until the JVM
+                // finishes the resolution, so do TA checks right after MHN.resolve() is over.
+                //
+                // All parameters passed by a caller are checked against MH type (PTYPES) on every invocation,
+                // so it is safe to call a MH from any context.
+                //
+                // REFC view on PTYPES doesn't matter, since it is used only as a starting point for resolution and doesn't
+                // participate in method selection.
                 m = MethodHandleNatives.resolve(m, lookupClass);
-                m.checkForTypeAlias();
+                m.checkForTypeAlias(m.getDeclaringClass());
                 m.resolution = null;
-            } catch (LinkageError ex) {
+            } catch (ClassNotFoundException | LinkageError ex) {
                 // JVM reports that the "bytecode behavior" would get an error
                 assert(!m.isResolved());
                 m.resolution = ex;
--- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu Mar 17 08:18:35 2016 -0700
+++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Tue Mar 22 11:33:41 2016 -0700
@@ -45,7 +45,7 @@
 
     static native void init(MemberName self, Object ref);
     static native void expand(MemberName self);
-    static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError;
+    static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError, ClassNotFoundException;
     static native int getMembers(Class<?> defc, String matchName, String matchSig,
             int matchFlags, Class<?> caller, int skip, MemberName[] results);
 
--- a/src/share/classes/sun/invoke/util/VerifyAccess.java	Thu Mar 17 08:18:35 2016 -0700
+++ b/src/share/classes/sun/invoke/util/VerifyAccess.java	Tue Mar 22 11:33:41 2016 -0700
@@ -185,22 +185,66 @@
      * @param refc the class attempting to make the reference
      */
     public static boolean isTypeVisible(Class<?> type, Class<?> refc) {
-        if (type == refc)  return true;  // easy check
+        if (type == refc) {
+            return true;  // easy check
+        }
         while (type.isArray())  type = type.getComponentType();
-        if (type.isPrimitive() || type == Object.class)  return true;
-        ClassLoader parent = type.getClassLoader();
-        if (parent == null)  return true;
-        ClassLoader child  = refc.getClassLoader();
-        if (child == null)  return false;
-        if (parent == child || loadersAreRelated(parent, child, true))
+        if (type.isPrimitive() || type == Object.class) {
             return true;
-        // Do it the hard way:  Look up the type name from the refc loader.
-        try {
-            Class<?> res = child.loadClass(type.getName());
-            return (type == res);
-        } catch (ClassNotFoundException ex) {
+        }
+        ClassLoader typeLoader = type.getClassLoader();
+        ClassLoader refcLoader = refc.getClassLoader();
+        if (typeLoader == refcLoader) {
+            return true;
+        }
+        if (refcLoader == null && typeLoader != null) {
             return false;
         }
+        if (typeLoader == null && type.getName().startsWith("java.")) {
+            // Note:  The API for actually loading classes, ClassLoader.defineClass,
+            // guarantees that classes with names beginning "java." cannot be aliased,
+            // because class loaders cannot load them directly.
+            return true;
+        }
+
+        // Do it the hard way:  Look up the type name from the refc loader.
+        //
+        // Force the refc loader to report and commit to a particular binding for this type name (type.getName()).
+        //
+        // In principle, this query might force the loader to load some unrelated class,
+        // which would cause this query to fail (and the original caller to give up).
+        // This would be wasted effort, but it is expected to be very rare, occurring
+        // only when an attacker is attempting to create a type alias.
+        // In the normal case, one class loader will simply delegate to the other,
+        // and the same type will be visible through both, with no extra loading.
+        //
+        // It is important to go through Class.forName instead of ClassLoader.loadClass
+        // because Class.forName goes through the JVM system dictionary, which records
+        // the class lookup once for all. This means that even if a not-well-behaved class loader
+        // would "change its mind" about the meaning of the name, the Class.forName request
+        // will use the result cached in the JVM system dictionary. Note that the JVM system dictionary
+        // will record the first successful result. Unsuccessful results are not stored.
+        //
+        // We use doPrivileged in order to allow an unprivileged caller to ask an arbitrary
+        // class loader about the binding of the proposed name (type.getName()).
+        // The looked up type ("res") is compared for equality against the proposed
+        // type ("type") and then is discarded.  Thus, the worst that can happen to
+        // the "child" class loader is that it is bothered to load and report a class
+        // that differs from "type"; this happens once due to JVM system dictionary
+        // memoization.  And the caller never gets to look at the alternate type binding
+        // ("res"), whether it exists or not.
+        final String name = type.getName();
+        Class<?> res = java.security.AccessController.doPrivileged(
+                new java.security.PrivilegedAction<Class>() {
+                    public Class<?> run() {
+                        try {
+                            return Class.forName(name, false, refcLoader);
+                        } catch (ClassNotFoundException | LinkageError e) {
+                            return null; // Assume the class is not found
+                        }
+                    }
+            });
+        return (type == res);
     }
 
     /**