src/share/classes/java/lang/reflect/Proxy.java
Print this page
*** 26,36 ****
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;
--- 26,35 ----
*** 51,70 ****
* dynamic proxy classes created by those methods.
*
* <p>To create a proxy for some interface {@code Foo}:
* <pre>
* InvocationHandler handler = new MyInvocationHandler(...);
! * Class proxyClass = Proxy.getProxyClass(
! * Foo.class.getClassLoader(), new Class[] { Foo.class });
! * Foo f = (Foo) proxyClass.
! * getConstructor(new Class[] { InvocationHandler.class }).
! * newInstance(new Object[] { handler });
* </pre>
* or more simply:
* <pre>
* Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
! * new Class[] { Foo.class },
* handler);
* </pre>
*
* <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
* class</i> below) is a class that implements a list of interfaces
--- 50,67 ----
* dynamic proxy classes created by those methods.
*
* <p>To create a proxy for some interface {@code Foo}:
* <pre>
* InvocationHandler handler = new MyInvocationHandler(...);
! * Class<?> proxyClass = Proxy.getProxyClass(Foo.class.getClassLoader(), Foo.class);
! * Foo f = (Foo) proxyClass.getConstructor(InvocationHandler.class).
! * newInstance(handler);
* </pre>
* or more simply:
* <pre>
* Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
! * new Class<?>[] { Foo.class },
* handler);
* </pre>
*
* <p>A <i>dynamic proxy class</i> (simply referred to as a <i>proxy
* class</i> below) is a class that implements a list of interfaces
*** 89,99 ****
* the proxy instance.
*
* <p>A proxy class has the following properties:
*
* <ul>
! * <li>Proxy classes are public, final, and not abstract.
*
* <li>The unqualified name of a proxy class is unspecified. The space
* of class names that begin with the string {@code "$Proxy"}
* should be, however, reserved for proxy classes.
*
--- 86,100 ----
* the proxy instance.
*
* <p>A proxy class has the following properties:
*
* <ul>
! * <li>Proxy classes are <em>public, final, and not abstract</em> if
! * all proxy interfaces are public.</li>
! *
! * <li>Proxy classes are <em>non-public, final, and not abstract</em> if
! * any of the proxy interfaces is non-public.</li>
*
* <li>The unqualified name of a proxy class is unspecified. The space
* of class names that begin with the string {@code "$Proxy"}
* should be, however, reserved for proxy classes.
*
*** 271,350 ****
* 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
! * permutation of interfaces has already been defined by the class
! * loader, then the existing proxy class will be returned; otherwise,
* a proxy class for those interfaces will be generated dynamically
* and defined by the class loader.
*
* <p>There are several restrictions on the parameters that may be
* passed to {@code Proxy.getProxyClass}:
--- 272,292 ----
* for its invocation handler.
*
* @param h the invocation handler for this proxy instance
*/
protected Proxy(InvocationHandler h) {
this.h = h;
}
/**
* 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 any of the given interfaces
! * is non-public, the proxy class will be non-public. If a proxy class
! * for the same permutation of interfaces has already been defined by the
! * class loader, then the existing proxy class will be returned; otherwise,
* a proxy class for those interfaces will be generated dynamically
* and defined by the class loader.
*
* <p>There are several restrictions on the parameters that may be
* passed to {@code Proxy.getProxyClass}:
*** 405,414 ****
--- 347,372 ----
* @return a proxy class that is defined in the specified class loader
* and that implements the specified interfaces
* @throws IllegalArgumentException if any of the restrictions on the
* parameters that may be passed to {@code getProxyClass}
* are violated
+ * @throws SecurityException if a security manager, <em>s</em>, is present
+ * and any of the following conditions is met:
+ * <ul>
+ * <li> the given {@code loader} is {@code null} and
+ * the caller's class loader is not {@code null} and the
+ * invocation of {@link SecurityManager#checkPermission
+ * s.checkPermission} with
+ * {@code RuntimePermission("getClassLoader")} permission
+ * denies access.</li>
+ * <li> the caller's class loader is not the same as or an
+ * ancestor of the class loader for the current class and
+ * invocation of {@link SecurityManager#checkPackageAccess
+ * s.checkPackageAccess()} denies access to any one of the
+ * given proxy interfaces.</li>
+ * </ul>
+
* @throws NullPointerException if the {@code interfaces} array
* argument or any of its elements are {@code null}
*/
@CallerSensitive
public static Class<?> getProxyClass(ClassLoader loader,
*** 447,460 ****
{
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
ClassLoader ccl = caller.getClassLoader();
if (VM.isSystemDomainLoader(loader) && !VM.isSystemDomainLoader(ccl)) {
- if (!ProxyAccessHelper.allowNullLoader) {
sm.checkPermission(SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
- }
ReflectUtil.checkProxyPackageAccess(ccl, interfaces);
}
}
/**
--- 405,416 ----
*** 591,609 ****
--- 547,567 ----
} while (true);
}
try {
String proxyPkg = null; // package to define proxy class in
+ int accessFlags = Modifier.PUBLIC | Modifier.FINAL;
/*
* Record the package of a non-public proxy interface so that the
* proxy class will be defined in the same package. Verify that
* all non-public proxy interfaces are in the same package.
*/
for (int i = 0; i < interfaces.length; i++) {
int flags = interfaces[i].getModifiers();
if (!Modifier.isPublic(flags)) {
+ accessFlags = Modifier.FINAL;
String name = interfaces[i].getName();
int n = name.lastIndexOf('.');
String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
if (proxyPkg == null) {
proxyPkg = pkg;
*** 635,645 ****
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
! proxyName, interfaces);
try {
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
--- 593,603 ----
/*
* Generate the specified proxy class.
*/
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
! proxyName, interfaces, accessFlags);
try {
proxyClass = defineClass0(loader, proxyName,
proxyClassFile, 0, proxyClassFile.length);
} catch (ClassFormatError e) {
/*
*** 676,691 ****
}
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
! * handler. This method is equivalent to:
! * <pre>
! * Proxy.getProxyClass(loader, interfaces).
! * getConstructor(new Class[] { InvocationHandler.class }).
! * newInstance(new Object[] { handler });
! * </pre>
*
* <p>{@code Proxy.newProxyInstance} throws
* {@code IllegalArgumentException} for the same reasons that
* {@code Proxy.getProxyClass} does.
*
--- 634,644 ----
}
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
! * handler.
*
* <p>{@code Proxy.newProxyInstance} throws
* {@code IllegalArgumentException} for the same reasons that
* {@code Proxy.getProxyClass} does.
*
*** 697,706 ****
--- 650,680 ----
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
* @throws IllegalArgumentException if any of the restrictions on the
* parameters that may be passed to {@code getProxyClass}
* are violated
+ * @throws SecurityException if a security manager, <em>s</em>, is present
+ * and any of the following conditions is met:
+ * <ul>
+ * <li> the given {@code loader} is {@code null} and
+ * the caller's class loader is not {@code null} and the
+ * invocation of {@link SecurityManager#checkPermission
+ * s.checkPermission} with
+ * {@code RuntimePermission("getClassLoader")} permission
+ * denies access;</li>
+ * <li> the caller's class loader is not the same as or an
+ * ancestor of the class loader for the current class and
+ * invocation of {@link SecurityManager#checkPackageAccess
+ * s.checkPackageAccess()} denies access to any one of the
+ * given proxy interfaces.</li>
+ * <li> any of the given proxy interfaces is non-public and the
+ * caller class is not in the same {@linkplain Package runtime package}
+ * as the non-public interface and the invocation of
+ * {@link SecurityManager#checkPermission s.checkPermission} with
+ * {@code ReflectPermission("newProxyInPackage.{package name}")}
+ * permission denies access.</li>
+ * </ul>
* @throws NullPointerException if the {@code interfaces} array
* argument or any of its elements are {@code null}, or
* if the invocation handler, {@code h}, is
* {@code null}
*/
*** 726,753 ****
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
! 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(), e);
}
}
private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
try {
return cons.newInstance(new Object[] {h} );
} catch (IllegalAccessException | InstantiationException e) {
throw new InternalError(e.toString(), e);
--- 700,764 ----
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
+ if (sm != null) {
+ checkNewProxyPermission(Reflection.getCallerClass(), cl);
+ }
+
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
! if (!Modifier.isPublic(cl.getModifiers())) {
! AccessController.doPrivileged(new PrivilegedAction<Void>() {
! public Void run() {
! cons.setAccessible(true);
! return null;
}
});
+ }
+ return cons.newInstance(new Object[]{h});
+ } catch (IllegalAccessException|InstantiationException e) {
+ throw new InternalError(e.toString(), e);
+ } catch (InvocationTargetException e) {
+ Throwable t = e.getCause();
+ if (t instanceof RuntimeException) {
+ throw (RuntimeException) t;
} else {
! throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
+ private static void checkNewProxyPermission(Class<?> caller, Class<?> proxyClass) {
+ SecurityManager sm = System.getSecurityManager();
+ if (sm != null) {
+ String pcn = proxyClass.getName();
+ if (pcn.startsWith(ReflectUtil.PROXY_PACKAGE + ".")) {
+ // all proxy interfaces are public
+ return;
+ }
+
+ ClassLoader ccl = caller.getClassLoader();
+ ClassLoader pcl = proxyClass.getClassLoader();
+
+ // do permission check if the caller is in a different runtime package
+ // of the proxy class
+ int n = pcn.lastIndexOf('.');
+ String pkg = (n == -1) ? "" : pcn.substring(0, n);
+
+ n = caller.getName().lastIndexOf('.');
+ String callerPkg = (n == -1) ? "" : caller.getName().substring(0, n);
+
+ if (pcl != ccl || !pkg.equals(callerPkg)) {
+ sm.checkPermission(new ReflectPermission("newProxyInPackage." + pkg));
+ }
+ }
+ }
+
private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
try {
return cons.newInstance(new Object[] {h} );
} catch (IllegalAccessException | InstantiationException e) {
throw new InternalError(e.toString(), e);