26 package java.io;
27
28 import java.io.ObjectStreamClass.WeakClassKey;
29 import java.lang.ref.ReferenceQueue;
30 import java.lang.reflect.Array;
31 import java.lang.reflect.Modifier;
32 import java.lang.reflect.Proxy;
33 import java.security.AccessControlContext;
34 import java.security.AccessController;
35 import java.security.PrivilegedAction;
36 import java.security.PrivilegedActionException;
37 import java.security.PrivilegedExceptionAction;
38 import java.util.Arrays;
39 import java.util.HashMap;
40 import java.util.Objects;
41 import java.util.concurrent.ConcurrentHashMap;
42 import java.util.concurrent.ConcurrentMap;
43
44 import static java.io.ObjectStreamClass.processQueue;
45
46 import sun.misc.ObjectInputFilter;
47 import sun.misc.ObjectStreamClassValidator;
48 import sun.misc.SharedSecrets;
49 import sun.reflect.misc.ReflectUtil;
50 import sun.misc.JavaOISAccess;
51 import sun.util.logging.PlatformLogger;
52
53 /**
54 * An ObjectInputStream deserializes primitive data and objects previously
55 * written using an ObjectOutputStream.
56 *
57 * <p>ObjectOutputStream and ObjectInputStream can provide an application with
58 * persistent storage for graphs of objects when used with a FileOutputStream
59 * and FileInputStream respectively. ObjectInputStream is used to recover
60 * those objects previously serialized. Other uses include passing objects
61 * between hosts using a socket stream or for marshaling and unmarshaling
62 * arguments and parameters in a remote communication system.
63 *
64 * <p>ObjectInputStream ensures that the types of all objects in the graph
65 * created from the stream match the classes present in the Java Virtual
237 private static class Caches {
238 /** cache of subclass security audit results */
239 static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
240 new ConcurrentHashMap<>();
241
242 /** queue for WeakReferences to audited subclasses */
243 static final ReferenceQueue<Class<?>> subclassAuditsQueue =
244 new ReferenceQueue<>();
245 }
246
247 static {
248 /* Setup access so sun.misc can invoke package private functions. */
249 sun.misc.SharedSecrets.setJavaOISAccess(new JavaOISAccess() {
250 public void setObjectInputFilter(ObjectInputStream stream, ObjectInputFilter filter) {
251 stream.setInternalObjectInputFilter(filter);
252 }
253
254 public ObjectInputFilter getObjectInputFilter(ObjectInputStream stream) {
255 return stream.getInternalObjectInputFilter();
256 }
257 });
258 }
259
260 /*
261 * Separate class to defer initialization of logging until needed.
262 */
263 private static class Logging {
264
265 /*
266 * Logger for ObjectInputFilter results.
267 * Setup the filter logger if it is set to INFO or WARNING.
268 * (Assuming it will not change).
269 */
270 private static final PlatformLogger traceLogger;
271 private static final PlatformLogger infoLogger;
272 static {
273 PlatformLogger filterLog = PlatformLogger.getLogger("java.io.serialization");
274 infoLogger = (filterLog != null &&
275 filterLog.isLoggable(PlatformLogger.Level.INFO)) ? filterLog : null;
276 traceLogger = (filterLog != null &&
1240 "ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
1241 status, clazz, arrayLength, totalObjectRefs, depth, bin.getBytesRead(),
1242 Objects.toString(ex, "n/a"));
1243 }
1244 InvalidClassException ice = new InvalidClassException("filter status: " + status);
1245 ice.initCause(ex);
1246 throw ice;
1247 } else {
1248 // Trace logging for those that succeed
1249 if (Logging.traceLogger != null) {
1250 Logging.traceLogger.finer(
1251 "ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
1252 status, clazz, arrayLength, totalObjectRefs, depth, bin.getBytesRead(),
1253 Objects.toString(ex, "n/a"));
1254 }
1255 }
1256 }
1257 }
1258
1259 /**
1260 * Provide access to the persistent fields read from the input stream.
1261 */
1262 public static abstract class GetField {
1263
1264 /**
1265 * Get the ObjectStreamClass that describes the fields in the stream.
1266 *
1267 * @return the descriptor class that describes the serializable fields
1268 */
1269 public abstract ObjectStreamClass getObjectStreamClass();
1270
1271 /**
1272 * Return true if the named field is defaulted and has no value in this
1273 * stream.
1274 *
1275 * @param name the name of the field
1276 * @return true, if and only if the named field is defaulted
1277 * @throws IOException if there are I/O errors while reading from
1278 * the underlying <code>InputStream</code>
1279 * @throws IllegalArgumentException if <code>name</code> does not
1729 }
1730
1731 /**
1732 * Reads in and returns class descriptor for a dynamic proxy class. Sets
1733 * passHandle to proxy class descriptor's assigned handle. If proxy class
1734 * descriptor cannot be resolved to a class in the local VM, a
1735 * ClassNotFoundException is associated with the descriptor's handle.
1736 */
1737 private ObjectStreamClass readProxyDesc(boolean unshared)
1738 throws IOException
1739 {
1740 if (bin.readByte() != TC_PROXYCLASSDESC) {
1741 throw new InternalError();
1742 }
1743
1744 ObjectStreamClass desc = new ObjectStreamClass();
1745 int descHandle = handles.assign(unshared ? unsharedMarker : desc);
1746 passHandle = NULL_HANDLE;
1747
1748 int numIfaces = bin.readInt();
1749 String[] ifaces = new String[numIfaces];
1750 for (int i = 0; i < numIfaces; i++) {
1751 ifaces[i] = bin.readUTF();
1752 }
1753
1754 Class<?> cl = null;
1755 ClassNotFoundException resolveEx = null;
1756 bin.setBlockDataMode(true);
1757 try {
1758 if ((cl = resolveProxyClass(ifaces)) == null) {
1759 resolveEx = new ClassNotFoundException("null class");
1760 } else if (!Proxy.isProxyClass(cl)) {
1761 throw new InvalidClassException("Not a proxy");
1762 } else {
1763 // ReflectUtil.checkProxyPackageAccess makes a test
1764 // equivalent to isCustomSubclass so there's no need
1765 // to condition this call to isCustomSubclass == true here.
1766 ReflectUtil.checkProxyPackageAccess(
1767 getClass().getClassLoader(),
1768 cl.getInterfaces());
3852 } else if (array instanceof int[]) {
3853 return ((int[]) array).clone();
3854 } else if (array instanceof long[]) {
3855 return ((long[]) array).clone();
3856 } else if (array instanceof short[]) {
3857 return ((short[]) array).clone();
3858 } else {
3859 throw new AssertionError();
3860 }
3861 }
3862
3863 private void validateDescriptor(ObjectStreamClass descriptor) {
3864 ObjectStreamClassValidator validating = validator;
3865 if (validating != null) {
3866 validating.validateDescriptor(descriptor);
3867 }
3868 }
3869
3870 // controlled access to ObjectStreamClassValidator
3871 private volatile ObjectStreamClassValidator validator;
3872
3873 private static void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator) {
3874 ois.validator = validator;
3875 }
3876 static {
3877 SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::setValidator);
3878 }
3879 }
|
26 package java.io;
27
28 import java.io.ObjectStreamClass.WeakClassKey;
29 import java.lang.ref.ReferenceQueue;
30 import java.lang.reflect.Array;
31 import java.lang.reflect.Modifier;
32 import java.lang.reflect.Proxy;
33 import java.security.AccessControlContext;
34 import java.security.AccessController;
35 import java.security.PrivilegedAction;
36 import java.security.PrivilegedActionException;
37 import java.security.PrivilegedExceptionAction;
38 import java.util.Arrays;
39 import java.util.HashMap;
40 import java.util.Objects;
41 import java.util.concurrent.ConcurrentHashMap;
42 import java.util.concurrent.ConcurrentMap;
43
44 import static java.io.ObjectStreamClass.processQueue;
45
46 import sun.misc.SharedSecrets;
47 import sun.misc.ObjectInputFilter;
48 import sun.misc.ObjectStreamClassValidator;
49 import sun.misc.SharedSecrets;
50 import sun.reflect.misc.ReflectUtil;
51 import sun.misc.JavaOISAccess;
52 import sun.util.logging.PlatformLogger;
53
54 /**
55 * An ObjectInputStream deserializes primitive data and objects previously
56 * written using an ObjectOutputStream.
57 *
58 * <p>ObjectOutputStream and ObjectInputStream can provide an application with
59 * persistent storage for graphs of objects when used with a FileOutputStream
60 * and FileInputStream respectively. ObjectInputStream is used to recover
61 * those objects previously serialized. Other uses include passing objects
62 * between hosts using a socket stream or for marshaling and unmarshaling
63 * arguments and parameters in a remote communication system.
64 *
65 * <p>ObjectInputStream ensures that the types of all objects in the graph
66 * created from the stream match the classes present in the Java Virtual
238 private static class Caches {
239 /** cache of subclass security audit results */
240 static final ConcurrentMap<WeakClassKey,Boolean> subclassAudits =
241 new ConcurrentHashMap<>();
242
243 /** queue for WeakReferences to audited subclasses */
244 static final ReferenceQueue<Class<?>> subclassAuditsQueue =
245 new ReferenceQueue<>();
246 }
247
248 static {
249 /* Setup access so sun.misc can invoke package private functions. */
250 sun.misc.SharedSecrets.setJavaOISAccess(new JavaOISAccess() {
251 public void setObjectInputFilter(ObjectInputStream stream, ObjectInputFilter filter) {
252 stream.setInternalObjectInputFilter(filter);
253 }
254
255 public ObjectInputFilter getObjectInputFilter(ObjectInputStream stream) {
256 return stream.getInternalObjectInputFilter();
257 }
258
259 public void checkArray(ObjectInputStream stream, Class<?> arrayType, int arrayLength)
260 throws InvalidClassException
261 {
262 stream.checkArray(arrayType, arrayLength);
263 }
264
265 public void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator) {
266 ois.validator = validator;
267 }
268 });
269 }
270
271 /*
272 * Separate class to defer initialization of logging until needed.
273 */
274 private static class Logging {
275
276 /*
277 * Logger for ObjectInputFilter results.
278 * Setup the filter logger if it is set to INFO or WARNING.
279 * (Assuming it will not change).
280 */
281 private static final PlatformLogger traceLogger;
282 private static final PlatformLogger infoLogger;
283 static {
284 PlatformLogger filterLog = PlatformLogger.getLogger("java.io.serialization");
285 infoLogger = (filterLog != null &&
286 filterLog.isLoggable(PlatformLogger.Level.INFO)) ? filterLog : null;
287 traceLogger = (filterLog != null &&
1251 "ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
1252 status, clazz, arrayLength, totalObjectRefs, depth, bin.getBytesRead(),
1253 Objects.toString(ex, "n/a"));
1254 }
1255 InvalidClassException ice = new InvalidClassException("filter status: " + status);
1256 ice.initCause(ex);
1257 throw ice;
1258 } else {
1259 // Trace logging for those that succeed
1260 if (Logging.traceLogger != null) {
1261 Logging.traceLogger.finer(
1262 "ObjectInputFilter {0}: {1}, array length: {2}, nRefs: {3}, depth: {4}, bytes: {5}, ex: {6}",
1263 status, clazz, arrayLength, totalObjectRefs, depth, bin.getBytesRead(),
1264 Objects.toString(ex, "n/a"));
1265 }
1266 }
1267 }
1268 }
1269
1270 /**
1271 * Checks the given array type and length to ensure that creation of such
1272 * an array is permitted by this ObjectInputStream. The arrayType argument
1273 * must represent an actual array type.
1274 *
1275 * This private method is called via SharedSecrets.
1276 *
1277 * @param arrayType the array type
1278 * @param arrayLength the array length
1279 * @throws NullPointerException if arrayType is null
1280 * @throws IllegalArgumentException if arrayType isn't actually an array type
1281 * @throws NegativeArraySizeException if arrayLength is negative
1282 * @throws InvalidClassException if the filter rejects creation
1283 */
1284 private void checkArray(Class<?> arrayType, int arrayLength) throws InvalidClassException {
1285 Objects.requireNonNull(arrayType);
1286 if (! arrayType.isArray()) {
1287 throw new IllegalArgumentException("not an array type");
1288 }
1289
1290 if (arrayLength < 0) {
1291 throw new NegativeArraySizeException();
1292 }
1293
1294 filterCheck(arrayType, arrayLength);
1295 }
1296
1297 /**
1298 * Provide access to the persistent fields read from the input stream.
1299 */
1300 public static abstract class GetField {
1301
1302 /**
1303 * Get the ObjectStreamClass that describes the fields in the stream.
1304 *
1305 * @return the descriptor class that describes the serializable fields
1306 */
1307 public abstract ObjectStreamClass getObjectStreamClass();
1308
1309 /**
1310 * Return true if the named field is defaulted and has no value in this
1311 * stream.
1312 *
1313 * @param name the name of the field
1314 * @return true, if and only if the named field is defaulted
1315 * @throws IOException if there are I/O errors while reading from
1316 * the underlying <code>InputStream</code>
1317 * @throws IllegalArgumentException if <code>name</code> does not
1767 }
1768
1769 /**
1770 * Reads in and returns class descriptor for a dynamic proxy class. Sets
1771 * passHandle to proxy class descriptor's assigned handle. If proxy class
1772 * descriptor cannot be resolved to a class in the local VM, a
1773 * ClassNotFoundException is associated with the descriptor's handle.
1774 */
1775 private ObjectStreamClass readProxyDesc(boolean unshared)
1776 throws IOException
1777 {
1778 if (bin.readByte() != TC_PROXYCLASSDESC) {
1779 throw new InternalError();
1780 }
1781
1782 ObjectStreamClass desc = new ObjectStreamClass();
1783 int descHandle = handles.assign(unshared ? unsharedMarker : desc);
1784 passHandle = NULL_HANDLE;
1785
1786 int numIfaces = bin.readInt();
1787 if (numIfaces > 65535) {
1788 throw new InvalidObjectException("interface limit exceeded: "
1789 + numIfaces);
1790 }
1791 String[] ifaces = new String[numIfaces];
1792 for (int i = 0; i < numIfaces; i++) {
1793 ifaces[i] = bin.readUTF();
1794 }
1795
1796 Class<?> cl = null;
1797 ClassNotFoundException resolveEx = null;
1798 bin.setBlockDataMode(true);
1799 try {
1800 if ((cl = resolveProxyClass(ifaces)) == null) {
1801 resolveEx = new ClassNotFoundException("null class");
1802 } else if (!Proxy.isProxyClass(cl)) {
1803 throw new InvalidClassException("Not a proxy");
1804 } else {
1805 // ReflectUtil.checkProxyPackageAccess makes a test
1806 // equivalent to isCustomSubclass so there's no need
1807 // to condition this call to isCustomSubclass == true here.
1808 ReflectUtil.checkProxyPackageAccess(
1809 getClass().getClassLoader(),
1810 cl.getInterfaces());
3894 } else if (array instanceof int[]) {
3895 return ((int[]) array).clone();
3896 } else if (array instanceof long[]) {
3897 return ((long[]) array).clone();
3898 } else if (array instanceof short[]) {
3899 return ((short[]) array).clone();
3900 } else {
3901 throw new AssertionError();
3902 }
3903 }
3904
3905 private void validateDescriptor(ObjectStreamClass descriptor) {
3906 ObjectStreamClassValidator validating = validator;
3907 if (validating != null) {
3908 validating.validateDescriptor(descriptor);
3909 }
3910 }
3911
3912 // controlled access to ObjectStreamClassValidator
3913 private volatile ObjectStreamClassValidator validator;
3914 }
|