8235351: Lookup::unreflect should bind with the original caller independent of Method's accessible flag
Reviewed-by: alanb
This commit is contained in:
parent
41b4803cdf
commit
e7fa637179
src/java.base/share/classes/java/lang/invoke
test/jdk/java/lang/invoke
@ -1789,7 +1789,7 @@ assertEquals("[x, y]", MH_asList.invoke("x", "y").toString());
|
||||
*/
|
||||
public MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
|
||||
MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
|
||||
return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerClass(method));
|
||||
return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerLookup(method));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1881,7 +1881,7 @@ assertEquals("", (String) MH_newString.invokeExact());
|
||||
}
|
||||
byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
|
||||
MemberName method = resolveOrFail(refKind, refc, name, type);
|
||||
return getDirectMethod(refKind, refc, method, findBoundCallerClass(method));
|
||||
return getDirectMethod(refKind, refc, method, findBoundCallerLookup(method));
|
||||
}
|
||||
private MethodHandle findVirtualForMH(String name, MethodType type) {
|
||||
// these names require special lookups because of the implicit MethodType argument
|
||||
@ -2133,7 +2133,7 @@ assertEquals(""+l, (String) MH_this.invokeExact(subl)); // Listie method
|
||||
checkSpecialCaller(specialCaller, refc);
|
||||
Lookup specialLookup = this.in(specialCaller);
|
||||
MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
|
||||
return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
|
||||
return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, findBoundCallerLookup(method));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2434,7 +2434,7 @@ return mh1;
|
||||
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
|
||||
Class<? extends Object> refc = receiver.getClass(); // may get NPE
|
||||
MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
|
||||
MethodHandle mh = getDirectMethodNoRestrictInvokeSpecial(refc, method, findBoundCallerClass(method));
|
||||
MethodHandle mh = getDirectMethodNoRestrictInvokeSpecial(refc, method, findBoundCallerLookup(method));
|
||||
if (!mh.type().leadingReferenceParameter().isAssignableFrom(receiver.getClass())) {
|
||||
throw new IllegalAccessException("The restricted defining class " +
|
||||
mh.type().leadingReferenceParameter().getName() +
|
||||
@ -2486,7 +2486,7 @@ return mh1;
|
||||
assert(method.isMethod());
|
||||
@SuppressWarnings("deprecation")
|
||||
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
|
||||
return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
|
||||
return lookup.getDirectMethodNoSecurityManager(refKind, method.getDeclaringClass(), method, findBoundCallerLookup(method));
|
||||
}
|
||||
private MethodHandle unreflectForMH(Method m) {
|
||||
// these names require special lookups because they throw UnsupportedOperationException
|
||||
@ -2537,7 +2537,7 @@ return mh1;
|
||||
MemberName method = new MemberName(m, true);
|
||||
assert(method.isMethod());
|
||||
// ignore m.isAccessible: this is a new kind of access
|
||||
return specialLookup.getDirectMethodNoSecurityManager(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method));
|
||||
return specialLookup.getDirectMethodNoSecurityManager(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerLookup(method));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2828,17 +2828,12 @@ return mh1;
|
||||
* If this lookup object has full privilege access, then the caller class is the lookupClass.
|
||||
* Otherwise, if m is caller-sensitive, throw IllegalAccessException.
|
||||
*/
|
||||
Class<?> findBoundCallerClass(MemberName m) throws IllegalAccessException {
|
||||
Class<?> callerClass = null;
|
||||
if (MethodHandleNatives.isCallerSensitive(m)) {
|
||||
Lookup findBoundCallerLookup(MemberName m) throws IllegalAccessException {
|
||||
if (MethodHandleNatives.isCallerSensitive(m) && !hasFullPrivilegeAccess()) {
|
||||
// Only lookups with full privilege access are allowed to resolve caller-sensitive methods
|
||||
if (hasFullPrivilegeAccess()) {
|
||||
callerClass = lookupClass;
|
||||
} 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");
|
||||
}
|
||||
return callerClass;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3042,28 +3037,28 @@ return mh1;
|
||||
}
|
||||
|
||||
/** Check access and get the requested method. */
|
||||
private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method, Class<?> boundCallerClass) throws IllegalAccessException {
|
||||
private MethodHandle getDirectMethod(byte refKind, Class<?> refc, MemberName method, Lookup callerLookup) throws IllegalAccessException {
|
||||
final boolean doRestrict = true;
|
||||
final boolean checkSecurity = true;
|
||||
return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, boundCallerClass);
|
||||
return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerLookup);
|
||||
}
|
||||
/** Check access and get the requested method, for invokespecial with no restriction on the application of narrowing rules. */
|
||||
private MethodHandle getDirectMethodNoRestrictInvokeSpecial(Class<?> refc, MemberName method, Class<?> boundCallerClass) throws IllegalAccessException {
|
||||
private MethodHandle getDirectMethodNoRestrictInvokeSpecial(Class<?> refc, MemberName method, Lookup callerLookup) throws IllegalAccessException {
|
||||
final boolean doRestrict = false;
|
||||
final boolean checkSecurity = true;
|
||||
return getDirectMethodCommon(REF_invokeSpecial, refc, method, checkSecurity, doRestrict, boundCallerClass);
|
||||
return getDirectMethodCommon(REF_invokeSpecial, refc, method, checkSecurity, doRestrict, callerLookup);
|
||||
}
|
||||
/** Check access and get the requested method, eliding security manager checks. */
|
||||
private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class<?> refc, MemberName method, Class<?> boundCallerClass) throws IllegalAccessException {
|
||||
private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class<?> refc, MemberName method, Lookup callerLookup) 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, boundCallerClass);
|
||||
return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerLookup);
|
||||
}
|
||||
/** Common code for all methods; do not call directly except from immediately above. */
|
||||
private MethodHandle getDirectMethodCommon(byte refKind, Class<?> refc, MemberName method,
|
||||
boolean checkSecurity,
|
||||
boolean doRestrict, Class<?> boundCallerClass) throws IllegalAccessException {
|
||||
|
||||
boolean doRestrict,
|
||||
Lookup boundCaller) throws IllegalAccessException {
|
||||
checkMethod(refKind, refc, method);
|
||||
// Optionally check with the security manager; this isn't needed for unreflect* calls.
|
||||
if (checkSecurity)
|
||||
@ -3101,7 +3096,6 @@ return mh1;
|
||||
// redo basic checks
|
||||
checkMethod(refKind, refc, method);
|
||||
}
|
||||
|
||||
DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method, lookupClass());
|
||||
MethodHandle mh = dmh;
|
||||
// Optionally narrow the receiver argument to lookupClass using restrictReceiver.
|
||||
@ -3109,22 +3103,25 @@ return mh1;
|
||||
(MethodHandleNatives.refKindHasReceiver(refKind) && restrictProtectedReceiver(method))) {
|
||||
mh = restrictReceiver(method, dmh, lookupClass());
|
||||
}
|
||||
mh = maybeBindCaller(method, mh, boundCallerClass);
|
||||
mh = maybeBindCaller(method, mh, boundCaller);
|
||||
mh = mh.setVarargs(method);
|
||||
return mh;
|
||||
}
|
||||
private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
|
||||
Class<?> boundCallerClass)
|
||||
private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, Lookup boundCaller)
|
||||
throws IllegalAccessException {
|
||||
if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
|
||||
if (boundCaller.allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
|
||||
return mh;
|
||||
Class<?> hostClass = lookupClass;
|
||||
if (!hasFullPrivilegeAccess()) // caller must have full power access
|
||||
hostClass = boundCallerClass; // boundCallerClass came from a security manager style stack walk
|
||||
MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass);
|
||||
|
||||
// boundCaller must have full privilege access.
|
||||
// It should have been checked by findBoundCallerLookup. Safe to check this again.
|
||||
if (!boundCaller.hasFullPrivilegeAccess())
|
||||
throw new IllegalAccessException("Attempt to lookup caller-sensitive method using restricted lookup object");
|
||||
|
||||
MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, boundCaller.lookupClass);
|
||||
// Note: caller will apply varargs after this step happens.
|
||||
return cbmh;
|
||||
}
|
||||
|
||||
/** Check access and get the requested field. */
|
||||
private MethodHandle getDirectField(byte refKind, Class<?> refc, MemberName field) throws IllegalAccessException {
|
||||
final boolean checkSecurity = true;
|
||||
@ -3296,7 +3293,7 @@ return mh1;
|
||||
if (MethodHandleNatives.refKindIsField(refKind)) {
|
||||
return getDirectFieldNoSecurityManager(refKind, defc, member);
|
||||
} else if (MethodHandleNatives.refKindIsMethod(refKind)) {
|
||||
return getDirectMethodNoSecurityManager(refKind, defc, member, lookupClass);
|
||||
return getDirectMethodNoSecurityManager(refKind, defc, member, findBoundCallerLookup(member));
|
||||
} else if (refKind == REF_newInvokeSpecial) {
|
||||
return getDirectConstructorNoSecurityManager(defc, member);
|
||||
}
|
||||
|
@ -22,7 +22,7 @@
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8196830
|
||||
* @bug 8196830 8235351
|
||||
* @modules java.base/jdk.internal.reflect
|
||||
* @run testng/othervm --illegal-access=deny CallerSensitiveAccess
|
||||
* @summary Check Lookup findVirtual, findStatic and unreflect behavior with
|
||||
@ -95,6 +95,27 @@ public class CallerSensitiveAccess {
|
||||
MethodHandles.publicLookup().unreflect(method);
|
||||
}
|
||||
|
||||
/**
|
||||
* public accessible caller sensitive methods in APIs exported by java.base.
|
||||
*/
|
||||
@DataProvider(name = "accessibleCallerSensitiveMethods")
|
||||
static Object[][] accessibleCallerSensitiveMethods() {
|
||||
return callerSensitiveMethods(Object.class.getModule())
|
||||
.filter(m -> Modifier.isPublic(m.getModifiers()))
|
||||
.map(m -> { m.setAccessible(true); return m; })
|
||||
.map(m -> new Object[] { m, shortDescription(m) })
|
||||
.toArray(Object[][]::new);
|
||||
}
|
||||
|
||||
/**
|
||||
* Using publicLookup, attempt to use unreflect to obtain a method handle to a
|
||||
* caller sensitive method.
|
||||
*/
|
||||
@Test(dataProvider = "accessibleCallerSensitiveMethods",
|
||||
expectedExceptions = IllegalAccessException.class)
|
||||
public void testLookupUnreflect(@NoInjection Method method, String desc) throws Exception {
|
||||
MethodHandles.publicLookup().unreflect(method);
|
||||
}
|
||||
|
||||
// -- Test method handles to setAccessible --
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user