changeset 6690:3ebfb90320ef

8017196: Ensure Proxies are handled appropriately Reviewed-by: dfuchs, jrose, jdn, ahgross, chegar
author mchung
date Thu, 18 Jul 2013 17:22:11 -0700
parents 269dc6aa6b62
children 54bd9675a80b
files src/share/classes/java/lang/invoke/MethodHandleNatives.java src/share/classes/java/lang/invoke/MethodHandles.java src/share/classes/java/lang/reflect/Proxy.java src/share/classes/sun/reflect/misc/ReflectUtil.java
diffstat 4 files changed, 75 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu Jul 18 10:12:56 2013 +0200
+++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Thu Jul 18 17:22:11 2013 -0700
@@ -492,6 +492,7 @@
             return defc == java.lang.ClassLoader.class;
         case "registerAsParallelCapable":
             return defc == java.lang.ClassLoader.class;
+        case "getInvocationHandler":
         case "getProxyClass":
         case "newProxyInstance":
             return defc == java.lang.reflect.Proxy.class;
--- a/src/share/classes/java/lang/invoke/MethodHandles.java	Thu Jul 18 10:12:56 2013 +0200
+++ b/src/share/classes/java/lang/invoke/MethodHandles.java	Thu Jul 18 17:22:11 2013 -0700
@@ -426,7 +426,7 @@
 
         Lookup(Class<?> lookupClass) {
             this(lookupClass, ALL_MODES);
-            checkUnprivilegedlookupClass(lookupClass);
+            checkUnprivilegedlookupClass(lookupClass, ALL_MODES);
         }
 
         private Lookup(Class<?> lookupClass, int allowedModes) {
@@ -480,7 +480,7 @@
                 // No permissions.
                 newModes = 0;
             }
-            checkUnprivilegedlookupClass(requestedLookupClass);
+            checkUnprivilegedlookupClass(requestedLookupClass, newModes);
             return new Lookup(requestedLookupClass, newModes);
         }
 
@@ -496,10 +496,19 @@
         /** Package-private version of lookup which is trusted. */
         static final Lookup IMPL_LOOKUP = new Lookup(Object.class, TRUSTED);
 
-        private static void checkUnprivilegedlookupClass(Class<?> lookupClass) {
+        private static void checkUnprivilegedlookupClass(Class<?> lookupClass, int allowedModes) {
             String name = lookupClass.getName();
             if (name.startsWith("java.lang.invoke."))
                 throw newIllegalArgumentException("illegal lookupClass: "+lookupClass);
+
+            // For caller-sensitive MethodHandles.lookup()
+            // disallow lookup more restricted packages
+            if (allowedModes == ALL_MODES && lookupClass.getClassLoader() == null) {
+                if (name.startsWith("java.") ||
+                        (name.startsWith("sun.") && !name.startsWith("sun.invoke."))) {
+                    throw newIllegalArgumentException("illegal lookupClass: " + lookupClass);
+                }
+            }
         }
 
         /**
--- a/src/share/classes/java/lang/reflect/Proxy.java	Thu Jul 18 10:12:56 2013 +0200
+++ b/src/share/classes/java/lang/reflect/Proxy.java	Thu Jul 18 17:22:11 2013 -0700
@@ -788,6 +788,7 @@
      * @throws  IllegalArgumentException if the argument is not a
      *          proxy instance
      */
+    @CallerSensitive
     public static InvocationHandler getInvocationHandler(Object proxy)
         throws IllegalArgumentException
     {
@@ -798,8 +799,19 @@
             throw new IllegalArgumentException("not a proxy instance");
         }
 
-        Proxy p = (Proxy) proxy;
-        return p.h;
+        final Proxy p = (Proxy) proxy;
+        final InvocationHandler ih = p.h;
+        if (System.getSecurityManager() != null) {
+            Class<?> ihClass = ih.getClass();
+            Class<?> caller = Reflection.getCallerClass();
+            if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(),
+                                                    ihClass.getClassLoader()))
+            {
+                ReflectUtil.checkPackageAccess(ihClass);
+            }
+        }
+
+        return ih;
     }
 
     private static native Class defineClass0(ClassLoader loader, String name,
--- a/src/share/classes/sun/reflect/misc/ReflectUtil.java	Thu Jul 18 10:12:56 2013 +0200
+++ b/src/share/classes/sun/reflect/misc/ReflectUtil.java	Thu Jul 18 17:22:11 2013 -0700
@@ -26,8 +26,10 @@
 
 package sun.reflect.misc;
 
+import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
+import java.util.Arrays;
 import sun.reflect.Reflection;
 
 public final class ReflectUtil {
@@ -249,4 +251,50 @@
         String pkg = (i != -1) ? name.substring(0, i) : "";
         return Proxy.isProxyClass(cls) && !pkg.equals(PROXY_PACKAGE);
     }
+
+    /**
+     * Check if the given method is a method declared in the proxy interface
+     * implemented by the given proxy instance.
+     *
+     * @param proxy a proxy instance
+     * @param method an interface method dispatched to a InvocationHandler
+     *
+     * @throws IllegalArgumentException if the given proxy or method is invalid.
+     */
+    public static void checkProxyMethod(Object proxy, Method method) {
+        // check if it is a valid proxy instance
+        if (proxy == null || !Proxy.isProxyClass(proxy.getClass())) {
+            throw new IllegalArgumentException("Not a Proxy instance");
 }
+        if (Modifier.isStatic(method.getModifiers())) {
+            throw new IllegalArgumentException("Can't handle static method");
+        }
+
+        Class<?> c = method.getDeclaringClass();
+        if (c == Object.class) {
+            String name = method.getName();
+            if (name.equals("hashCode") || name.equals("equals") || name.equals("toString")) {
+                return;
+            }
+        }
+
+        if (isSuperInterface(proxy.getClass(), c)) {
+            return;
+        }
+
+        // disallow any method not declared in one of the proxy intefaces
+        throw new IllegalArgumentException("Can't handle: " + method);
+    }
+
+    private static boolean isSuperInterface(Class<?> c, Class<?> intf) {
+        for (Class<?> i : c.getInterfaces()) {
+            if (i == intf) {
+                return true;
+            }
+            if (isSuperInterface(i, intf)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}