jdk/src/share/classes/java/lang/reflect/Proxy.java

Print this page
rev 5671 : 7197546: (proxy) Reflect about creating reflective proxies
Reviewed-by: alanb, jdn, jrose

*** 25,43 **** --- 25,49 ---- package java.lang.reflect; import java.lang.ref.Reference; import java.lang.ref.WeakReference; + import java.security.AccessController; + import java.security.Permission; + import java.security.PrivilegedAction; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.List; import java.util.WeakHashMap; import sun.misc.ProxyGenerator; + import sun.reflect.Reflection; + import sun.reflect.misc.ReflectUtil; + import sun.security.util.SecurityConstants; /** * {@code Proxy} provides static methods for creating dynamic proxy * classes and instances, and it is also the superclass of all * dynamic proxy classes created by those methods.
*** 263,275 **** --- 269,341 ---- * for its invocation handler. * * @param h the invocation handler for this proxy instance */ protected Proxy(InvocationHandler h) { + doNewInstanceCheck(); this.h = h; } + private static class ProxyAccessHelper { + // The permission is implementation specific. + static final Permission PROXY_PERMISSION = + new ReflectPermission("proxyConstructorNewInstance"); + // These system properties are defined to provide a short-term + // workaround if customers need to disable the new security checks. + static final boolean allowNewInstance; + static final boolean allowNullLoader; + static { + allowNewInstance = getBooleanProperty("sun.reflect.proxy.allowsNewInstance"); + allowNullLoader = getBooleanProperty("sun.reflect.proxy.allowsNullLoader"); + } + + private static boolean getBooleanProperty(final String key) { + String s = AccessController.doPrivileged(new PrivilegedAction<String>() { + public String run() { + return System.getProperty(key); + } + }); + return Boolean.valueOf(s); + } + + static boolean needsNewInstanceCheck(Class<?> proxyClass) { + if (!Proxy.isProxyClass(proxyClass) || allowNewInstance) { + return false; + } + + if (proxyClass.getName().startsWith(ReflectUtil.PROXY_PACKAGE + ".")) { + // all proxy interfaces are public + return false; + } + for (Class<?> intf : proxyClass.getInterfaces()) { + if (!Modifier.isPublic(intf.getModifiers())) { + return true; + } + } + return false; + } + } + + /* + * Access check on a proxy class that implements any non-public interface. + * + * @throws SecurityException if a security manager exists, and + * the caller does not have the permission. + */ + private void doNewInstanceCheck() { + SecurityManager sm = System.getSecurityManager(); + Class<?> proxyClass = this.getClass(); + if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(proxyClass)) { + try { + sm.checkPermission(ProxyAccessHelper.PROXY_PERMISSION); + } catch (SecurityException e) { + throw new SecurityException("Not allowed to construct a Proxy " + + "instance that implements a non-public interface", e); + } + } + } + /** * Returns the {@code java.lang.Class} object for a proxy class * given a class loader and an array of interfaces. The proxy class * will be defined by the specified class loader and will implement * all of the supplied interfaces. If a proxy class for the same
*** 344,353 **** --- 410,464 ---- */ public static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) throws IllegalArgumentException { + return getProxyClass0(loader, interfaces); // stack walk magic: do not refactor + } + + private static void checkProxyLoader(ClassLoader ccl, + ClassLoader loader) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + if (loader == null && ccl != null) { + if (!ProxyAccessHelper.allowNullLoader) { + sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION); + } + } + } + } + + /* + * Generate a proxy class (caller-sensitive). + * + * To define a proxy class, it performs the access checks as in + * Class.forName (VM will invoke ClassLoader.checkPackageAccess): + * 1. "getClassLoader" permission check if loader == null + * 2. checkPackageAccess on the interfaces it implements + * + * To get a constructor and new instance of a proxy class, it performs + * the package access check on the interfaces it implements + * as in Class.getConstructor. + * + * If an interface is non-public, the proxy class must be defined by + * the defining loader of the interface. If the caller's class loader + * is not the same as the defining loader of the interface, the VM + * will throw IllegalAccessError when the generated proxy class is + * being defined via the defineClass0 method. + */ + private static Class<?> getProxyClass0(ClassLoader loader, + Class<?>... interfaces) { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + final int CALLER_FRAME = 3; // 0: Reflection, 1: getProxyClass0 2: Proxy 3: caller + final Class<?> caller = Reflection.getCallerClass(CALLER_FRAME); + final ClassLoader ccl = caller.getClassLoader(); + checkProxyLoader(ccl, loader); + ReflectUtil.checkProxyPackageAccess(ccl, interfaces); + } + if (interfaces.length > 65535) { throw new IllegalArgumentException("interface limit exceeded"); } Class<?> proxyClass = null;
*** 495,506 **** "non-public interfaces from different packages"); } } } ! if (proxyPkg == null) { // if no non-public proxy interfaces, ! proxyPkg = ""; // use the unnamed package } { /* * Choose a name for the proxy class to generate. --- 606,618 ---- "non-public interfaces from different packages"); } } } ! if (proxyPkg == null) { ! // if no non-public proxy interfaces, use sun.proxy package ! proxyPkg = ReflectUtil.PROXY_PACKAGE + "."; } { /* * Choose a name for the proxy class to generate.
*** 596,621 **** } /* * Look up or generate the designated proxy class. */ ! Class<?> cl = getProxyClass(loader, interfaces); /* * Invoke its constructor with the designated invocation handler. */ try { ! Constructor cons = cl.getConstructor(constructorParams); ! return cons.newInstance(new Object[] { h }); } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); ! } catch (IllegalAccessException e) { ! throw new InternalError(e.toString()); ! } catch (InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { ! throw new InternalError(e.toString()); } } /** * Returns true if and only if the specified class was dynamically --- 708,754 ---- } /* * Look up or generate the designated proxy class. */ ! Class<?> cl = getProxyClass0(loader, interfaces); // stack walk magic: do not refactor /* * Invoke its constructor with the designated invocation handler. */ try { ! final Constructor<?> cons = cl.getConstructor(constructorParams); ! final InvocationHandler ih = h; ! SecurityManager sm = System.getSecurityManager(); ! if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) { ! // create proxy instance with doPrivilege as the proxy class may ! // implement non-public interfaces that requires a special permission ! return AccessController.doPrivileged(new PrivilegedAction<Object>() { ! public Object run() { ! return newInstance(cons, ih); ! } ! }); ! } else { ! return newInstance(cons, ih); ! } } catch (NoSuchMethodException e) { throw new InternalError(e.toString()); ! } ! } ! ! private static Object newInstance(Constructor<?> cons, InvocationHandler h) { ! try { ! return cons.newInstance(new Object[] {h} ); ! } catch (IllegalAccessException | InstantiationException e) { throw new InternalError(e.toString()); } catch (InvocationTargetException e) { ! Throwable t = e.getCause(); ! if (t instanceof RuntimeException) { ! throw (RuntimeException) t; ! } else { ! throw new InternalError(t.toString()); ! } } } /** * Returns true if and only if the specified class was dynamically