8011557: Improve reflection utility classes
authormchung
Wed, 17 Apr 2013 15:04:59 -0700
changeset 18244 a1031f4526b2
parent 18243 176cb77883eb
child 18245 7f4796a3f93a
8011557: Improve reflection utility classes Reviewed-by: ahgross, alanb
jdk/src/share/classes/java/lang/Class.java
jdk/src/share/classes/java/lang/reflect/Proxy.java
jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java
--- a/jdk/src/share/classes/java/lang/Class.java	Mon Apr 22 11:29:43 2013 +0100
+++ b/jdk/src/share/classes/java/lang/Class.java	Wed Apr 17 15:04:59 2013 -0700
@@ -2338,7 +2338,7 @@
                 if (i != -1) {
                     // skip the package access check on a proxy class in default proxy package
                     String pkg = name.substring(0, i);
-                    if (!Proxy.isProxyClass(this) || !pkg.equals(ReflectUtil.PROXY_PACKAGE)) {
+                    if (!Proxy.isProxyClass(this) || ReflectUtil.isNonPublicProxyClass(this)) {
                         s.checkPackageAccess(pkg);
                     }
                 }
--- a/jdk/src/share/classes/java/lang/reflect/Proxy.java	Mon Apr 22 11:29:43 2013 +0100
+++ b/jdk/src/share/classes/java/lang/reflect/Proxy.java	Wed Apr 17 15:04:59 2013 -0700
@@ -734,25 +734,21 @@
     private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass) {
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
-            String pcn = proxyClass.getName();
-            if (pcn.startsWith(ReflectUtil.PROXY_PACKAGE + ".")) {
-                // all proxy interfaces are public
-                return;
-            }
-
-            ClassLoader ccl = caller.getClassLoader();
-            ClassLoader pcl = proxyClass.getClassLoader();
+            if (ReflectUtil.isNonPublicProxyClass(proxyClass)) {
+                ClassLoader ccl = caller.getClassLoader();
+                ClassLoader pcl = proxyClass.getClassLoader();
 
-            // do permission check if the caller is in a different runtime package
-            // of the proxy class
-            int n = pcn.lastIndexOf('.');
-            String pkg = (n == -1) ? "" : pcn.substring(0, n);
+                // do permission check if the caller is in a different runtime package
+                // of the proxy class
+                int n = proxyClass.getName().lastIndexOf('.');
+                String pkg = (n == -1) ? "" : proxyClass.getName().substring(0, n);
 
-            n = caller.getName().lastIndexOf('.');
-            String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
+                n = caller.getName().lastIndexOf('.');
+                String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
 
-            if (pcl != ccl || !pkg.equals(callerPkg)) {
-                sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
+                if (pcl != ccl || !pkg.equals(callerPkg)) {
+                    sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
+                }
             }
         }
     }
--- a/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java	Mon Apr 22 11:29:43 2013 +0100
+++ b/jdk/src/share/classes/sun/reflect/misc/ReflectUtil.java	Wed Apr 17 15:04:59 2013 -0700
@@ -27,6 +27,7 @@
 package sun.reflect.misc;
 
 import java.lang.reflect.Modifier;
+import java.lang.reflect.Proxy;
 import sun.reflect.Reflection;
 
 public final class ReflectUtil {
@@ -114,11 +115,26 @@
         return false;
     }
 
-
+    /**
+     * Checks package access on the given class.
+     *
+     * If it is a {@link Proxy#isProxyClass(java.lang.Class)} that implements
+     * a non-public interface (i.e. may be in a non-restricted package),
+     * also check the package access on the proxy interfaces.
+     */
     public static void checkPackageAccess(Class<?> clazz) {
         checkPackageAccess(clazz.getName());
+        if (isNonPublicProxyClass(clazz)) {
+            checkProxyPackageAccess(clazz);
+        }
     }
 
+    /**
+     * Checks package access on the given classname.
+     * This method is typically called when the Class instance is not
+     * available and the caller attempts to load a class on behalf
+     * the true caller (application).
+     */
     public static void checkPackageAccess(String name) {
         SecurityManager s = System.getSecurityManager();
         if (s != null) {
@@ -180,13 +196,30 @@
     }
 
     /**
+     * Check package access on the proxy interfaces that the given proxy class
+     * implements.
+     *
+     * @param clazz Proxy class object
+     */
+    public static void checkProxyPackageAccess(Class<?> clazz) {
+        SecurityManager s = System.getSecurityManager();
+        if (s != null) {
+            // check proxy interfaces if the given class is a proxy class
+            if (Proxy.isProxyClass(clazz)) {
+                for (Class<?> intf : clazz.getInterfaces()) {
+                    checkPackageAccess(intf);
+                }
+            }
+        }
+    }
+
+    /**
      * Access check on the interfaces that a proxy class implements and throw
-     * {@code SecurityException} if it accesses a restricted package.
+     * {@code SecurityException} if it accesses a restricted package from
+     * the caller's class loader.
      *
      * @param ccl the caller's class loader
      * @param interfaces the list of interfaces that a proxy class implements
-     *
-     * @see Proxy#checkProxyAccess
      */
     public static void checkProxyPackageAccess(ClassLoader ccl,
                                                Class<?>... interfaces)
@@ -205,4 +238,16 @@
     // Note that bytecode instrumentation tools may exclude 'sun.*'
     // classes but not generated proxy classes and so keep it in com.sun.*
     public static final String PROXY_PACKAGE = "com.sun.proxy";
+
+    /**
+     * Test if the given class is a proxy class that implements
+     * non-public interface.  Such proxy class may be in a non-restricted
+     * package that bypasses checkPackageAccess.
+     */
+    public static boolean isNonPublicProxyClass(Class<?> cls) {
+        String name = cls.getName();
+        int i = name.lastIndexOf('.');
+        String pkg = (i != -1) ? name.substring(0, i) : "";
+        return Proxy.isProxyClass(cls) && !pkg.equals(PROXY_PACKAGE);
+    }
 }