8011557: Improve reflection utility classes

Reviewed-by: ahgross, alanb
This commit is contained in:
Mandy Chung 2013-04-17 15:04:59 -07:00
parent 8ab5854ca2
commit 3a6de961eb
3 changed files with 62 additions and 21 deletions

View File

@ -2338,7 +2338,7 @@ public final class Class<T> implements java.io.Serializable,
if (i != -1) { if (i != -1) {
// skip the package access check on a proxy class in default proxy package // skip the package access check on a proxy class in default proxy package
String pkg = name.substring(0, i); String pkg = name.substring(0, i);
if (!Proxy.isProxyClass(this) || !pkg.equals(ReflectUtil.PROXY_PACKAGE)) { if (!Proxy.isProxyClass(this) || ReflectUtil.isNonPublicProxyClass(this)) {
s.checkPackageAccess(pkg); s.checkPackageAccess(pkg);
} }
} }

View File

@ -734,25 +734,21 @@ public class Proxy implements java.io.Serializable {
private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass) { private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass) {
SecurityManager sm = System.getSecurityManager(); SecurityManager sm = System.getSecurityManager();
if (sm != null) { if (sm != null) {
String pcn = proxyClass.getName(); if (ReflectUtil.isNonPublicProxyClass(proxyClass)) {
if (pcn.startsWith(ReflectUtil.PROXY_PACKAGE + ".")) { ClassLoader ccl = caller.getClassLoader();
// all proxy interfaces are public ClassLoader pcl = proxyClass.getClassLoader();
return;
}
ClassLoader ccl = caller.getClassLoader(); // do permission check if the caller is in a different runtime package
ClassLoader pcl = proxyClass.getClassLoader(); // of the proxy class
int n = proxyClass.getName().lastIndexOf('.');
String pkg = (n == -1) ? "" : proxyClass.getName().substring(0, n);
// do permission check if the caller is in a different runtime package n = caller.getName().lastIndexOf('.');
// of the proxy class String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
int n = pcn.lastIndexOf('.');
String pkg = (n == -1) ? "" : pcn.substring(0, n);
n = caller.getName().lastIndexOf('.'); if (pcl != ccl || !pkg.equals(callerPkg)) {
String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n); sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
}
if (pcl != ccl || !pkg.equals(callerPkg)) {
sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
} }
} }
} }

View File

@ -27,6 +27,7 @@
package sun.reflect.misc; package sun.reflect.misc;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
import sun.reflect.Reflection; import sun.reflect.Reflection;
public final class ReflectUtil { public final class ReflectUtil {
@ -114,11 +115,26 @@ public final class ReflectUtil {
return false; return false;
} }
/**
* Checks package access on the given class.
*
* If it is a {@link Proxy#isProxyClass(java.lang.Class)} that implements
* a non-public interface (i.e. may be in a non-restricted package),
* also check the package access on the proxy interfaces.
*/
public static void checkPackageAccess(Class<?> clazz) { public static void checkPackageAccess(Class<?> clazz) {
checkPackageAccess(clazz.getName()); checkPackageAccess(clazz.getName());
if (isNonPublicProxyClass(clazz)) {
checkProxyPackageAccess(clazz);
}
} }
/**
* Checks package access on the given classname.
* This method is typically called when the Class instance is not
* available and the caller attempts to load a class on behalf
* the true caller (application).
*/
public static void checkPackageAccess(String name) { public static void checkPackageAccess(String name) {
SecurityManager s = System.getSecurityManager(); SecurityManager s = System.getSecurityManager();
if (s != null) { if (s != null) {
@ -179,14 +195,31 @@ public final class ReflectUtil {
return !isAncestor(from, to); return !isAncestor(from, to);
} }
/**
* Check package access on the proxy interfaces that the given proxy class
* implements.
*
* @param clazz Proxy class object
*/
public static void checkProxyPackageAccess(Class<?> clazz) {
SecurityManager s = System.getSecurityManager();
if (s != null) {
// check proxy interfaces if the given class is a proxy class
if (Proxy.isProxyClass(clazz)) {
for (Class<?> intf : clazz.getInterfaces()) {
checkPackageAccess(intf);
}
}
}
}
/** /**
* Access check on the interfaces that a proxy class implements and throw * Access check on the interfaces that a proxy class implements and throw
* {@code SecurityException} if it accesses a restricted package. * {@code SecurityException} if it accesses a restricted package from
* the caller's class loader.
* *
* @param ccl the caller's class loader * @param ccl the caller's class loader
* @param interfaces the list of interfaces that a proxy class implements * @param interfaces the list of interfaces that a proxy class implements
*
* @see Proxy#checkProxyAccess
*/ */
public static void checkProxyPackageAccess(ClassLoader ccl, public static void checkProxyPackageAccess(ClassLoader ccl,
Class<?>... interfaces) Class<?>... interfaces)
@ -205,4 +238,16 @@ public final class ReflectUtil {
// Note that bytecode instrumentation tools may exclude 'sun.*' // Note that bytecode instrumentation tools may exclude 'sun.*'
// classes but not generated proxy classes and so keep it in com.sun.* // classes but not generated proxy classes and so keep it in com.sun.*
public static final String PROXY_PACKAGE = "com.sun.proxy"; public static final String PROXY_PACKAGE = "com.sun.proxy";
/**
* Test if the given class is a proxy class that implements
* non-public interface. Such proxy class may be in a non-restricted
* package that bypasses checkPackageAccess.
*/
public static boolean isNonPublicProxyClass(Class<?> cls) {
String name = cls.getName();
int i = name.lastIndexOf('.');
String pkg = (i != -1) ? name.substring(0, i) : "";
return Proxy.isProxyClass(cls) && !pkg.equals(PROXY_PACKAGE);
}
} }