Thu, 25 May 2017 12:11:16 -0700
8180024: Improve construction of objects during deserialization
Reviewed-by: dfuchs
src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java Mon Jun 26 14:48:52 2017 -0700 1.2 +++ b/src/share/classes/com/sun/corba/se/impl/io/ObjectStreamClass.java Thu May 25 12:11:16 2017 -0700 1.3 @@ -31,13 +31,17 @@ 1.4 1.5 package com.sun.corba.se.impl.io; 1.6 1.7 +import java.security.AccessControlContext; 1.8 +import java.security.AccessController; 1.9 import java.security.MessageDigest; 1.10 import java.security.NoSuchAlgorithmException; 1.11 import java.security.DigestOutputStream; 1.12 -import java.security.AccessController; 1.13 +import java.security.PermissionCollection; 1.14 +import java.security.Permissions; 1.15 import java.security.PrivilegedExceptionAction; 1.16 import java.security.PrivilegedActionException; 1.17 import java.security.PrivilegedAction; 1.18 +import java.security.ProtectionDomain; 1.19 1.20 import java.lang.reflect.Modifier; 1.21 import java.lang.reflect.Array; 1.22 @@ -47,6 +51,7 @@ 1.23 import java.lang.reflect.Constructor; 1.24 import java.lang.reflect.Proxy; 1.25 import java.lang.reflect.InvocationTargetException; 1.26 +import java.lang.reflect.UndeclaredThrowableException; 1.27 1.28 import java.io.IOException; 1.29 import java.io.DataOutputStream; 1.30 @@ -57,6 +62,11 @@ 1.31 1.32 import java.util.Arrays; 1.33 import java.util.Comparator; 1.34 +import java.util.HashSet; 1.35 +import java.util.Set; 1.36 + 1.37 +import sun.misc.JavaSecurityAccess; 1.38 +import sun.misc.SharedSecrets; 1.39 1.40 import com.sun.corba.se.impl.util.RepositoryId; 1.41 1.42 @@ -418,6 +428,65 @@ 1.43 private static final PersistentFieldsValue persistentFieldsValue = 1.44 new PersistentFieldsValue(); 1.45 1.46 + /** 1.47 + * Creates a PermissionDomain that grants no permission. 1.48 + */ 1.49 + private ProtectionDomain noPermissionsDomain() { 1.50 + PermissionCollection perms = new Permissions(); 1.51 + perms.setReadOnly(); 1.52 + return new ProtectionDomain(null, perms); 1.53 + } 1.54 + 1.55 + /** 1.56 + * Aggregate the ProtectionDomains of all the classes that separate 1.57 + * a concrete class {@code cl} from its ancestor's class declaring 1.58 + * a constructor {@code cons}. 1.59 + * 1.60 + * If {@code cl} is defined by the boot loader, or the constructor 1.61 + * {@code cons} is declared by {@code cl}, or if there is no security 1.62 + * manager, then this method does nothing and {@code null} is returned. 1.63 + * 1.64 + * @param cons A constructor declared by {@code cl} or one of its 1.65 + * ancestors. 1.66 + * @param cl A concrete class, which is either the class declaring 1.67 + * the constructor {@code cons}, or a serializable subclass 1.68 + * of that class. 1.69 + * @return An array of ProtectionDomain representing the set of 1.70 + * ProtectionDomain that separate the concrete class {@code cl} 1.71 + * from its ancestor's declaring {@code cons}, or {@code null}. 1.72 + */ 1.73 + private ProtectionDomain[] getProtectionDomains(Constructor<?> cons, 1.74 + Class<?> cl) { 1.75 + ProtectionDomain[] domains = null; 1.76 + if (cons != null && cl.getClassLoader() != null 1.77 + && System.getSecurityManager() != null) { 1.78 + Class<?> cls = cl; 1.79 + Class<?> fnscl = cons.getDeclaringClass(); 1.80 + Set<ProtectionDomain> pds = null; 1.81 + while (cls != fnscl) { 1.82 + ProtectionDomain pd = cls.getProtectionDomain(); 1.83 + if (pd != null) { 1.84 + if (pds == null) pds = new HashSet<>(); 1.85 + pds.add(pd); 1.86 + } 1.87 + cls = cls.getSuperclass(); 1.88 + if (cls == null) { 1.89 + // that's not supposed to happen 1.90 + // make a ProtectionDomain with no permission. 1.91 + // should we throw instead? 1.92 + if (pds == null) pds = new HashSet<>(); 1.93 + else pds.clear(); 1.94 + pds.add(noPermissionsDomain()); 1.95 + break; 1.96 + } 1.97 + } 1.98 + if (pds != null) { 1.99 + domains = pds.toArray(new ProtectionDomain[0]); 1.100 + } 1.101 + } 1.102 + return domains; 1.103 + } 1.104 + 1.105 /* 1.106 * Initialize class descriptor. This method is only invoked on class 1.107 * descriptors created via calls to lookupInternal(). This method is kept 1.108 @@ -551,11 +620,15 @@ 1.109 readResolveObjectMethod = ObjectStreamClass.getInheritableMethod(cl, 1.110 "readResolve", noTypesList, Object.class); 1.111 1.112 + domains = new ProtectionDomain[] {noPermissionsDomain()}; 1.113 + 1.114 if (externalizable) 1.115 cons = getExternalizableConstructor(cl) ; 1.116 else 1.117 cons = getSerializableConstructor(cl) ; 1.118 1.119 + domains = getProtectionDomains(cons, cl); 1.120 + 1.121 if (serializable && !forProxyClass) { 1.122 /* Look for the writeObject method 1.123 * Set the accessible flag on it here. ObjectOutputStream 1.124 @@ -902,20 +975,53 @@ 1.125 throws InstantiationException, InvocationTargetException, 1.126 UnsupportedOperationException 1.127 { 1.128 + if (!initialized) 1.129 + throw new InternalError("Unexpected call when not initialized"); 1.130 if (cons != null) { 1.131 try { 1.132 - return cons.newInstance(new Object[0]); 1.133 + if (domains == null || domains.length == 0) { 1.134 + return cons.newInstance(); 1.135 + } else { 1.136 + JavaSecurityAccess jsa = SharedSecrets.getJavaSecurityAccess(); 1.137 + PrivilegedAction<?> pea = (PrivilegedAction<?>) new PrivilegedAction() { 1.138 + public Object run() { 1.139 + try { 1.140 + return cons.newInstance(); 1.141 + } catch (InstantiationException 1.142 + | InvocationTargetException 1.143 + | IllegalAccessException x) { 1.144 + throw new UndeclaredThrowableException(x); 1.145 + } 1.146 + } 1.147 + }; // Can't use PrivilegedExceptionAction with jsa 1.148 + try { 1.149 + return jsa.doIntersectionPrivilege(pea, 1.150 + AccessController.getContext(), 1.151 + new AccessControlContext(domains)); 1.152 + } catch (UndeclaredThrowableException x) { 1.153 + Throwable cause = x.getCause(); 1.154 + if (cause instanceof InstantiationException) 1.155 + throw (InstantiationException) cause; 1.156 + if (cause instanceof InvocationTargetException) 1.157 + throw (InvocationTargetException) cause; 1.158 + if (cause instanceof IllegalAccessException) 1.159 + throw (IllegalAccessException) cause; 1.160 + // not supposed to happen 1.161 + throw x; 1.162 + } 1.163 + } 1.164 } catch (IllegalAccessException ex) { 1.165 // should not occur, as access checks have been suppressed 1.166 InternalError ie = new InternalError(); 1.167 - ie.initCause( ex ) ; 1.168 - throw ie ; 1.169 + ie.initCause(ex); 1.170 + throw ie; 1.171 } 1.172 } else { 1.173 throw new UnsupportedOperationException(); 1.174 } 1.175 } 1.176 1.177 + 1.178 /** 1.179 * Returns public no-arg constructor of given class, or null if none found. 1.180 * Access checks are disabled on the returned constructor (if any), since 1.181 @@ -1526,7 +1632,8 @@ 1.182 Method readObjectMethod; 1.183 private transient Method writeReplaceObjectMethod; 1.184 private transient Method readResolveObjectMethod; 1.185 - private Constructor cons ; 1.186 + private Constructor<?> cons; 1.187 + private transient ProtectionDomain[] domains; 1.188 1.189 /** 1.190 * Beginning in Java to IDL ptc/02-01-12, RMI-IIOP has a