< prev index next >
src/share/classes/java/io/ObjectStreamClass.java
Print this page
rev 12542 : 8180024: Improve construction of objects during deserialization
Reviewed-by: dfuchs
*** 30,55 ****
--- 30,62 ----
import java.lang.ref.SoftReference;
import java.lang.ref.WeakReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
+ import java.lang.reflect.UndeclaredThrowableException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Proxy;
+ import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
+ import java.security.PermissionCollection;
+ import java.security.Permissions;
import java.security.PrivilegedAction;
+ import java.security.ProtectionDomain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
+ import sun.misc.JavaSecurityAccess;
+ import sun.misc.SharedSecrets;
import sun.misc.Unsafe;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.reflect.ReflectionFactory;
import sun.reflect.misc.ReflectUtil;
*** 171,180 ****
--- 178,190 ----
/** data layout of serialized objects described by this class desc */
private volatile ClassDataSlot[] dataLayout;
/** serialization-appropriate constructor, or null if none */
private Constructor<?> cons;
+ /** protection domains that need to be checked when calling the constructor */
+ private ProtectionDomain[] domains;
+
/** class-defined writeObject method, or null if none */
private Method writeObjectMethod;
/** class-defined readObject method, or null if none */
private Method readObjectMethod;
/** class-defined readObjectNoData method, or null if none */
*** 503,512 ****
--- 513,523 ----
Void.TYPE);
readObjectNoDataMethod = getPrivateMethod(
cl, "readObjectNoData", null, Void.TYPE);
hasWriteObjectData = (writeObjectMethod != null);
}
+ domains = getProtectionDomains(cons, cl);
writeReplaceMethod = getInheritableMethod(
cl, "writeReplace", null, Object.class);
readResolveMethod = getInheritableMethod(
cl, "readResolve", null, Object.class);
return null;
*** 546,555 ****
--- 557,625 ----
*/
ObjectStreamClass() {
}
/**
+ * 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;
+ }
+
+ /**
* Initializes class descriptor representing a proxy class.
*/
void initProxy(Class<?> cl,
ClassNotFoundException resolveEx,
ObjectStreamClass superDesc)
*** 575,584 ****
--- 645,655 ----
name = localDesc.name;
externalizable = localDesc.externalizable;
writeReplaceMethod = localDesc.writeReplaceMethod;
readResolveMethod = localDesc.readResolveMethod;
deserializeEx = localDesc.deserializeEx;
+ domains = localDesc.domains;
cons = localDesc.cons;
}
fieldRefl = getReflector(fields, localDesc);
initialized = true;
}
*** 661,670 ****
--- 732,742 ----
writeReplaceMethod = localDesc.writeReplaceMethod;
readResolveMethod = localDesc.readResolveMethod;
if (deserializeEx == null) {
deserializeEx = localDesc.deserializeEx;
}
+ domains = localDesc.domains;
cons = localDesc.cons;
}
fieldRefl = getReflector(fields, localDesc);
// reassign to matched fields so as to reflect local unshared settings
*** 1001,1011 ****
--- 1073,1111 ----
UnsupportedOperationException
{
requireInitialized();
if (cons != null) {
try {
+ if (domains == null || domains.length == 0) {
+ return cons.newInstance();
+ } else {
+ JavaSecurityAccess jsa = SharedSecrets.getJavaSecurityAccess();
+ PrivilegedAction<?> pea = () -> {
+ 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
throw new InternalError(ex);
}
} else {
< prev index next >