7050328: (jsr-292) findConstructor throws ExceptionInInitializerError if run under SecurityManager
authorjrose
Wed, 01 Jun 2011 23:56:47 -0700
changeset 9780 6fc3b49cfee4
parent 9779 e3a8fbcb21fb
child 9781 ce852878da20
7050328: (jsr-292) findConstructor throws ExceptionInInitializerError if run under SecurityManager Summary: Wrap system property and reflection accesses under doPrivileged. Ensure constant pool linkage bypasses the SM as specified. Reviewed-by: kvn, never
jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java
jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java
jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java
jdk/src/share/classes/java/lang/invoke/MethodHandles.java
jdk/src/share/classes/sun/invoke/util/ValueConversions.java
jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Jun 01 23:56:43 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleImpl.java	Wed Jun 01 23:56:47 2011 -0700
@@ -26,6 +26,8 @@
 package java.lang.invoke;
 
 import sun.invoke.util.VerifyType;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -336,18 +338,20 @@
         void setFieldL(C obj, V x) { unsafe.putObject(obj, offset, x); }
         // cast (V) is OK here, since we wrap convertArguments around the MH.
 
-        static Object staticBase(MemberName field) {
+        static Object staticBase(final MemberName field) {
             if (!field.isStatic())  return null;
-            Class c = field.getDeclaringClass();
-            java.lang.reflect.Field f;
-            try {
-                // FIXME:  Should not have to create 'f' to get this value.
-                f = c.getDeclaredField(field.getName());
-                // Note:  Previous line might invalidly throw SecurityException (7042829)
-                return unsafe.staticFieldBase(f);
-            } catch (NoSuchFieldException ee) {
-                throw uncaughtException(ee);
-            }
+            return AccessController.doPrivileged(new PrivilegedAction<Object>() {
+                    public Object run() {
+                        try {
+                            Class c = field.getDeclaringClass();
+                            // FIXME:  Should not have to create 'f' to get this value.
+                            java.lang.reflect.Field f = c.getDeclaredField(field.getName());
+                            return unsafe.staticFieldBase(f);
+                        } catch (NoSuchFieldException ee) {
+                            throw uncaughtException(ee);
+                        }
+                    }
+                });
         }
 
         int getStaticI() { return unsafe.getInt(base, offset); }
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Wed Jun 01 23:56:43 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleNatives.java	Wed Jun 01 23:56:47 2011 -0700
@@ -395,18 +395,7 @@
                                                  Class<?> defc, String name, Object type) {
         try {
             Lookup lookup = IMPL_LOOKUP.in(callerClass);
-            switch (refKind) {
-            case REF_getField:          return lookup.findGetter(       defc, name, (Class<?>)   type );
-            case REF_getStatic:         return lookup.findStaticGetter( defc, name, (Class<?>)   type );
-            case REF_putField:          return lookup.findSetter(       defc, name, (Class<?>)   type );
-            case REF_putStatic:         return lookup.findStaticSetter( defc, name, (Class<?>)   type );
-            case REF_invokeVirtual:     return lookup.findVirtual(      defc, name, (MethodType) type );
-            case REF_invokeStatic:      return lookup.findStatic(       defc, name, (MethodType) type );
-            case REF_invokeSpecial:     return lookup.findSpecial(      defc, name, (MethodType) type, callerClass );
-            case REF_newInvokeSpecial:  return lookup.findConstructor(  defc,       (MethodType) type );
-            case REF_invokeInterface:   return lookup.findVirtual(      defc, name, (MethodType) type );
-            }
-            throw new InternalError("bad MethodHandle constant "+name+" : "+type);
+            return lookup.linkMethodHandleConstant(refKind, defc, name, type);
         } catch (ReflectiveOperationException ex) {
             Error err = new IncompatibleClassChangeError();
             err.initCause(ex);
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java	Wed Jun 01 23:56:43 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandleStatics.java	Wed Jun 01 23:56:47 2011 -0700
@@ -25,6 +25,9 @@
 
 package java.lang.invoke;
 
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
 /**
  * This class consists exclusively of static names internal to the
  * method handle implementation.
@@ -35,7 +38,17 @@
 
     private MethodHandleStatics() { }  // do not instantiate
 
-    static final boolean DEBUG_METHOD_HANDLE_NAMES = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
+    static final boolean DEBUG_METHOD_HANDLE_NAMES;
+    static {
+        final Object[] values = { false };
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    values[0] = Boolean.getBoolean("java.lang.invoke.MethodHandle.DEBUG_NAMES");
+                    return null;
+                }
+            });
+        DEBUG_METHOD_HANDLE_NAMES = (Boolean) values[0];
+    }
 
     /*non-public*/ static String getNameString(MethodHandle target, MethodType type) {
         if (type == null)
--- a/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Wed Jun 01 23:56:43 2011 -0700
+++ b/jdk/src/share/classes/java/lang/invoke/MethodHandles.java	Wed Jun 01 23:56:47 2011 -0700
@@ -35,6 +35,7 @@
 import java.util.Arrays;
 import sun.reflect.Reflection;
 import static java.lang.invoke.MethodHandleStatics.*;
+import static java.lang.invoke.MethodHandleNatives.Constants.*;
 
 /**
  * This class consists exclusively of static methods that operate on or return
@@ -579,9 +580,18 @@
         MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             MemberName method = resolveOrFail(refc, name, type, true);
             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
+            return accessStatic(refc, method);
+        }
+        private
+        MethodHandle accessStatic(Class<?> refc, MemberName method) throws IllegalAccessException {
             checkMethod(refc, method, true);
             return MethodHandleImpl.findMethod(method, false, lookupClassOrNull());
         }
+        private
+        MethodHandle resolveStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+            MemberName method = resolveOrFail(refc, name, type, true);
+            return accessStatic(refc, method);
+        }
 
         /**
          * Produces a method handle for a virtual method.
@@ -624,6 +634,13 @@
         public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             MemberName method = resolveOrFail(refc, name, type, false);
             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
+            return accessVirtual(refc, method);
+        }
+        private MethodHandle resolveVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+            MemberName method = resolveOrFail(refc, name, type, false);
+            return accessVirtual(refc, method);
+        }
+        private MethodHandle accessVirtual(Class<?> refc, MemberName method) throws IllegalAccessException {
             checkMethod(refc, method, false);
             MethodHandle mh = MethodHandleImpl.findMethod(method, true, lookupClassOrNull());
             return restrictProtectedReceiver(method, mh);
@@ -658,13 +675,21 @@
         public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
             String name = "<init>";
             MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull());
+            checkSecurityManager(refc, ctor);  // stack walk magic: do not refactor
+            return accessConstructor(refc, ctor);
+        }
+        private MethodHandle accessConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {
             assert(ctor.isConstructor());
-            checkSecurityManager(refc, ctor);  // stack walk magic: do not refactor
             checkAccess(refc, ctor);
             MethodHandle rawMH = MethodHandleImpl.findMethod(ctor, false, lookupClassOrNull());
             MethodHandle allocMH = MethodHandleImpl.makeAllocator(rawMH);
             return fixVarargs(allocMH, rawMH);
         }
+        private MethodHandle resolveConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+            String name = "<init>";
+            MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull());
+            return accessConstructor(refc, ctor);
+        }
 
         /** Return a version of MH which matches matchMH w.r.t. isVarargsCollector. */
         private static MethodHandle fixVarargs(MethodHandle mh, MethodHandle matchMH) {
@@ -720,10 +745,20 @@
             checkSpecialCaller(specialCaller);
             MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller);
             checkSecurityManager(refc, method);  // stack walk magic: do not refactor
+            return accessSpecial(refc, method, specialCaller);
+        }
+        private MethodHandle accessSpecial(Class<?> refc, MemberName method,
+                                           Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
             checkMethod(refc, method, false);
             MethodHandle mh = MethodHandleImpl.findMethod(method, false, specialCaller);
             return restrictReceiver(method, mh, specialCaller);
         }
+        private MethodHandle resolveSpecial(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
+            Class<?> specialCaller = lookupClass();
+            checkSpecialCaller(specialCaller);
+            MemberName method = resolveOrFail(refc, name, type, false, false, specialCaller);
+            return accessSpecial(refc, method, specialCaller);
+        }
 
         /**
          * Produces a method handle giving read access to a non-static field.
@@ -747,6 +782,10 @@
             checkSecurityManager(refc, field);  // stack walk magic: do not refactor
             return makeAccessor(refc, field, false, false, 0);
         }
+        private MethodHandle resolveGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+            MemberName field = resolveOrFail(refc, name, type, false);
+            return makeAccessor(refc, field, false, false, 0);
+        }
 
         /**
          * Produces a method handle giving write access to a non-static field.
@@ -770,6 +809,10 @@
             checkSecurityManager(refc, field);  // stack walk magic: do not refactor
             return makeAccessor(refc, field, false, true, 0);
         }
+        private MethodHandle resolveSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+            MemberName field = resolveOrFail(refc, name, type, false);
+            return makeAccessor(refc, field, false, true, 0);
+        }
 
         /**
          * Produces a method handle giving read access to a static field.
@@ -792,6 +835,10 @@
             checkSecurityManager(refc, field);  // stack walk magic: do not refactor
             return makeAccessor(refc, field, false, false, 1);
         }
+        private MethodHandle resolveStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+            MemberName field = resolveOrFail(refc, name, type, true);
+            return makeAccessor(refc, field, false, false, 1);
+        }
 
         /**
          * Produces a method handle giving write access to a static field.
@@ -814,6 +861,10 @@
             checkSecurityManager(refc, field);  // stack walk magic: do not refactor
             return makeAccessor(refc, field, false, true, 1);
         }
+        private MethodHandle resolveStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
+            MemberName field = resolveOrFail(refc, name, type, true);
+            return makeAccessor(refc, field, false, true, 1);
+        }
 
         /**
          * Produces an early-bound method handle for a non-static method.
@@ -1179,6 +1230,25 @@
             MethodHandle mh = MethodHandleImpl.accessField(field, isSetter, lookupClassOrNull());
             return restrictProtectedReceiver(field, mh);
         }
+
+        /** Hook called from the JVM (via MethodHandleNatives) to link MH constants:
+         */
+        /*non-public*/
+        MethodHandle linkMethodHandleConstant(int refKind, Class<?> defc, String name, Object type) throws ReflectiveOperationException {
+            switch (refKind) {
+            case REF_getField:          return resolveGetter(       defc, name, (Class<?>)   type );
+            case REF_getStatic:         return resolveStaticGetter( defc, name, (Class<?>)   type );
+            case REF_putField:          return resolveSetter(       defc, name, (Class<?>)   type );
+            case REF_putStatic:         return resolveStaticSetter( defc, name, (Class<?>)   type );
+            case REF_invokeVirtual:     return resolveVirtual(      defc, name, (MethodType) type );
+            case REF_invokeStatic:      return resolveStatic(       defc, name, (MethodType) type );
+            case REF_invokeSpecial:     return resolveSpecial(      defc, name, (MethodType) type );
+            case REF_newInvokeSpecial:  return resolveConstructor(  defc,       (MethodType) type );
+            case REF_invokeInterface:   return resolveVirtual(      defc, name, (MethodType) type );
+            }
+            // oops
+            throw new ReflectiveOperationException("bad MethodHandle constant #"+refKind+" "+name+" : "+type);
+        }
     }
 
     /**
--- a/jdk/src/share/classes/sun/invoke/util/ValueConversions.java	Wed Jun 01 23:56:43 2011 -0700
+++ b/jdk/src/share/classes/sun/invoke/util/ValueConversions.java	Wed Jun 01 23:56:47 2011 -0700
@@ -29,6 +29,8 @@
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
 import java.lang.invoke.MethodType;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -38,7 +40,17 @@
 public class ValueConversions {
     private static final Class<?> THIS_CLASS = ValueConversions.class;
     // Do not adjust this except for special platforms:
-    private static final int MAX_ARITY = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
+    private static final int MAX_ARITY;
+    static {
+        final Object[] values = { 255 };
+        AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    values[0] = Integer.getInteger(THIS_CLASS.getName()+".MAX_ARITY", 255);
+                    return null;
+                }
+            });
+        MAX_ARITY = (Integer) values[0];
+    }
 
     private static final Lookup IMPL_LOOKUP = MethodHandles.lookup();
 
--- a/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java	Wed Jun 01 23:56:43 2011 -0700
+++ b/jdk/test/java/lang/invoke/InvokeDynamicPrintArgs.java	Wed Jun 01 23:56:47 2011 -0700
@@ -30,6 +30,10 @@
  *      --verify-specifier-count=3
  *      --expand-properties --classpath ${test.classes}
  *      --java test.java.lang.invoke.InvokeDynamicPrintArgs --check-output
+ * @run main/othervm
+ *      indify.Indify
+ *      --expand-properties --classpath ${test.classes}
+ *      --java test.java.lang.invoke.InvokeDynamicPrintArgs --security-manager
  */
 
 package test.java.lang.invoke;
@@ -45,7 +49,8 @@
 
 public class InvokeDynamicPrintArgs {
     public static void main(String... av) throws Throwable {
-        if (av.length > 0)  openBuf();  // --check-output mode
+        if (av.length > 0 && av[0].equals("--check-output"))  openBuf();
+        if (av.length > 0 && av[0].equals("--security-manager"))  setSM();
         System.out.println("Printing some argument lists, starting with a empty one:");
         INDY_nothing().invokeExact();                 // BSM specifier #0 = {bsm}
         INDY_bar().invokeExact("bar arg", 1);         // BSM specifier #1 = {bsm2, Void.class, "void type"}
@@ -55,6 +60,43 @@
         // Hence, BSM specifier count should be 3.  See "--verify-specifier-count=3" above.
         System.out.println("Done printing argument lists.");
         closeBuf();
+        checkConstantRefs();
+    }
+
+    private static void checkConstantRefs() throws Throwable {
+        // check some constant references:
+        assertEquals(MT_bsm(), MH_bsm().type());
+        assertEquals(MT_bsm2(), MH_bsm2().type());
+        try {
+            assertEquals(MT_bsm(), non_MH_bsm().type());
+            // if SM is installed, must throw before this point
+            assertEquals(false, System.getSecurityManager() != null);
+        } catch (SecurityException ex) {
+            // if SM is installed, must throw to this point
+            assertEquals(true, System.getSecurityManager() != null);
+        }
+    }
+    private static void assertEquals(Object exp, Object act) {
+        if (exp == act || (exp != null && exp.equals(act)))  return;
+        throw new AssertionError("not equal: "+exp+", "+act);
+    }
+
+    private static void setSM() {
+        // Test for severe security manager interactions (7050328).
+        class SM extends SecurityManager {
+            public void checkPackageAccess(String pkg) {
+                if (pkg.startsWith("test."))
+                    throw new SecurityException("checkPackageAccess "+pkg);
+            }
+            public void checkMemberAccess(Class<?> clazz, int which) {
+                if (clazz == InvokeDynamicPrintArgs.class)
+                    throw new SecurityException("checkMemberAccess "+clazz.getName()+" #"+which);
+            }
+            // allow these others:
+            public void checkPermission(java.security.Permission perm) {
+            }
+        }
+        System.setSecurityManager(new SM());
     }
 
     @Test
@@ -130,6 +172,9 @@
         shouldNotCallThis();
         return lookup().findStatic(lookup().lookupClass(), "bsm", MT_bsm());
     }
+    private static MethodHandle non_MH_bsm() throws ReflectiveOperationException {
+        return lookup().findStatic(lookup().lookupClass(), "bsm", MT_bsm());
+    }
 
     /* Example of a constant call site with user-data.
      * In this case, the user data is exactly the BSM data.