提交 6a4b3466 编写于 作者: J jrose

8025112: JSR 292 spec updates for security manager and caller sensitivity

Summary: align CONSTANT_MethodHandle and Lookup.find* API calls, clarify security manager & @CallerSensitive interactions
Reviewed-by: mchung, twisti
上级 31532c96
...@@ -1330,6 +1330,11 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString()); ...@@ -1330,6 +1330,11 @@ assertEquals("[three, thee, tee]", asListFix.invoke((Object)argv).toString());
return null; // DMH returns DMH.member return null; // DMH returns DMH.member
} }
/*non-public*/
Class<?> internalCallerClass() {
return null; // caller-bound MH for @CallerSensitive method returns caller
}
/*non-public*/ /*non-public*/
MethodHandle withInternalMemberName(MemberName member) { MethodHandle withInternalMemberName(MemberName member) {
if (member != null) { if (member != null) {
......
...@@ -381,6 +381,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -381,6 +381,10 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MemberName internalMemberName() { MemberName internalMemberName() {
return asFixedArity().internalMemberName(); return asFixedArity().internalMemberName();
} }
@Override
Class<?> internalCallerClass() {
return asFixedArity().internalCallerClass();
}
/*non-public*/ /*non-public*/
@Override @Override
...@@ -831,7 +835,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -831,7 +835,7 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
MethodHandle vamh = prepareForInvoker(mh); MethodHandle vamh = prepareForInvoker(mh);
// Cache the result of makeInjectedInvoker once per argument class. // Cache the result of makeInjectedInvoker once per argument class.
MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass);
return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName()); return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass);
} }
private static MethodHandle makeInjectedInvoker(Class<?> hostClass) { private static MethodHandle makeInjectedInvoker(Class<?> hostClass) {
...@@ -886,10 +890,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -886,10 +890,12 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
} }
// Undo the adapter effect of prepareForInvoker: // Undo the adapter effect of prepareForInvoker:
private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, MemberName member) { private static MethodHandle restoreToType(MethodHandle vamh, MethodType type,
MemberName member,
Class<?> hostClass) {
MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount()); MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount());
mh = mh.asType(type); mh = mh.asType(type);
mh = mh.withInternalMemberName(member); mh = new WrappedMember(mh, type, member, hostClass);
return mh; return mh;
} }
...@@ -958,11 +964,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -958,11 +964,13 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
static class WrappedMember extends MethodHandle { static class WrappedMember extends MethodHandle {
private final MethodHandle target; private final MethodHandle target;
private final MemberName member; private final MemberName member;
private final Class<?> callerClass;
private WrappedMember(MethodHandle target, MethodType type, MemberName member) { private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) {
super(type, reinvokerForm(target)); super(type, reinvokerForm(target));
this.target = target; this.target = target;
this.member = member; this.member = member;
this.callerClass = callerClass;
} }
@Override @Override
...@@ -980,19 +988,23 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; ...@@ -980,19 +988,23 @@ import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP;
return member; return member;
} }
@Override @Override
Class<?> internalCallerClass() {
return callerClass;
}
@Override
boolean isInvokeSpecial() { boolean isInvokeSpecial() {
return target.isInvokeSpecial(); return target.isInvokeSpecial();
} }
@Override @Override
MethodHandle viewAsType(MethodType newType) { MethodHandle viewAsType(MethodType newType) {
return new WrappedMember(target, newType, member); return new WrappedMember(target, newType, member, callerClass);
} }
} }
static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) { static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) {
if (member.equals(target.internalMemberName())) if (member.equals(target.internalMemberName()))
return target; return target;
return new WrappedMember(target, target.type(), member); return new WrappedMember(target, target.type(), member, null);
} }
} }
...@@ -61,6 +61,18 @@ import static java.lang.invoke.MethodHandleStatics.*; ...@@ -61,6 +61,18 @@ import static java.lang.invoke.MethodHandleStatics.*;
* Cracking must be done via a {@code Lookup} object equivalent to that which created * Cracking must be done via a {@code Lookup} object equivalent to that which created
* the target method handle, or which has enough access permissions to recreate * the target method handle, or which has enough access permissions to recreate
* an equivalent method handle. * an equivalent method handle.
* <p>
* If the underlying method is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>,
* the direct method handle will have been "bound" to a particular caller class, the
* {@linkplain java.lang.invoke.MethodHandles.Lookup#lookupClass() lookup class}
* of the lookup object used to create it.
* Cracking this method handle with a different lookup class will fail
* even if the underlying method is public (like {@code Class.forName}).
* <p>
* The requirement of lookup object matching provides a "fast fail" behavior
* for programs which may otherwise trust erroneous revelation of a method
* handle with symbolic information (or caller binding) from an unexpected scope.
* Use {@link java.lang.invoke.MethodHandles#reflectAs} to override this limitation.
* *
* <h1><a name="refkinds"></a>Reference kinds</h1> * <h1><a name="refkinds"></a>Reference kinds</h1>
* The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a> * The <a href="MethodHandles.Lookup.html#lookups">Lookup Factory Methods</a>
......
...@@ -107,6 +107,11 @@ public class MethodHandleProxies { ...@@ -107,6 +107,11 @@ public class MethodHandleProxies {
* such as abstract classes with single abstract methods. * such as abstract classes with single abstract methods.
* Future versions of this API may also equip wrapper instances * Future versions of this API may also equip wrapper instances
* with one or more additional public "marker" interfaces. * with one or more additional public "marker" interfaces.
* <p>
* If a security manager is installed, this method is caller sensitive.
* During any invocation of the target method handle via the returned wrapper,
* the original creator of the wrapper (the caller) will be visible
* to context checks requested by the security manager.
* *
* @param <T> the desired type of the wrapper, a single-method interface * @param <T> the desired type of the wrapper, a single-method interface
* @param intfc a class object representing {@code T} * @param intfc a class object representing {@code T}
......
...@@ -90,6 +90,10 @@ public class MethodHandles { ...@@ -90,6 +90,10 @@ public class MethodHandles {
* {@linkplain Lookup#in <code>publicLookup().in(C.class)</code>}. * {@linkplain Lookup#in <code>publicLookup().in(C.class)</code>}.
* Since all classes have equal access to public names, * Since all classes have equal access to public names,
* such a change would confer no new access rights. * such a change would confer no new access rights.
* A public lookup object is always subject to
* <a href="MethodHandles.Lookup.html#secmgr">security manager checks</a>.
* Also, it cannot access
* <a href="MethodHandles.Lookup.html#callsens">caller sensitive methods</a>.
* @return a lookup object which is trusted minimally * @return a lookup object which is trusted minimally
*/ */
public static Lookup publicLookup() { public static Lookup publicLookup() {
...@@ -242,9 +246,9 @@ public class MethodHandles { ...@@ -242,9 +246,9 @@ public class MethodHandles {
* For example, lookups for {@code MethodHandle.invokeExact} and * For example, lookups for {@code MethodHandle.invokeExact} and
* {@code MethodHandle.invoke} will always succeed, regardless of requested type. * {@code MethodHandle.invoke} will always succeed, regardless of requested type.
* <li>If there is a security manager installed, it can forbid the lookup * <li>If there is a security manager installed, it can forbid the lookup
* on various grounds (<a href="#secmgr">see below</a>). * on various grounds (<a href="MethodHandles.Lookup.html#secmgr">see below</a>).
* By contrast, the {@code ldc} instruction is not subject to * By contrast, the {@code ldc} instruction on a {@code CONSTANT_MethodHandle}
* security manager checks. * constant is not subject to security manager checks.
* <li>If the looked-up method has a * <li>If the looked-up method has a
* <a href="MethodHandle.html#maxarity">very large arity</a>, * <a href="MethodHandle.html#maxarity">very large arity</a>,
* the method handle creation may fail, due to the method handle * the method handle creation may fail, due to the method handle
...@@ -374,13 +378,42 @@ public class MethodHandles { ...@@ -374,13 +378,42 @@ public class MethodHandles {
* {@link SecurityManager#checkPermission smgr.checkPermission} * {@link SecurityManager#checkPermission smgr.checkPermission}
* with {@code RuntimePermission("accessDeclaredMembers")} is called. * with {@code RuntimePermission("accessDeclaredMembers")} is called.
* <li>If the retrieved member is not public, * <li>If the retrieved member is not public,
* and if {@code lookc} is not present,
* and if {@code defc} and {@code refc} are different, * and if {@code defc} and {@code refc} are different,
* then {@link SecurityManager#checkPackageAccess * then {@link SecurityManager#checkPackageAccess
* smgr.checkPackageAccess(defcPkg)} is called, * smgr.checkPackageAccess(defcPkg)} is called,
* where {@code defcPkg} is the package of {@code defc}. * where {@code defcPkg} is the package of {@code defc}.
* </ul> * </ul>
* Security checks are performed after other access checks have passed.
* Therefore, the above rules presuppose a member that is public,
* or else that is being accessed from a lookup class that has
* rights to access the member.
*
* <h1><a name="callsens"></a>Caller sensitive methods</h1>
* A small number of Java methods have a special property called caller sensitivity.
* A <em>caller-sensitive</em> method can behave differently depending on the
* identity of its immediate caller.
* <p>
* If a method handle for a caller-sensitive method is requested,
* the general rules for <a href="MethodHandles.Lookup.html#equiv">bytecode behaviors</a> apply,
* but they take account of the lookup class in a special way.
* The resulting method handle behaves as if it were called
* from an instruction contained in the lookup class,
* so that the caller-sensitive method detects the lookup class.
* (By contrast, the invoker of the method handle is disregarded.)
* Thus, in the case of caller-sensitive methods,
* different lookup classes may give rise to
* differently behaving method handles.
* <p>
* In cases where the lookup object is
* {@link MethodHandles#publicLookup() publicLookup()},
* or some other lookup object without
* {@linkplain java.lang.invoke.MethodHandles.Lookup#PRIVATE private access},
* the lookup class is disregarded.
* In such cases, no caller-sensitive method handle can be created,
* access is forbidden, and the lookup fails with an
* {@code IllegalAccessException}.
*/ */
// FIXME in MR1: clarify that the bytecode behavior of a caller-ID method (like Class.forName) is relative to the lookupClass used to create the method handle, not the dynamic caller of the method handle
public static final public static final
class Lookup { class Lookup {
/** The class on behalf of whom the lookup is being performed. */ /** The class on behalf of whom the lookup is being performed. */
...@@ -639,7 +672,6 @@ assertEquals("[x, y]", MH_asList.invoke("x", "y").toString()); ...@@ -639,7 +672,6 @@ assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
public public
MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type); MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
checkSecurityManager(refc, method);
return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerClass(method)); return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerClass(method));
} }
...@@ -721,7 +753,6 @@ assertEquals("", (String) MH_newString.invokeExact()); ...@@ -721,7 +753,6 @@ assertEquals("", (String) MH_newString.invokeExact());
} }
byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual); byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
MemberName method = resolveOrFail(refKind, refc, name, type); MemberName method = resolveOrFail(refKind, refc, name, type);
checkSecurityManager(refc, method);
return getDirectMethod(refKind, refc, method, findBoundCallerClass(method)); return getDirectMethod(refKind, refc, method, findBoundCallerClass(method));
} }
private MethodHandle findVirtualForMH(String name, MethodType type) { private MethodHandle findVirtualForMH(String name, MethodType type) {
...@@ -782,7 +813,6 @@ assertEquals("[x, y, z]", pb.command().toString()); ...@@ -782,7 +813,6 @@ assertEquals("[x, y, z]", pb.command().toString());
public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException { public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
String name = "<init>"; String name = "<init>";
MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type); MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
checkSecurityManager(refc, ctor);
return getDirectConstructor(refc, ctor); return getDirectConstructor(refc, ctor);
} }
...@@ -864,7 +894,6 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method ...@@ -864,7 +894,6 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
checkSpecialCaller(specialCaller); checkSpecialCaller(specialCaller);
Lookup specialLookup = this.in(specialCaller); Lookup specialLookup = this.in(specialCaller);
MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type); MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
checkSecurityManager(refc, method);
return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, findBoundCallerClass(method)); return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
} }
...@@ -887,7 +916,6 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method ...@@ -887,7 +916,6 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
*/ */
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_getField, refc, name, type); MemberName field = resolveOrFail(REF_getField, refc, name, type);
checkSecurityManager(refc, field);
return getDirectField(REF_getField, refc, field); return getDirectField(REF_getField, refc, field);
} }
...@@ -910,7 +938,6 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method ...@@ -910,7 +938,6 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
*/ */
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_putField, refc, name, type); MemberName field = resolveOrFail(REF_putField, refc, name, type);
checkSecurityManager(refc, field);
return getDirectField(REF_putField, refc, field); return getDirectField(REF_putField, refc, field);
} }
...@@ -935,7 +962,6 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method ...@@ -935,7 +962,6 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
*/ */
public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_getStatic, refc, name, type); MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
checkSecurityManager(refc, field);
return getDirectField(REF_getStatic, refc, field); return getDirectField(REF_getStatic, refc, field);
} }
...@@ -960,7 +986,6 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method ...@@ -960,7 +986,6 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
*/ */
public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException { public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
MemberName field = resolveOrFail(REF_putStatic, refc, name, type); MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
checkSecurityManager(refc, field);
return getDirectField(REF_putStatic, refc, field); return getDirectField(REF_putStatic, refc, field);
} }
...@@ -1013,7 +1038,6 @@ return mh1; ...@@ -1013,7 +1038,6 @@ return mh1;
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException { public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
Class<? extends Object> refc = receiver.getClass(); // may get NPE Class<? extends Object> refc = receiver.getClass(); // may get NPE
MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type); MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
checkSecurityManager(refc, method);
MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method)); MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
return mh.bindReceiver(receiver).setVarargs(method); return mh.bindReceiver(receiver).setVarargs(method);
} }
...@@ -1054,7 +1078,7 @@ return mh1; ...@@ -1054,7 +1078,7 @@ return mh1;
refKind = REF_invokeVirtual; refKind = REF_invokeVirtual;
assert(method.isMethod()); assert(method.isMethod());
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this; Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method)); return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
} }
private MethodHandle unreflectForMH(Method m) { private MethodHandle unreflectForMH(Method m) {
// these names require special lookups because they throw UnsupportedOperationException // these names require special lookups because they throw UnsupportedOperationException
...@@ -1090,7 +1114,7 @@ return mh1; ...@@ -1090,7 +1114,7 @@ return mh1;
MemberName method = new MemberName(m, true); MemberName method = new MemberName(m, true);
assert(method.isMethod()); assert(method.isMethod());
// ignore m.isAccessible: this is a new kind of access // ignore m.isAccessible: this is a new kind of access
return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method)); return specialLookup.getDirectMethodNoSecurityManager(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method));
} }
/** /**
...@@ -1122,7 +1146,7 @@ return mh1; ...@@ -1122,7 +1146,7 @@ return mh1;
MemberName ctor = new MemberName(c); MemberName ctor = new MemberName(c);
assert(ctor.isConstructor()); assert(ctor.isConstructor());
Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this; Lookup lookup = c.isAccessible() ? IMPL_LOOKUP : this;
return lookup.getDirectConstructor(ctor.getDeclaringClass(), ctor); return lookup.getDirectConstructorNoSecurityManager(ctor.getDeclaringClass(), ctor);
} }
/** /**
...@@ -1152,7 +1176,7 @@ return mh1; ...@@ -1152,7 +1176,7 @@ return mh1;
? MethodHandleNatives.refKindIsSetter(field.getReferenceKind()) ? MethodHandleNatives.refKindIsSetter(field.getReferenceKind())
: MethodHandleNatives.refKindIsGetter(field.getReferenceKind())); : MethodHandleNatives.refKindIsGetter(field.getReferenceKind()));
Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this; Lookup lookup = f.isAccessible() ? IMPL_LOOKUP : this;
return lookup.getDirectField(field.getReferenceKind(), f.getDeclaringClass(), field); return lookup.getDirectFieldNoSecurityManager(field.getReferenceKind(), f.getDeclaringClass(), field);
} }
/** /**
...@@ -1183,6 +1207,8 @@ return mh1; ...@@ -1183,6 +1207,8 @@ return mh1;
* is capable of reproducing the target method handle. * is capable of reproducing the target method handle.
* This means that the cracking may fail if target is a direct method handle * This means that the cracking may fail if target is a direct method handle
* but was created by an unrelated lookup object. * but was created by an unrelated lookup object.
* This can happen if the method handle is <a href="MethodHandles.Lookup.html#callsens">caller sensitive</a>
* and was created by a lookup object for a different class.
* @param target a direct method handle to crack into symbolic reference components * @param target a direct method handle to crack into symbolic reference components
* @return a symbolic reference which can be used to reconstruct this method handle from this lookup object * @return a symbolic reference which can be used to reconstruct this method handle from this lookup object
* @exception SecurityException if a security manager is present and it * @exception SecurityException if a security manager is present and it
...@@ -1208,11 +1234,16 @@ return mh1; ...@@ -1208,11 +1234,16 @@ return mh1;
refKind = REF_invokeInterface; refKind = REF_invokeInterface;
// Check SM permissions and member access before cracking. // Check SM permissions and member access before cracking.
try { try {
checkSecurityManager(defc, member);
checkAccess(refKind, defc, member); checkAccess(refKind, defc, member);
checkSecurityManager(defc, member);
} catch (IllegalAccessException ex) { } catch (IllegalAccessException ex) {
throw new IllegalArgumentException(ex); throw new IllegalArgumentException(ex);
} }
if (allowedModes != TRUSTED && member.isCallerSensitive()) {
Class<?> callerClass = target.internalCallerClass();
if (!hasPrivateAccess() || callerClass != lookupClass())
throw new IllegalArgumentException("method handle is caller sensitive: "+callerClass);
}
// Produce the handle to the results. // Produce the handle to the results.
return new InfoFromMemberName(this, member, refKind); return new InfoFromMemberName(this, member, refKind);
} }
...@@ -1266,8 +1297,8 @@ return mh1; ...@@ -1266,8 +1297,8 @@ return mh1;
Class<?> findBoundCallerClass(MemberName m) throws IllegalAccessException { Class<?> findBoundCallerClass(MemberName m) throws IllegalAccessException {
Class<?> callerClass = null; Class<?> callerClass = null;
if (MethodHandleNatives.isCallerSensitive(m)) { if (MethodHandleNatives.isCallerSensitive(m)) {
// Only full-power lookup is allowed to resolve caller-sensitive methods // Only lookups with private access are allowed to resolve caller-sensitive methods
if (isFullPowerLookup()) { if (hasPrivateAccess()) {
callerClass = lookupClass; callerClass = lookupClass;
} else { } else {
throw new IllegalAccessException("Attempt to lookup caller-sensitive method using restricted lookup object"); throw new IllegalAccessException("Attempt to lookup caller-sensitive method using restricted lookup object");
...@@ -1276,7 +1307,7 @@ return mh1; ...@@ -1276,7 +1307,7 @@ return mh1;
return callerClass; return callerClass;
} }
private boolean isFullPowerLookup() { private boolean hasPrivateAccess() {
return (allowedModes & PRIVATE) != 0; return (allowedModes & PRIVATE) != 0;
} }
...@@ -1291,22 +1322,21 @@ return mh1; ...@@ -1291,22 +1322,21 @@ return mh1;
if (allowedModes == TRUSTED) return; if (allowedModes == TRUSTED) return;
// Step 1: // Step 1:
if (!isFullPowerLookup() || boolean fullPowerLookup = hasPrivateAccess();
if (!fullPowerLookup ||
!VerifyAccess.classLoaderIsAncestor(lookupClass, refc)) { !VerifyAccess.classLoaderIsAncestor(lookupClass, refc)) {
ReflectUtil.checkPackageAccess(refc); ReflectUtil.checkPackageAccess(refc);
} }
// Step 2: // Step 2:
if (m.isPublic()) return; if (m.isPublic()) return;
Class<?> defc = m.getDeclaringClass(); if (!fullPowerLookup) {
{ smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
if (!isFullPowerLookup()) {
smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
}
} }
// Step 3: // Step 3:
if (defc != refc) { Class<?> defc = m.getDeclaringClass();
if (!fullPowerLookup && defc != refc) {
ReflectUtil.checkPackageAccess(defc); ReflectUtil.checkPackageAccess(defc);
} }
} }
...@@ -1335,6 +1365,7 @@ return mh1; ...@@ -1335,6 +1365,7 @@ return mh1;
throw m.makeAccessException(message, this); throw m.makeAccessException(message, this);
} }
/** Check public/protected/private bits on the symbolic reference class and its member. */
void checkAccess(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException { void checkAccess(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
assert(m.referenceKindIsConsistentWith(refKind) && assert(m.referenceKindIsConsistentWith(refKind) &&
MethodHandleNatives.refKindIsValid(refKind) && MethodHandleNatives.refKindIsValid(refKind) &&
...@@ -1409,7 +1440,7 @@ return mh1; ...@@ -1409,7 +1440,7 @@ return mh1;
private void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException { private void checkSpecialCaller(Class<?> specialCaller) throws IllegalAccessException {
int allowedModes = this.allowedModes; int allowedModes = this.allowedModes;
if (allowedModes == TRUSTED) return; if (allowedModes == TRUSTED) return;
if ((allowedModes & PRIVATE) == 0 if (!hasPrivateAccess()
|| (specialCaller != lookupClass() || (specialCaller != lookupClass()
&& !(ALLOW_NESTMATE_ACCESS && && !(ALLOW_NESTMATE_ACCESS &&
VerifyAccess.isSamePackageMember(specialCaller, lookupClass())))) VerifyAccess.isSamePackageMember(specialCaller, lookupClass()))))
...@@ -1441,18 +1472,32 @@ return mh1; ...@@ -1441,18 +1472,32 @@ return mh1;
return mh.viewAsType(narrowType); return mh.viewAsType(narrowType);
} }
/** Check access and get the requested method. */
private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException { private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
return getDirectMethodCommon(refKind, refc, method, final boolean doRestrict = true;
(refKind == REF_invokeSpecial || final boolean checkSecurity = true;
(MethodHandleNatives.refKindHasReceiver(refKind) && return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
restrictProtectedReceiver(method))), callerClass);
} }
/** Check access and get the requested method, eliding receiver narrowing rules. */
private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException { private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
return getDirectMethodCommon(refKind, refc, method, false, callerClass); final boolean doRestrict = false;
final boolean checkSecurity = true;
return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
}
/** Check access and get the requested method, eliding security manager checks. */
private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
final boolean doRestrict = true;
final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants
return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
} }
/** Common code for all methods; do not call directly except from immediately above. */
private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method, private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
boolean checkSecurity,
boolean doRestrict, Class<?> callerClass) throws IllegalAccessException { boolean doRestrict, Class<?> callerClass) throws IllegalAccessException {
checkMethod(refKind, refc, method); checkMethod(refKind, refc, method);
// Optionally check with the security manager; this isn't needed for unreflect* calls.
if (checkSecurity)
checkSecurityManager(refc, method);
assert(!method.isMethodHandleInvoke()); assert(!method.isMethodHandleInvoke());
Class<?> refcAsSuper; Class<?> refcAsSuper;
...@@ -1482,7 +1527,11 @@ return mh1; ...@@ -1482,7 +1527,11 @@ return mh1;
MethodHandle mh = DirectMethodHandle.make(refKind, refc, method); MethodHandle mh = DirectMethodHandle.make(refKind, refc, method);
mh = maybeBindCaller(method, mh, callerClass); mh = maybeBindCaller(method, mh, callerClass);
mh = mh.setVarargs(method); mh = mh.setVarargs(method);
if (doRestrict) // Optionally narrow the receiver argument to refc using restrictReceiver.
if (doRestrict &&
(refKind == REF_invokeSpecial ||
(MethodHandleNatives.refKindHasReceiver(refKind) &&
restrictProtectedReceiver(method))))
mh = restrictReceiver(method, mh, lookupClass()); mh = restrictReceiver(method, mh, lookupClass());
return mh; return mh;
} }
...@@ -1492,14 +1541,29 @@ return mh1; ...@@ -1492,14 +1541,29 @@ return mh1;
if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method)) if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
return mh; return mh;
Class<?> hostClass = lookupClass; Class<?> hostClass = lookupClass;
if ((allowedModes & PRIVATE) == 0) // caller must use full-power lookup if (!hasPrivateAccess()) // caller must have private access
hostClass = callerClass; // callerClass came from a security manager style stack walk hostClass = callerClass; // callerClass came from a security manager style stack walk
MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass); MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass);
// Note: caller will apply varargs after this step happens. // Note: caller will apply varargs after this step happens.
return cbmh; return cbmh;
} }
/** Check access and get the requested field. */
private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException { private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
final boolean checkSecurity = true;
return getDirectFieldCommon(refKind, refc, field, checkSecurity);
}
/** Check access and get the requested field, eliding security manager checks. */
private MethodHandle getDirectFieldNoSecurityManager(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants
return getDirectFieldCommon(refKind, refc, field, checkSecurity);
}
/** Common code for all fields; do not call directly except from immediately above. */
private MethodHandle getDirectFieldCommon(byte refKind, Class<?> refc, MemberName field,
boolean checkSecurity) throws IllegalAccessException {
checkField(refKind, refc, field); checkField(refKind, refc, field);
// Optionally check with the security manager; this isn't needed for unreflect* calls.
if (checkSecurity)
checkSecurityManager(refc, field);
MethodHandle mh = DirectMethodHandle.make(refc, field); MethodHandle mh = DirectMethodHandle.make(refc, field);
boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) && boolean doRestrict = (MethodHandleNatives.refKindHasReceiver(refKind) &&
restrictProtectedReceiver(field)); restrictProtectedReceiver(field));
...@@ -1507,9 +1571,24 @@ return mh1; ...@@ -1507,9 +1571,24 @@ return mh1;
mh = restrictReceiver(field, mh, lookupClass()); mh = restrictReceiver(field, mh, lookupClass());
return mh; return mh;
} }
/** Check access and get the requested constructor. */
private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException { private MethodHandle getDirectConstructor(Class<?> refc, MemberName ctor) throws IllegalAccessException {
final boolean checkSecurity = true;
return getDirectConstructorCommon(refc, ctor, checkSecurity);
}
/** Check access and get the requested constructor, eliding security manager checks. */
private MethodHandle getDirectConstructorNoSecurityManager(Class<?> refc, MemberName ctor) throws IllegalAccessException {
final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants
return getDirectConstructorCommon(refc, ctor, checkSecurity);
}
/** Common code for all constructors; do not call directly except from immediately above. */
private MethodHandle getDirectConstructorCommon(Class<?> refc, MemberName ctor,
boolean checkSecurity) throws IllegalAccessException {
assert(ctor.isConstructor()); assert(ctor.isConstructor());
checkAccess(REF_newInvokeSpecial, refc, ctor); checkAccess(REF_newInvokeSpecial, refc, ctor);
// Optionally check with the security manager; this isn't needed for unreflect* calls.
if (checkSecurity)
checkSecurityManager(refc, ctor);
assert(!MethodHandleNatives.isCallerSensitive(ctor)); // maybeBindCaller not relevant here assert(!MethodHandleNatives.isCallerSensitive(ctor)); // maybeBindCaller not relevant here
return DirectMethodHandle.make(ctor).setVarargs(ctor); return DirectMethodHandle.make(ctor).setVarargs(ctor);
} }
...@@ -1527,7 +1606,7 @@ return mh1; ...@@ -1527,7 +1606,7 @@ return mh1;
return mh; return mh;
} }
MemberName resolved = resolveOrFail(refKind, member); MemberName resolved = resolveOrFail(refKind, member);
mh = getDirectMethodHandle(refKind, defc, resolved); mh = getDirectMethodForConstant(refKind, defc, resolved);
if (mh instanceof DirectMethodHandle if (mh instanceof DirectMethodHandle
&& canBeCached(refKind, defc, resolved)) { && canBeCached(refKind, defc, resolved)) {
MemberName key = mh.internalMemberName(); MemberName key = mh.internalMemberName();
...@@ -1573,13 +1652,14 @@ return mh1; ...@@ -1573,13 +1652,14 @@ return mh1;
return true; return true;
} }
private private
MethodHandle getDirectMethodHandle(byte refKind, Class<?> defc, MemberName member) throws ReflectiveOperationException { MethodHandle getDirectMethodForConstant(byte refKind, Class<?> defc, MemberName member)
throws ReflectiveOperationException {
if (MethodHandleNatives.refKindIsField(refKind)) { if (MethodHandleNatives.refKindIsField(refKind)) {
return getDirectField(refKind, defc, member); return getDirectFieldNoSecurityManager(refKind, defc, member);
} else if (MethodHandleNatives.refKindIsMethod(refKind)) { } else if (MethodHandleNatives.refKindIsMethod(refKind)) {
return getDirectMethod(refKind, defc, member, lookupClass); return getDirectMethodNoSecurityManager(refKind, defc, member, lookupClass);
} else if (refKind == REF_newInvokeSpecial) { } else if (refKind == REF_newInvokeSpecial) {
return getDirectConstructor(defc, member); return getDirectConstructorNoSecurityManager(defc, member);
} }
// oops // oops
throw newIllegalArgumentException("bad MethodHandle constant #"+member); throw newIllegalArgumentException("bad MethodHandle constant #"+member);
......
...@@ -47,7 +47,10 @@ public class TestPrivateMember { ...@@ -47,7 +47,10 @@ public class TestPrivateMember {
MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType mt = MethodType.methodType(void.class); MethodType mt = MethodType.methodType(void.class);
try { try {
MethodHandle mh = lookup.findStatic(Class.class, "checkInitted", mt); Class<?> checkInittedHolder = TestPrivateMemberPackageSibling.class;
// Original model: checkInittedHolder = Class.class;
// Not using Class.checkInitted because it could change without notice.
MethodHandle mh = lookup.findStatic(checkInittedHolder, "checkInitted", mt);
throw new RuntimeException("IllegalAccessException not thrown"); throw new RuntimeException("IllegalAccessException not thrown");
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
// okay // okay
...@@ -55,3 +58,7 @@ public class TestPrivateMember { ...@@ -55,3 +58,7 @@ public class TestPrivateMember {
} }
} }
} }
class TestPrivateMemberPackageSibling {
private static void checkInitted() { }
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册