7193339: Prepare system classes be defined by a non-null module loader
authormchung
Fri, 24 Aug 2012 22:55:49 -0700
changeset 13589 da4cb574f4a6
parent 13588 6cbdac071165
child 13590 f7f85d7f7a82
7193339: Prepare system classes be defined by a non-null module loader Reviewed-by: alanb, dholmes, dsamersoff, sspitsyn, psandoz
jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanMapping.java
jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPHelper.java
jdk/src/share/classes/java/lang/Class.java
jdk/src/share/classes/java/lang/ClassLoader.java
jdk/src/share/classes/java/lang/Thread.java
jdk/src/share/classes/java/lang/management/ManagementFactory.java
jdk/src/share/classes/java/lang/management/PlatformComponent.java
jdk/src/share/classes/java/util/prefs/Preferences.java
jdk/src/share/classes/javax/script/ScriptEngineManager.java
jdk/src/share/classes/sun/management/MappedMXBeanType.java
jdk/src/share/classes/sun/misc/Unsafe.java
jdk/src/share/classes/sun/misc/VM.java
jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanMapping.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanMapping.java	Fri Aug 24 22:55:49 2012 -0700
@@ -169,7 +169,7 @@
             return (Class<?>) javaType;
         try {
             String className = openType.getClassName();
-            return Class.forName(className, false, null);
+            return Class.forName(className, false, MXBeanMapping.class.getClassLoader());
         } catch (ClassNotFoundException e) {
             throw new RuntimeException(e);  // should not happen
         }
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPHelper.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/IIOPHelper.java	Fri Aug 24 22:55:49 2012 -0700
@@ -52,7 +52,8 @@
         AccessController.doPrivileged(new PrivilegedAction<IIOPProxy>() {
             public IIOPProxy run() {
                 try {
-                    Class<?> c = Class.forName(IMPL_CLASS, true, null);
+                    Class<?> c = Class.forName(IMPL_CLASS, true,
+                                               IIOPHelper.class.getClassLoader());
                     return (IIOPProxy)c.newInstance();
                 } catch (ClassNotFoundException cnf) {
                     return null;
--- a/jdk/src/share/classes/java/lang/Class.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/java/lang/Class.java	Fri Aug 24 22:55:49 2012 -0700
@@ -228,7 +228,8 @@
      * ensure it's ok to access the bootstrap class loader.
      *
      * @param name       fully qualified name of the desired class
-     * @param initialize whether the class must be initialized
+     * @param initialize if {@code true} the class will be initialized.
+     *                   See Section 12.4 of <em>The Java Language Specification</em>.
      * @param loader     class loader from which the class must be loaded
      * @return           class object representing the desired class
      *
@@ -605,7 +606,7 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             ClassLoader ccl = ClassLoader.getCallerClassLoader();
-            if (ccl != null && ccl != cl && !cl.isAncestor(ccl)) {
+            if (ClassLoader.needsClassLoaderPermissionCheck(ccl, cl)) {
                 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
             }
         }
@@ -2170,8 +2171,7 @@
         if (s != null) {
             s.checkMemberAccess(this, which);
             ClassLoader cl = getClassLoader0();
-            if ((ccl != null) && (ccl != cl) &&
-                  ((cl == null) || !cl.isAncestor(ccl))) {
+            if (sun.reflect.misc.ReflectUtil.needsPackageAccessCheck(ccl, cl)) {
                 String name = this.getName();
                 int i = name.lastIndexOf('.');
                 if (i != -1) {
--- a/jdk/src/share/classes/java/lang/ClassLoader.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/java/lang/ClassLoader.java	Fri Aug 24 22:55:49 2012 -0700
@@ -1403,7 +1403,7 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             ClassLoader ccl = getCallerClassLoader();
-            if (ccl != null && !isAncestor(ccl)) {
+            if (needsClassLoaderPermissionCheck(ccl, this)) {
                 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
             }
         }
@@ -1473,7 +1473,7 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             ClassLoader ccl = getCallerClassLoader();
-            if (ccl != null && ccl != scl && !scl.isAncestor(ccl)) {
+            if (needsClassLoaderPermissionCheck(ccl, scl)) {
                 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
             }
         }
@@ -1523,6 +1523,23 @@
         return false;
     }
 
+    // Tests if class loader access requires "getClassLoader" permission
+    // check.  A class loader 'from' can access class loader 'to' if
+    // class loader 'from' is same as class loader 'to' or an ancestor
+    // of 'to'.  The class loader in a system domain can access
+    // any class loader.
+    static boolean needsClassLoaderPermissionCheck(ClassLoader from,
+                                                   ClassLoader to)
+    {
+        if (from == to)
+            return false;
+
+        if (from == null)
+            return false;
+
+        return !to.isAncestor(from);
+    }
+
     // Returns the invoker's class loader, or null if none.
     // NOTE: This must always be invoked when there is exactly one intervening
     // frame from the core libraries on the stack between this method's
--- a/jdk/src/share/classes/java/lang/Thread.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/java/lang/Thread.java	Fri Aug 24 22:55:49 2012 -0700
@@ -1449,8 +1449,7 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             ClassLoader ccl = ClassLoader.getCallerClassLoader();
-            if (ccl != null && ccl != contextClassLoader &&
-                    !contextClassLoader.isAncestor(ccl)) {
+            if (ClassLoader.needsClassLoaderPermissionCheck(ccl, contextClassLoader)) {
                 sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
             }
         }
--- a/jdk/src/share/classes/java/lang/management/ManagementFactory.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/java/lang/management/ManagementFactory.java	Fri Aug 24 22:55:49 2012 -0700
@@ -576,16 +576,16 @@
                                Class<T> mxbeanInterface)
             throws java.io.IOException {
 
-        final Class<?> interfaceClass = mxbeanInterface;
         // Only allow MXBean interfaces from rt.jar loaded by the
         // bootstrap class loader
-        final ClassLoader loader =
+        final Class<?> cls = mxbeanInterface;
+        ClassLoader loader =
             AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
                 public ClassLoader run() {
-                    return interfaceClass.getClassLoader();
+                    return cls.getClassLoader();
                 }
             });
-        if (loader != null) {
+        if (!sun.misc.VM.isSystemDomainLoader(loader)) {
             throw new IllegalArgumentException(mxbeanName +
                 " is not a platform MXBean");
         }
@@ -593,10 +593,10 @@
         try {
             final ObjectName objName = new ObjectName(mxbeanName);
             // skip the isInstanceOf check for LoggingMXBean
-            String intfName = interfaceClass.getName();
+            String intfName = mxbeanInterface.getName();
             if (!connection.isInstanceOf(objName, intfName)) {
                 throw new IllegalArgumentException(mxbeanName +
-                    " is not an instance of " + interfaceClass);
+                    " is not an instance of " + mxbeanInterface);
             }
 
             final Class[] interfaces;
--- a/jdk/src/share/classes/java/lang/management/PlatformComponent.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/java/lang/management/PlatformComponent.java	Fri Aug 24 22:55:49 2012 -0700
@@ -363,7 +363,8 @@
         try {
             // Lazy loading the MXBean interface only when it is needed
             return (Class<? extends PlatformManagedObject>)
-                       Class.forName(mxbeanInterfaceName, false, null);
+                       Class.forName(mxbeanInterfaceName, false,
+                                     PlatformManagedObject.class.getClassLoader());
         } catch (ClassNotFoundException x) {
             throw new AssertionError(x);
         }
--- a/jdk/src/share/classes/java/util/prefs/Preferences.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/java/util/prefs/Preferences.java	Fri Aug 24 22:55:49 2012 -0700
@@ -300,7 +300,8 @@
         }
         try {
             return (PreferencesFactory)
-                Class.forName(platformFactory, false, null).newInstance();
+                Class.forName(platformFactory, false,
+                              Preferences.class.getClassLoader()).newInstance();
         } catch (Exception e) {
             throw new InternalError(
                 "Can't instantiate platform default Preferences factory "
--- a/jdk/src/share/classes/javax/script/ScriptEngineManager.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/javax/script/ScriptEngineManager.java	Fri Aug 24 22:55:49 2012 -0700
@@ -423,7 +423,7 @@
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             ClassLoader callerLoader = getCallerClassLoader();
-            if (callerLoader != null) {
+            if (!sun.misc.VM.isSystemDomainLoader(callerLoader)) {
                 if (loader != callerLoader || !isAncestor(loader, callerLoader)) {
                     try {
                         sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
--- a/jdk/src/share/classes/sun/management/MappedMXBeanType.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/sun/management/MappedMXBeanType.java	Fri Aug 24 22:55:49 2012 -0700
@@ -803,7 +803,7 @@
                 Class<?> c;
                 try {
                     c = Class.forName(t.getClassName(), false,
-                                      String.class.getClassLoader());
+                                      MappedMXBeanType.class.getClassLoader());
                     MappedMXBeanType.newBasicType(c, t);
                 } catch (ClassNotFoundException e) {
                     // the classes that these predefined types declare
--- a/jdk/src/share/classes/sun/misc/Unsafe.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/sun/misc/Unsafe.java	Fri Aug 24 22:55:49 2012 -0700
@@ -82,7 +82,7 @@
      */
     public static Unsafe getUnsafe() {
         Class<?> cc = sun.reflect.Reflection.getCallerClass(2);
-        if (cc.getClassLoader() != null)
+        if (!VM.isSystemDomainLoader(cc.getClassLoader()))
             throw new SecurityException("Unsafe");
         return theUnsafe;
     }
--- a/jdk/src/share/classes/sun/misc/VM.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/sun/misc/VM.java	Fri Aug 24 22:55:49 2012 -0700
@@ -218,6 +218,14 @@
     }
 
     /**
+     * Returns true if the given class loader is in the system domain
+     * in which all permissions are granted.
+     */
+    public static boolean isSystemDomainLoader(ClassLoader loader) {
+        return loader == null;
+    }
+
+    /**
      * Returns the system property of the specified key saved at
      * system initialization time.  This method should only be used
      * for the system properties that are not changed during runtime.
--- a/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java	Fri Aug 24 11:48:51 2012 -0700
+++ b/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java	Fri Aug 24 22:55:49 2012 -0700
@@ -144,4 +144,38 @@
         }
         return true;
     }
+
+    // Returns true if p is an ancestor of cl i.e. class loader 'p' can
+    // be found in the cl's delegation chain
+    private static boolean isAncestor(ClassLoader p, ClassLoader cl) {
+        ClassLoader acl = cl;
+        do {
+            acl = acl.getParent();
+            if (p == acl) {
+                return true;
+            }
+        } while (acl != null);
+        return false;
+    }
+
+    /**
+     * Returns true if package access check is needed for reflective
+     * access from a class loader 'from' to classes or members in
+     * a class defined by class loader 'to'.  This method returns true
+     * if 'from' is not the same as or an ancestor of 'to'.  All code
+     * in a system domain are granted with all permission and so this
+     * method returns false if 'from' class loader is a class loader
+     * loading system classes.  On the other hand, if a class loader
+     * attempts to access system domain classes, it requires package
+     * access check and this method will return true.
+     */
+    public static boolean needsPackageAccessCheck(ClassLoader from, ClassLoader to) {
+        if (from == null || from == to)
+            return false;
+
+        if (to == null)
+            return true;
+
+        return !isAncestor(from, to);
+    }
 }