From 056924fd8fb79fcd0652a35114f59c66e7acd8e4 Mon Sep 17 00:00:00 2001 From: jrose Date: Wed, 1 Jun 2011 23:56:47 -0700 Subject: [PATCH] 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 --- .../java/lang/invoke/MethodHandleImpl.java | 26 ++++--- .../java/lang/invoke/MethodHandleNatives.java | 13 +--- .../java/lang/invoke/MethodHandleStatics.java | 15 +++- .../java/lang/invoke/MethodHandles.java | 72 ++++++++++++++++++- .../sun/invoke/util/ValueConversions.java | 14 +++- .../lang/invoke/InvokeDynamicPrintArgs.java | 47 +++++++++++- 6 files changed, 160 insertions(+), 27 deletions(-) diff --git a/src/share/classes/java/lang/invoke/MethodHandleImpl.java b/src/share/classes/java/lang/invoke/MethodHandleImpl.java index 06811feaf..5437e85a3 100644 --- a/src/share/classes/java/lang/invoke/MethodHandleImpl.java +++ b/src/share/classes/java/lang/invoke/MethodHandleImpl.java @@ -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 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 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() { + 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); } diff --git a/src/share/classes/java/lang/invoke/MethodHandleNatives.java b/src/share/classes/java/lang/invoke/MethodHandleNatives.java index 0d17f4a5c..ef3df63a3 100644 --- a/src/share/classes/java/lang/invoke/MethodHandleNatives.java +++ b/src/share/classes/java/lang/invoke/MethodHandleNatives.java @@ -395,18 +395,7 @@ class MethodHandleNatives { 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); diff --git a/src/share/classes/java/lang/invoke/MethodHandleStatics.java b/src/share/classes/java/lang/invoke/MethodHandleStatics.java index 61c442778..e812d245b 100644 --- a/src/share/classes/java/lang/invoke/MethodHandleStatics.java +++ b/src/share/classes/java/lang/invoke/MethodHandleStatics.java @@ -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 @@ package java.lang.invoke; 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() { + 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) diff --git a/src/share/classes/java/lang/invoke/MethodHandles.java b/src/share/classes/java/lang/invoke/MethodHandles.java index 42de21345..9e18b4b1a 100644 --- a/src/share/classes/java/lang/invoke/MethodHandles.java +++ b/src/share/classes/java/lang/invoke/MethodHandles.java @@ -35,6 +35,7 @@ import java.util.ArrayList; 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 @@ public class MethodHandles { 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 class MethodHandles { 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 class MethodHandles { public MethodHandle findConstructor(Class refc, MethodType type) throws NoSuchMethodException, IllegalAccessException { String name = ""; MemberName ctor = resolveOrFail(refc, name, type, false, false, lookupClassOrNull()); - assert(ctor.isConstructor()); 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()); 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 = ""; + 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 @@ public class MethodHandles { 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 @@ public class MethodHandles { 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 @@ public class MethodHandles { 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 @@ public class MethodHandles { 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 @@ public class MethodHandles { 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 @@ return mh1; 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); + } } /** diff --git a/src/share/classes/sun/invoke/util/ValueConversions.java b/src/share/classes/sun/invoke/util/ValueConversions.java index f3e2f85f8..917978598 100644 --- a/src/share/classes/sun/invoke/util/ValueConversions.java +++ b/src/share/classes/sun/invoke/util/ValueConversions.java @@ -29,6 +29,8 @@ import java.lang.invoke.MethodHandle; 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 @@ import java.util.List; 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() { + 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(); diff --git a/test/java/lang/invoke/InvokeDynamicPrintArgs.java b/test/java/lang/invoke/InvokeDynamicPrintArgs.java index 9c3db4291..89d2fdb4c 100644 --- a/test/java/lang/invoke/InvokeDynamicPrintArgs.java +++ b/test/java/lang/invoke/InvokeDynamicPrintArgs.java @@ -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 @@ import static java.lang.invoke.MethodType.*; 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 @@ public class InvokeDynamicPrintArgs { // 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 @@ public class InvokeDynamicPrintArgs { 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. -- GitLab