8009424: Restrict publicLookup with additional checks
Reviewed-by: vlivanov, jdn
This commit is contained in:
parent
a638aed2e1
commit
94bc7320f8
@ -31,11 +31,13 @@ import java.security.PrivilegedAction;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
import sun.invoke.util.ValueConversions;
|
||||
import sun.invoke.util.VerifyAccess;
|
||||
import sun.invoke.util.Wrapper;
|
||||
import sun.reflect.CallerSensitive;
|
||||
import sun.reflect.Reflection;
|
||||
import sun.reflect.misc.ReflectUtil;
|
||||
import sun.security.util.SecurityConstants;
|
||||
import static java.lang.invoke.MethodHandleStatics.*;
|
||||
import static java.lang.invoke.MethodHandleNatives.Constants.*;
|
||||
@ -578,14 +580,11 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public
|
||||
MethodHandle findStatic(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
|
||||
MemberName method = resolveOrFail(REF_invokeStatic, refc, name, type);
|
||||
Class<?> callerClass = Reflection.getCallerClass();
|
||||
checkSecurityManager(refc, method, callerClass);
|
||||
return getDirectMethod(REF_invokeStatic, refc, method,
|
||||
findBoundCallerClass(method, callerClass));
|
||||
checkSecurityManager(refc, method);
|
||||
return getDirectMethod(REF_invokeStatic, refc, method, findBoundCallerClass(method));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -631,7 +630,6 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findVirtual(Class<?> refc, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
|
||||
if (refc == MethodHandle.class) {
|
||||
MethodHandle mh = findVirtualForMH(name, type);
|
||||
@ -639,10 +637,8 @@ public class MethodHandles {
|
||||
}
|
||||
byte refKind = (refc.isInterface() ? REF_invokeInterface : REF_invokeVirtual);
|
||||
MemberName method = resolveOrFail(refKind, refc, name, type);
|
||||
Class<?> callerClass = Reflection.getCallerClass();
|
||||
checkSecurityManager(refc, method, callerClass);
|
||||
return getDirectMethod(refKind, refc, method,
|
||||
findBoundCallerClass(method, callerClass));
|
||||
checkSecurityManager(refc, method);
|
||||
return getDirectMethod(refKind, refc, method, findBoundCallerClass(method));
|
||||
}
|
||||
private MethodHandle findVirtualForMH(String name, MethodType type) {
|
||||
// these names require special lookups because of the implicit MethodType argument
|
||||
@ -679,11 +675,10 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findConstructor(Class<?> refc, MethodType type) throws NoSuchMethodException, IllegalAccessException {
|
||||
String name = "<init>";
|
||||
MemberName ctor = resolveOrFail(REF_newInvokeSpecial, refc, name, type);
|
||||
checkSecurityManager(refc, ctor, Reflection.getCallerClass());
|
||||
checkSecurityManager(refc, ctor);
|
||||
return getDirectConstructor(refc, ctor);
|
||||
}
|
||||
|
||||
@ -721,16 +716,13 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findSpecial(Class<?> refc, String name, MethodType type,
|
||||
Class<?> specialCaller) throws NoSuchMethodException, IllegalAccessException {
|
||||
checkSpecialCaller(specialCaller);
|
||||
Lookup specialLookup = this.in(specialCaller);
|
||||
MemberName method = specialLookup.resolveOrFail(REF_invokeSpecial, refc, name, type);
|
||||
Class<?> callerClass = Reflection.getCallerClass();
|
||||
checkSecurityManager(refc, method, callerClass);
|
||||
return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method,
|
||||
findBoundCallerClass(method, callerClass));
|
||||
checkSecurityManager(refc, method);
|
||||
return specialLookup.getDirectMethod(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -750,10 +742,9 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
|
||||
MemberName field = resolveOrFail(REF_getField, refc, name, type);
|
||||
checkSecurityManager(refc, field, Reflection.getCallerClass());
|
||||
checkSecurityManager(refc, field);
|
||||
return getDirectField(REF_getField, refc, field);
|
||||
}
|
||||
|
||||
@ -774,10 +765,9 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
|
||||
MemberName field = resolveOrFail(REF_putField, refc, name, type);
|
||||
checkSecurityManager(refc, field, Reflection.getCallerClass());
|
||||
checkSecurityManager(refc, field);
|
||||
return getDirectField(REF_putField, refc, field);
|
||||
}
|
||||
|
||||
@ -797,10 +787,9 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findStaticGetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
|
||||
MemberName field = resolveOrFail(REF_getStatic, refc, name, type);
|
||||
checkSecurityManager(refc, field, Reflection.getCallerClass());
|
||||
checkSecurityManager(refc, field);
|
||||
return getDirectField(REF_getStatic, refc, field);
|
||||
}
|
||||
|
||||
@ -820,10 +809,9 @@ public class MethodHandles {
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle findStaticSetter(Class<?> refc, String name, Class<?> type) throws NoSuchFieldException, IllegalAccessException {
|
||||
MemberName field = resolveOrFail(REF_putStatic, refc, name, type);
|
||||
checkSecurityManager(refc, field, Reflection.getCallerClass());
|
||||
checkSecurityManager(refc, field);
|
||||
return getDirectField(REF_putStatic, refc, field);
|
||||
}
|
||||
|
||||
@ -873,14 +861,11 @@ return mh1;
|
||||
* <a href="MethodHandles.Lookup.html#secmgr">refuses access</a>
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
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);
|
||||
Class<?> callerClass = Reflection.getCallerClass();
|
||||
checkSecurityManager(refc, method, callerClass);
|
||||
MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method,
|
||||
findBoundCallerClass(method, callerClass));
|
||||
checkSecurityManager(refc, method);
|
||||
MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
|
||||
return mh.bindReceiver(receiver).setVarargs(method);
|
||||
}
|
||||
|
||||
@ -905,16 +890,14 @@ return mh1;
|
||||
* is set and {@code asVarargsCollector} fails
|
||||
* @throws NullPointerException if the argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle unreflect(Method m) throws IllegalAccessException {
|
||||
MemberName method = new MemberName(m);
|
||||
byte refKind = method.getReferenceKind();
|
||||
if (refKind == REF_invokeSpecial)
|
||||
refKind = REF_invokeVirtual;
|
||||
assert(method.isMethod());
|
||||
Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
|
||||
Lookup lookup = m.isAccessible() ? IMPL_LOOKUP : this;
|
||||
return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, callerClass);
|
||||
return lookup.getDirectMethod(refKind, method.getDeclaringClass(), method, findBoundCallerClass(method));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -938,15 +921,13 @@ return mh1;
|
||||
* is set and {@code asVarargsCollector} fails
|
||||
* @throws NullPointerException if any argument is null
|
||||
*/
|
||||
@CallerSensitive
|
||||
public MethodHandle unreflectSpecial(Method m, Class<?> specialCaller) throws IllegalAccessException {
|
||||
checkSpecialCaller(specialCaller);
|
||||
Lookup specialLookup = this.in(specialCaller);
|
||||
MemberName method = new MemberName(m, true);
|
||||
assert(method.isMethod());
|
||||
Class<?> callerClass = findBoundCallerClass(method, Reflection.getCallerClass());
|
||||
// ignore m.isAccessible: this is a new kind of access
|
||||
return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, callerClass);
|
||||
return specialLookup.getDirectMethod(REF_invokeSpecial, method.getDeclaringClass(), method, findBoundCallerClass(method));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1047,21 +1028,25 @@ return mh1;
|
||||
/**
|
||||
* Find my trustable caller class if m is a caller sensitive method.
|
||||
* If this lookup object has private access, then the caller class is the lookupClass.
|
||||
* Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
|
||||
* This is the same caller class as is used by checkSecurityManager.
|
||||
* Otherwise, if m is caller-sensitive, throw IllegalAccessException.
|
||||
*/
|
||||
Class<?> findBoundCallerClass(MemberName m, Class<?> callerAtEntryPoint) {
|
||||
Class<?> findBoundCallerClass(MemberName m) throws IllegalAccessException {
|
||||
Class<?> callerClass = null;
|
||||
if (MethodHandleNatives.isCallerSensitive(m)) {
|
||||
// Do not refactor this to a more "logical" place, since it is stack walk magic.
|
||||
// Note that this is the same expression as in Step 2 below in checkSecurityManager.
|
||||
callerClass = ((allowedModes & PRIVATE) != 0
|
||||
? lookupClass // for strong access modes, no extra check
|
||||
: callerAtEntryPoint);
|
||||
// Only full-power lookup is allowed to resolve caller-sensitive methods
|
||||
if (isFullPowerLookup()) {
|
||||
callerClass = lookupClass;
|
||||
} else {
|
||||
throw new IllegalAccessException("Attempt to lookup caller-sensitive method using restricted lookup object");
|
||||
}
|
||||
}
|
||||
return callerClass;
|
||||
}
|
||||
|
||||
private boolean isFullPowerLookup() {
|
||||
return (allowedModes & PRIVATE) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether a security manager has an overridden
|
||||
* SecurityManager.checkMemberAccess method.
|
||||
@ -1082,10 +1067,8 @@ return mh1;
|
||||
* Perform necessary <a href="MethodHandles.Lookup.html#secmgr">access checks</a>.
|
||||
* Determines a trustable caller class to compare with refc, the symbolic reference class.
|
||||
* If this lookup object has private access, then the caller class is the lookupClass.
|
||||
* Otherwise, it is the caller of the currently executing public API method (e.g., findVirtual).
|
||||
* This function performs stack walk magic: do not refactor it.
|
||||
*/
|
||||
void checkSecurityManager(Class<?> refc, MemberName m, Class<?> caller) {
|
||||
void checkSecurityManager(Class<?> refc, MemberName m) {
|
||||
SecurityManager smgr = System.getSecurityManager();
|
||||
if (smgr == null) return;
|
||||
if (allowedModes == TRUSTED) return;
|
||||
@ -1105,13 +1088,10 @@ return mh1;
|
||||
}
|
||||
|
||||
// Step 2:
|
||||
Class<?> callerClass = ((allowedModes & PRIVATE) != 0
|
||||
? lookupClass // for strong access modes, no extra check
|
||||
: caller);
|
||||
if (!VerifyAccess.classLoaderIsAncestor(lookupClass, refc) ||
|
||||
(callerClass != lookupClass &&
|
||||
!VerifyAccess.classLoaderIsAncestor(callerClass, refc)))
|
||||
smgr.checkPackageAccess(VerifyAccess.getPackageName(refc));
|
||||
if (!isFullPowerLookup() ||
|
||||
!VerifyAccess.classLoaderIsAncestor(lookupClass, refc)) {
|
||||
ReflectUtil.checkPackageAccess(refc);
|
||||
}
|
||||
|
||||
// Step 3:
|
||||
if (m.isPublic()) return;
|
||||
@ -1121,7 +1101,7 @@ return mh1;
|
||||
final int which = Member.DECLARED;
|
||||
final Class<?> clazz = defc;
|
||||
if (!overridden) {
|
||||
if (caller.getClassLoader() != clazz.getClassLoader()) {
|
||||
if (!isFullPowerLookup()) {
|
||||
smgr.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION);
|
||||
}
|
||||
} else {
|
||||
@ -1132,8 +1112,9 @@ return mh1;
|
||||
}
|
||||
|
||||
// Step 4:
|
||||
if (defc != refc)
|
||||
smgr.checkPackageAccess(VerifyAccess.getPackageName(defc));
|
||||
if (defc != refc) {
|
||||
ReflectUtil.checkPackageAccess(defc);
|
||||
}
|
||||
}
|
||||
|
||||
void checkMethod(byte refKind, Class<?> refc, MemberName m) throws IllegalAccessException {
|
||||
|
Loading…
Reference in New Issue
Block a user