8015256: Better class accessibility
Summary: Improve protection domain check in forName()
Reviewed-by: mchung, acorn, jdn
--- a/jdk/src/java.base/share/classes/java/lang/Class.java Thu May 08 21:09:57 2014 +0400
+++ b/jdk/src/java.base/share/classes/java/lang/Class.java Tue Jul 22 16:24:48 2014 +0400
@@ -262,8 +262,8 @@
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
- return forName0(className, true,
- ClassLoader.getClassLoader(Reflection.getCallerClass()));
+ Class<?> caller = Reflection.getCallerClass();
+ return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
@@ -333,22 +333,27 @@
ClassLoader loader)
throws ClassNotFoundException
{
- if (sun.misc.VM.isSystemDomainLoader(loader)) {
- SecurityManager sm = System.getSecurityManager();
- if (sm != null) {
- ClassLoader ccl = ClassLoader.getClassLoader(Reflection.getCallerClass());
+ Class<?> caller = null;
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ // Reflective call to get caller class is only needed if a security manager
+ // is present. Avoid the overhead of making this call otherwise.
+ caller = Reflection.getCallerClass();
+ if (sun.misc.VM.isSystemDomainLoader(loader)) {
+ ClassLoader ccl = ClassLoader.getClassLoader(caller);
if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
- return forName0(name, initialize, loader);
+ return forName0(name, initialize, loader, caller);
}
- /** Called after security checks have been made. */
+ /** Called after security check for system loader access checks have been made. */
private static native Class<?> forName0(String name, boolean initialize,
- ClassLoader loader)
+ ClassLoader loader,
+ Class<?> caller)
throws ClassNotFoundException;
/**
--- a/jdk/src/java.base/share/native/include/jvm.h Thu May 08 21:09:57 2014 +0400
+++ b/jdk/src/java.base/share/native/include/jvm.h Tue Jul 22 16:24:48 2014 +0400
@@ -386,6 +386,19 @@
JVM_FindClassFromBootLoader(JNIEnv *env, const char *name);
/*
+ * Find a class from a given class loader. Throws ClassNotFoundException.
+ * name: name of class
+ * init: whether initialization is done
+ * loader: class loader to look up the class. This may not be the same as the caller's
+ * class loader.
+ * caller: initiating class. The initiating class may be null when a security
+ * manager is not installed.
+ */
+JNIEXPORT jclass JNICALL
+JVM_FindClassFromCaller(JNIEnv *env, const char *name, jboolean init,
+ jobject loader, jclass caller);
+
+/*
* Find a class from a given class loader. Throw ClassNotFoundException
* or NoClassDefFoundError depending on the value of the last
* argument.
--- a/jdk/src/java.base/share/native/libjava/Class.c Thu May 08 21:09:57 2014 +0400
+++ b/jdk/src/java.base/share/native/libjava/Class.c Tue Jul 22 16:24:48 2014 +0400
@@ -93,7 +93,7 @@
JNIEXPORT jclass JNICALL
Java_java_lang_Class_forName0(JNIEnv *env, jclass this, jstring classname,
- jboolean initialize, jobject loader)
+ jboolean initialize, jobject loader, jclass caller)
{
char *clname;
jclass cls = 0;
@@ -131,8 +131,7 @@
goto done;
}
- cls = JVM_FindClassFromClassLoader(env, clname, initialize,
- loader, JNI_FALSE);
+ cls = JVM_FindClassFromCaller(env, clname, initialize, loader, caller);
done:
if (clname != buf) {