mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 23:34:52 +02:00
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
2 changed files with 52 additions and 34 deletions
|
@ -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 {
|
public 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);
|
||||||
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);
|
byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
|
||||||
MemberName method = resolveOrFail(refKind, refc, name, type);
|
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) {
|
private MethodHandle findVirtualForMH(String name, MethodType type) {
|
||||||
// these names require special lookups because of the implicit MethodType argument
|
// 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);
|
checkSpecialCaller(specialCaller, refc);
|
||||||
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);
|
||||||
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 {
|
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);
|
||||||
MethodHandle mh = getDirectMethodNoRestrictInvokeSpecial(refc, method, findBoundCallerClass(method));
|
MethodHandle mh = getDirectMethodNoRestrictInvokeSpecial(refc, method, findBoundCallerLookup(method));
|
||||||
if (!mh.type().leadingReferenceParameter().isAssignableFrom(receiver.getClass())) {
|
if (!mh.type().leadingReferenceParameter().isAssignableFrom(receiver.getClass())) {
|
||||||
throw new IllegalAccessException("The restricted defining class " +
|
throw new IllegalAccessException("The restricted defining class " +
|
||||||
mh.type().leadingReferenceParameter().getName() +
|
mh.type().leadingReferenceParameter().getName() +
|
||||||
|
@ -2486,7 +2486,7 @@ return mh1;
|
||||||
assert(method.isMethod());
|
assert(method.isMethod());
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
|
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) {
|
private MethodHandle unreflectForMH(Method m) {
|
||||||
// these names require special lookups because they throw UnsupportedOperationException
|
// these names require special lookups because they throw UnsupportedOperationException
|
||||||
|
@ -2537,7 +2537,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.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.
|
* If this lookup object has full privilege access, then the caller class is the lookupClass.
|
||||||
* Otherwise, if m is caller-sensitive, throw IllegalAccessException.
|
* Otherwise, if m is caller-sensitive, throw IllegalAccessException.
|
||||||
*/
|
*/
|
||||||
Class<?> findBoundCallerClass(MemberName m) throws IllegalAccessException {
|
Lookup findBoundCallerLookup(MemberName m) throws IllegalAccessException {
|
||||||
Class<?> callerClass = null;
|
if (MethodHandleNatives.isCallerSensitive(m) && !hasFullPrivilegeAccess()) {
|
||||||
if (MethodHandleNatives.isCallerSensitive(m)) {
|
|
||||||
// Only lookups with full privilege access are allowed to resolve caller-sensitive methods
|
// 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 this;
|
||||||
return callerClass;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -3042,28 +3037,28 @@ return mh1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check access and get the requested method. */
|
/** 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 doRestrict = true;
|
||||||
final boolean checkSecurity = 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. */
|
/** 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 doRestrict = false;
|
||||||
final boolean checkSecurity = true;
|
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. */
|
/** 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 doRestrict = true;
|
||||||
final boolean checkSecurity = false; // not needed for reflection or for linking CONSTANT_MH constants
|
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. */
|
/** 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 checkSecurity,
|
||||||
boolean doRestrict, Class<?> boundCallerClass) throws IllegalAccessException {
|
boolean doRestrict,
|
||||||
|
Lookup boundCaller) throws IllegalAccessException {
|
||||||
checkMethod(refKind, refc, method);
|
checkMethod(refKind, refc, method);
|
||||||
// Optionally check with the security manager; this isn't needed for unreflect* calls.
|
// Optionally check with the security manager; this isn't needed for unreflect* calls.
|
||||||
if (checkSecurity)
|
if (checkSecurity)
|
||||||
|
@ -3101,7 +3096,6 @@ return mh1;
|
||||||
// redo basic checks
|
// redo basic checks
|
||||||
checkMethod(refKind, refc, method);
|
checkMethod(refKind, refc, method);
|
||||||
}
|
}
|
||||||
|
|
||||||
DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method, lookupClass());
|
DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method, lookupClass());
|
||||||
MethodHandle mh = dmh;
|
MethodHandle mh = dmh;
|
||||||
// Optionally narrow the receiver argument to lookupClass using restrictReceiver.
|
// Optionally narrow the receiver argument to lookupClass using restrictReceiver.
|
||||||
|
@ -3109,22 +3103,25 @@ return mh1;
|
||||||
(MethodHandleNatives.refKindHasReceiver(refKind) && restrictProtectedReceiver(method))) {
|
(MethodHandleNatives.refKindHasReceiver(refKind) && restrictProtectedReceiver(method))) {
|
||||||
mh = restrictReceiver(method, dmh, lookupClass());
|
mh = restrictReceiver(method, dmh, lookupClass());
|
||||||
}
|
}
|
||||||
mh = maybeBindCaller(method, mh, boundCallerClass);
|
mh = maybeBindCaller(method, mh, boundCaller);
|
||||||
mh = mh.setVarargs(method);
|
mh = mh.setVarargs(method);
|
||||||
return mh;
|
return mh;
|
||||||
}
|
}
|
||||||
private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh,
|
private MethodHandle maybeBindCaller(MemberName method, MethodHandle mh, Lookup boundCaller)
|
||||||
Class<?> boundCallerClass)
|
|
||||||
throws IllegalAccessException {
|
throws IllegalAccessException {
|
||||||
if (allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
|
if (boundCaller.allowedModes == TRUSTED || !MethodHandleNatives.isCallerSensitive(method))
|
||||||
return mh;
|
return mh;
|
||||||
Class<?> hostClass = lookupClass;
|
|
||||||
if (!hasFullPrivilegeAccess()) // caller must have full power access
|
// boundCaller must have full privilege access.
|
||||||
hostClass = boundCallerClass; // boundCallerClass came from a security manager style stack walk
|
// It should have been checked by findBoundCallerLookup. Safe to check this again.
|
||||||
MethodHandle cbmh = MethodHandleImpl.bindCaller(mh, hostClass);
|
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.
|
// Note: caller will apply varargs after this step happens.
|
||||||
return cbmh;
|
return cbmh;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Check access and get the requested field. */
|
/** 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;
|
final boolean checkSecurity = true;
|
||||||
|
@ -3296,7 +3293,7 @@ return mh1;
|
||||||
if (MethodHandleNatives.refKindIsField(refKind)) {
|
if (MethodHandleNatives.refKindIsField(refKind)) {
|
||||||
return getDirectFieldNoSecurityManager(refKind, defc, member);
|
return getDirectFieldNoSecurityManager(refKind, defc, member);
|
||||||
} else if (MethodHandleNatives.refKindIsMethod(refKind)) {
|
} else if (MethodHandleNatives.refKindIsMethod(refKind)) {
|
||||||
return getDirectMethodNoSecurityManager(refKind, defc, member, lookupClass);
|
return getDirectMethodNoSecurityManager(refKind, defc, member, findBoundCallerLookup(member));
|
||||||
} else if (refKind == REF_newInvokeSpecial) {
|
} else if (refKind == REF_newInvokeSpecial) {
|
||||||
return getDirectConstructorNoSecurityManager(defc, member);
|
return getDirectConstructorNoSecurityManager(defc, member);
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* @test
|
/* @test
|
||||||
* @bug 8196830
|
* @bug 8196830 8235351
|
||||||
* @modules java.base/jdk.internal.reflect
|
* @modules java.base/jdk.internal.reflect
|
||||||
* @run testng/othervm --illegal-access=deny CallerSensitiveAccess
|
* @run testng/othervm --illegal-access=deny CallerSensitiveAccess
|
||||||
* @summary Check Lookup findVirtual, findStatic and unreflect behavior with
|
* @summary Check Lookup findVirtual, findStatic and unreflect behavior with
|
||||||
|
@ -95,6 +95,27 @@ public class CallerSensitiveAccess {
|
||||||
MethodHandles.publicLookup().unreflect(method);
|
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 --
|
// -- Test method handles to setAccessible --
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue