8180024: Improve construction of objects during deserialization
Reviewed-by: dfuchs
diff --git a/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java b/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java
index 185f40c..cd1d5bd 100644
--- a/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java
+++ b/corba/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java
@@ -31,13 +31,17 @@
package com.sun.corba.se.impl.io;
+import java.security.AccessControlContext;
+import java.security.AccessController;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.DigestOutputStream;
-import java.security.AccessController;
+import java.security.PermissionCollection;
+import java.security.Permissions;
import java.security.PrivilegedExceptionAction;
import java.security.PrivilegedActionException;
import java.security.PrivilegedAction;
+import java.security.ProtectionDomain;
import java.lang.reflect.Modifier;
import java.lang.reflect.Array;
@@ -47,6 +51,7 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.UndeclaredThrowableException;
import java.io.IOException;
import java.io.DataOutputStream;
@@ -57,6 +62,11 @@
import java.util.Arrays;
import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Set;
+
+import sun.misc.JavaSecurityAccess;
+import sun.misc.SharedSecrets;
import com.sun.corba.se.impl.util.RepositoryId;
@@ -418,6 +428,65 @@
private static final PersistentFieldsValue persistentFieldsValue =
new PersistentFieldsValue();
+ /**
+ * Creates a PermissionDomain that grants no permission.
+ */
+ private ProtectionDomain noPermissionsDomain() {
+ PermissionCollection perms = new Permissions();
+ perms.setReadOnly();
+ return new ProtectionDomain(null, perms);
+ }
+
+ /**
+ * Aggregate the ProtectionDomains of all the classes that separate
+ * a concrete class {@code cl} from its ancestor's class declaring
+ * a constructor {@code cons}.
+ *
+ * If {@code cl} is defined by the boot loader, or the constructor
+ * {@code cons} is declared by {@code cl}, or if there is no security
+ * manager, then this method does nothing and {@code null} is returned.
+ *
+ * @param cons A constructor declared by {@code cl} or one of its
+ * ancestors.
+ * @param cl A concrete class, which is either the class declaring
+ * the constructor {@code cons}, or a serializable subclass
+ * of that class.
+ * @return An array of ProtectionDomain representing the set of
+ * ProtectionDomain that separate the concrete class {@code cl}
+ * from its ancestor's declaring {@code cons}, or {@code null}.
+ */
+ private ProtectionDomain[] getProtectionDomains(Constructor<?> cons,
+ Class<?> cl) {
+ ProtectionDomain[] domains = null;
+ if (cons != null && cl.getClassLoader() != null
+ && System.getSecurityManager() != null) {
+ Class<?> cls = cl;
+ Class<?> fnscl = cons.getDeclaringClass();
+ Set<ProtectionDomain> pds = null;
+ while (cls != fnscl) {
+ ProtectionDomain pd = cls.getProtectionDomain();
+ if (pd != null) {
+ if (pds == null) pds = new HashSet<>();
+ pds.add(pd);
+ }
+ cls = cls.getSuperclass();
+ if (cls == null) {
+ // that's not supposed to happen
+ // make a ProtectionDomain with no permission.
+ // should we throw instead?
+ if (pds == null) pds = new HashSet<>();
+ else pds.clear();
+ pds.add(noPermissionsDomain());
+ break;
+ }
+ }
+ if (pds != null) {
+ domains = pds.toArray(new ProtectionDomain[0]);
+ }
+ }
+ return domains;
+ }
+
/*
* Initialize class descriptor. This method is only invoked on class
* descriptors created via calls to lookupInternal(). This method is kept
@@ -551,11 +620,15 @@
readResolveObjectMethod = ObjectStreamClass.getInheritableMethod(cl,
"readResolve", noTypesList, Object.class);
+ domains = new ProtectionDomain[] {noPermissionsDomain()};
+
if (externalizable)
cons = getExternalizableConstructor(cl) ;
else
cons = getSerializableConstructor(cl) ;
+ domains = getProtectionDomains(cons, cl);
+
if (serializable && !forProxyClass) {
/* Look for the writeObject method
* Set the accessible flag on it here. ObjectOutputStream
@@ -902,20 +975,53 @@
throws InstantiationException, InvocationTargetException,
UnsupportedOperationException
{
+ if (!initialized)
+ throw new InternalError("Unexpected call when not initialized");
if (cons != null) {
try {
- return cons.newInstance(new Object[0]);
+ if (domains == null || domains.length == 0) {
+ return cons.newInstance();
+ } else {
+ JavaSecurityAccess jsa = SharedSecrets.getJavaSecurityAccess();
+ PrivilegedAction<?> pea = (PrivilegedAction<?>) new PrivilegedAction() {
+ public Object run() {
+ try {
+ return cons.newInstance();
+ } catch (InstantiationException
+ | InvocationTargetException
+ | IllegalAccessException x) {
+ throw new UndeclaredThrowableException(x);
+ }
+ }
+ }; // Can't use PrivilegedExceptionAction with jsa
+ try {
+ return jsa.doIntersectionPrivilege(pea,
+ AccessController.getContext(),
+ new AccessControlContext(domains));
+ } catch (UndeclaredThrowableException x) {
+ Throwable cause = x.getCause();
+ if (cause instanceof InstantiationException)
+ throw (InstantiationException) cause;
+ if (cause instanceof InvocationTargetException)
+ throw (InvocationTargetException) cause;
+ if (cause instanceof IllegalAccessException)
+ throw (IllegalAccessException) cause;
+ // not supposed to happen
+ throw x;
+ }
+ }
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
InternalError ie = new InternalError();
- ie.initCause( ex ) ;
- throw ie ;
+ ie.initCause(ex);
+ throw ie;
}
} else {
throw new UnsupportedOperationException();
}
}
+
/**
* Returns public no-arg constructor of given class, or null if none found.
* Access checks are disabled on the returned constructor (if any), since
@@ -1526,7 +1632,8 @@
Method readObjectMethod;
private transient Method writeReplaceObjectMethod;
private transient Method readResolveObjectMethod;
- private Constructor cons ;
+ private Constructor<?> cons;
+ private transient ProtectionDomain[] domains;
/**
* Beginning in Java to IDL ptc/02-01-12, RMI-IIOP has a