提交 ea46548c 编写于 作者: A asaha

Merge

......@@ -553,6 +553,12 @@ ecf980386508e3c74319172e2da9ffedacbb42e2 jdk8u75-b08
e6f4eb91a1fa895c2f4520e4cca0ae6f2ca14fbb jdk8u75-b09
93ea7fd6a5a26940d5a2b020c4e9012a85685a5a jdk8u75-b10
748ca164767d268e1739748f4df02b623397446c jdk8u75-b12
02e1209648050922a5a9f2789d9d359795f6f834 jdk8u77-b00
f08584a0fde9344b0aa4766984266ca68b9a5018 jdk8u77-b01
1a3e81c05703bb36def80a57681e1692c866f621 jdk8u77-b02
c44179bce874a97e93ffd7b76a226af417e017a4 jdk8u77-b03
71f59a00df6c8f3bd5c6d6631a4988a431adab56 jdk8u91-b00
7ade7a1ab10ff893f62cce9440b4a839aa19c250 jdk8u91-b13
39baa472e20c13c0eb1243eb5dce589e82f78143 jdk8u76-b00
6ea3aea950d19d803475b3f4d704a2942e71b302 jdk8u76-b01
4de4cffb5988cd68959ce4bbd14c6d4547078c91 jdk8u76-b02
......
......@@ -653,6 +653,9 @@ public abstract class ClassLoader {
if (!checkName(name))
throw new NoClassDefFoundError("IllegalName: " + name);
// Note: Checking logic in java.lang.invoke.MemberName.checkForTypeAlias
// relies on the fact that spoofing is impossible if a class has a name
// of the form "java.*"
if ((name != null) && name.startsWith("java.")) {
throw new SecurityException
("Prohibited package name: " +
......
......@@ -783,7 +783,7 @@ import java.util.Objects;
assert(isResolved() == isResolved);
}
void checkForTypeAlias() {
void checkForTypeAlias(Class<?> refc) {
if (isInvocable()) {
MethodType type;
if (this.type instanceof MethodType)
......@@ -791,16 +791,16 @@ import java.util.Objects;
else
this.type = type = getMethodType();
if (type.erase() == type) return;
if (VerifyAccess.isTypeVisible(type, clazz)) return;
throw new LinkageError("bad method type alias: "+type+" not visible from "+clazz);
if (VerifyAccess.isTypeVisible(type, refc)) return;
throw new LinkageError("bad method type alias: "+type+" not visible from "+refc);
} else {
Class<?> type;
if (this.type instanceof Class<?>)
type = (Class<?>) this.type;
else
this.type = type = getFieldType();
if (VerifyAccess.isTypeVisible(type, clazz)) return;
throw new LinkageError("bad field type alias: "+type+" not visible from "+clazz);
if (VerifyAccess.isTypeVisible(type, refc)) return;
throw new LinkageError("bad field type alias: "+type+" not visible from "+refc);
}
}
......@@ -959,10 +959,25 @@ import java.util.Objects;
MemberName m = ref.clone(); // JVM will side-effect the ref
assert(refKind == m.getReferenceKind());
try {
// There are 4 entities in play here:
// * LC: lookupClass
// * REFC: symbolic reference class (MN.clazz before resolution);
// * DEFC: resolved method holder (MN.clazz after resolution);
// * PTYPES: parameter types (MN.type)
//
// What we care about when resolving a MemberName is consistency between DEFC and PTYPES.
// We do type alias (TA) checks on DEFC to ensure that. DEFC is not known until the JVM
// finishes the resolution, so do TA checks right after MHN.resolve() is over.
//
// All parameters passed by a caller are checked against MH type (PTYPES) on every invocation,
// so it is safe to call a MH from any context.
//
// REFC view on PTYPES doesn't matter, since it is used only as a starting point for resolution and doesn't
// participate in method selection.
m = MethodHandleNatives.resolve(m, lookupClass);
m.checkForTypeAlias();
m.checkForTypeAlias(m.getDeclaringClass());
m.resolution = null;
} catch (LinkageError ex) {
} catch (ClassNotFoundException | LinkageError ex) {
// JVM reports that the "bytecode behavior" would get an error
assert(!m.isResolved());
m.resolution = ex;
......
......@@ -45,7 +45,7 @@ class MethodHandleNatives {
static native void init(MemberName self, Object ref);
static native void expand(MemberName self);
static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError;
static native MemberName resolve(MemberName self, Class<?> caller) throws LinkageError, ClassNotFoundException;
static native int getMembers(Class<?> defc, String matchName, String matchSig,
int matchFlags, Class<?> caller, int skip, MemberName[] results);
......
......@@ -185,22 +185,66 @@ public class VerifyAccess {
* @param refc the class attempting to make the reference
*/
public static boolean isTypeVisible(Class<?> type, Class<?> refc) {
if (type == refc) return true; // easy check
if (type == refc) {
return true; // easy check
}
while (type.isArray()) type = type.getComponentType();
if (type.isPrimitive() || type == Object.class) return true;
ClassLoader parent = type.getClassLoader();
if (parent == null) return true;
ClassLoader child = refc.getClassLoader();
if (child == null) return false;
if (parent == child || loadersAreRelated(parent, child, true))
if (type.isPrimitive() || type == Object.class) {
return true;
}
ClassLoader typeLoader = type.getClassLoader();
ClassLoader refcLoader = refc.getClassLoader();
if (typeLoader == refcLoader) {
return true;
}
if (refcLoader == null && typeLoader != null) {
return false;
}
if (typeLoader == null && type.getName().startsWith("java.")) {
// Note: The API for actually loading classes, ClassLoader.defineClass,
// guarantees that classes with names beginning "java." cannot be aliased,
// because class loaders cannot load them directly.
return true;
}
// Do it the hard way: Look up the type name from the refc loader.
//
// Force the refc loader to report and commit to a particular binding for this type name (type.getName()).
//
// In principle, this query might force the loader to load some unrelated class,
// which would cause this query to fail (and the original caller to give up).
// This would be wasted effort, but it is expected to be very rare, occurring
// only when an attacker is attempting to create a type alias.
// In the normal case, one class loader will simply delegate to the other,
// and the same type will be visible through both, with no extra loading.
//
// It is important to go through Class.forName instead of ClassLoader.loadClass
// because Class.forName goes through the JVM system dictionary, which records
// the class lookup once for all. This means that even if a not-well-behaved class loader
// would "change its mind" about the meaning of the name, the Class.forName request
// will use the result cached in the JVM system dictionary. Note that the JVM system dictionary
// will record the first successful result. Unsuccessful results are not stored.
//
// We use doPrivileged in order to allow an unprivileged caller to ask an arbitrary
// class loader about the binding of the proposed name (type.getName()).
// The looked up type ("res") is compared for equality against the proposed
// type ("type") and then is discarded. Thus, the worst that can happen to
// the "child" class loader is that it is bothered to load and report a class
// that differs from "type"; this happens once due to JVM system dictionary
// memoization. And the caller never gets to look at the alternate type binding
// ("res"), whether it exists or not.
final String name = type.getName();
Class<?> res = java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Class>() {
public Class<?> run() {
try {
Class<?> res = child.loadClass(type.getName());
return (type == res);
} catch (ClassNotFoundException ex) {
return false;
return Class.forName(name, false, refcLoader);
} catch (ClassNotFoundException | LinkageError e) {
return null; // Assume the class is not found
}
}
});
return (type == res);
}
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册