8198662: Incompatible internal API change in JDK8u161: signature of method exportObject()

Reviewed-by: dfuchs, robm, jwilhelm, rriggs
diff --git a/jdk/src/share/classes/com/sun/jmx/remote/internal/RMIExporter.java b/jdk/src/share/classes/com/sun/jmx/remote/internal/RMIExporter.java
index ead4a4d..8568aa9 100644
--- a/jdk/src/share/classes/com/sun/jmx/remote/internal/RMIExporter.java
+++ b/jdk/src/share/classes/com/sun/jmx/remote/internal/RMIExporter.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,7 +25,6 @@
 
 package com.sun.jmx.remote.internal;
 
-import sun.misc.ObjectInputFilter;
 import java.rmi.NoSuchObjectException;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
@@ -52,8 +51,7 @@
     public Remote exportObject(Remote obj,
                                int port,
                                RMIClientSocketFactory csf,
-                               RMIServerSocketFactory ssf,
-                               ObjectInputFilter filter)
+                               RMIServerSocketFactory ssf)
             throws RemoteException;
 
     public boolean unexportObject(Remote obj, boolean force)
diff --git a/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java b/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java
index 8856d6b..9d924a3 100644
--- a/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java
+++ b/jdk/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java
@@ -1,6 +1,6 @@
 
 /*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -70,61 +70,6 @@
             "jmx.remote.rmi.server.credential.types";
 
     /**
-    * Name of the attribute that specifies an
-    * {@link ObjectInputFilter} pattern string to filter classes acceptable
-    * for {@link RMIServer#newClient(java.lang.Object) RMIServer.newClient()}
-    * remote method call.
-    * <p>
-    * The filter pattern must be in same format as used in
-    * {@link java.io.ObjectInputFilter.Config.createFilter}
-    * <p>
-    * This list of classes allowed by filter should correspond to the
-    * transitive closure of the credentials class (or classes) used by the
-    * installed {@linkplain JMXAuthenticator} associated with the
-    * {@linkplain RMIServer} implementation.
-    * If the attribute is not set then any class is deemed acceptable.
-    * @see ObjectInputFilter
-    */
-    public static final String CREDENTIALS_FILTER_PATTERN =
-        "jmx.remote.rmi.server.credentials.filter.pattern";
-
-    /**
-     * This attribute defines a pattern from which to create a
-     * {@link java.io.ObjectInputFilter} that will be used when deserializing
-     * objects sent to the {@code JMXConnectorServer} by any client.
-     * <p>
-     * The filter will be called for any class found in the serialized
-     * stream sent to server by client, including all JMX defined classes
-     * (such as {@link javax.management.ObjectName}), all method parameters,
-     * and, if present in the stream, all classes transitively referred by
-     * the serial form of any deserialized object.
-     * The pattern must be in same format as used in
-     * {@link java.io.ObjectInputFilter.Config.createFilter}.
-     * It may define a white list of permitted classes, a black list of
-     * rejected classes, a maximum depth for the deserialized objects,
-     * etc.
-     * <p>
-     * To be functional, the filter should allow at least all the
-     * concrete types in the transitive closure of all objects that
-     * might get serialized when serializing all JMX classes referred
-     * as parameters in the {@link
-     * javax.management.remote.rmi.RMIConnection} interface,
-     * plus all classes that a {@link javax.management.remote.rmi.RMIConnectorClient}
-     * might need to transmit wrapped in {@linkplain java.rmi.MarshalledObject
-     * marshalled objects} in order to interoperate with the MBeans registered
-     * in the {@code MBeanServer}. That would potentially include all the
-     * concrete {@linkplain javax.management.openmbean  JMX OpenTypes} and the
-     * classes they use in their serial form.
-     * <p>
-     * Care must be taken when defining such a filter, as defining
-     * a white list too restrictive or a too wide a black list may
-     * prevent legitimate clients from interoperating with the
-     * {@code JMXConnectorServer}.
-     */
-    public static final String SERIAL_FILTER_PATTERN =
-       "jmx.remote.rmi.server.serial.filter.pattern";
-
-    /**
      * <p>Name of the attribute that specifies a default class loader
      * object.
      * The value associated with this attribute is a ClassLoader object</p>
diff --git a/jdk/src/share/classes/java/io/ObjectInputStream.java b/jdk/src/share/classes/java/io/ObjectInputStream.java
index e43d461..7e173eb 100644
--- a/jdk/src/share/classes/java/io/ObjectInputStream.java
+++ b/jdk/src/share/classes/java/io/ObjectInputStream.java
@@ -45,6 +45,8 @@
 
 import sun.misc.SharedSecrets;
 import sun.misc.ObjectInputFilter;
+import sun.misc.ObjectStreamClassValidator;
+import sun.misc.SharedSecrets;
 import sun.reflect.misc.ReflectUtil;
 import sun.misc.JavaOISAccess;
 import sun.util.logging.PlatformLogger;
@@ -1750,6 +1752,9 @@
                 throw new StreamCorruptedException(
                     String.format("invalid type code: %02X", tc));
         }
+        if (descriptor != null) {
+            validateDescriptor(descriptor);
+        }
         return descriptor;
     }
 
@@ -3895,4 +3900,21 @@
             throw new AssertionError();
         }
     }
+
+    private void validateDescriptor(ObjectStreamClass descriptor) {
+        ObjectStreamClassValidator validating = validator;
+        if (validating != null) {
+            validating.validateDescriptor(descriptor);
+        }
+    }
+
+    // controlled access to ObjectStreamClassValidator
+    private volatile ObjectStreamClassValidator validator;
+
+    private static void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator) {
+        ois.validator = validator;
+    }
+    static {
+        SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::setValidator);
+    }
 }
diff --git a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java
index 621bccb..4cdb092 100644
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -33,7 +33,6 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
-import sun.misc.ObjectInputFilter;
 import java.io.ObjectOutputStream;
 import java.net.MalformedURLException;
 import java.rmi.server.RMIClientSocketFactory;
diff --git a/jdk/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java b/jdk/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java
index c16936b..562de79 100644
--- a/jdk/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java
+++ b/jdk/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -26,7 +26,6 @@
 package javax.management.remote.rmi;
 
 import java.io.IOException;
-import sun.misc.ObjectInputFilter;
 import java.rmi.NoSuchObjectException;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
@@ -48,11 +47,6 @@
 import sun.rmi.server.DeserializationChecker;
 import sun.rmi.server.UnicastServerRef;
 import sun.rmi.server.UnicastServerRef2;
-import java.util.Arrays;
-import java.util.Set;
-import java.util.stream.Collectors;
-import sun.rmi.transport.LiveRef;
-
 
 /**
  * <p>An {@link RMIServer} object that is exported through JRMP and that
@@ -65,6 +59,8 @@
  */
 public class RMIJRMPServerImpl extends RMIServerImpl {
 
+    private final ExportedWrapper exportedWrapper;
+
     /**
      * <p>Creates a new {@link RMIServer} object that will be exported
      * on the given port using the given socket factories.</p>
@@ -105,37 +101,31 @@
 
         String[] credentialsTypes
                 = (String[]) this.env.get(EnvHelp.CREDENTIAL_TYPES);
-
-        String credentialsFilter
-                = (String) this.env.get(EnvHelp.CREDENTIALS_FILTER_PATTERN);
-
-        if(credentialsFilter != null){
-            cFilter = ObjectInputFilter.Config.createFilter(credentialsFilter);
-            allowedTypes = null;
+        List<String> types = null;
+        if (credentialsTypes != null) {
+            types = new ArrayList<>();
+            for (String type : credentialsTypes) {
+                if (type == null) {
+                    throw new IllegalArgumentException("A credential type is null.");
+                }
+                ReflectUtil.checkPackageAccess(type);
+                types.add(type);
+            }
         }
-        else if (credentialsTypes != null) {
-            allowedTypes = Arrays.stream(credentialsTypes).filter(
-                    s -> s!= null).collect(Collectors.toSet());
-            allowedTypes.stream().forEach(ReflectUtil::checkPackageAccess);
-            cFilter = this::newClientCheckInput;
-        } else {
-            allowedTypes = null;
-            cFilter = null;
-        }
-
-        String userJmxFilter =
-                (String) this.env.get(EnvHelp.SERIAL_FILTER_PATTERN);
-        if(userJmxFilter != null && !userJmxFilter.isEmpty())
-            jmxRmiFilter = ObjectInputFilter.Config.createFilter(userJmxFilter);
-        else
-            jmxRmiFilter = null;
+        exportedWrapper = types != null ?
+                new ExportedWrapper(this, types) :
+                null;
     }
 
     protected void export() throws IOException {
-        export(this, cFilter);
+        if (exportedWrapper != null) {
+            export(exportedWrapper);
+        } else {
+            export(this);
+        }
     }
 
-    private void export(Remote obj, ObjectInputFilter typeFilter) throws RemoteException {
+    private void export(Remote obj) throws RemoteException {
         final RMIExporter exporter =
             (RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE);
         final boolean daemon = EnvHelp.isServerDaemon(env);
@@ -146,14 +136,16 @@
                     " cannot be used to specify an exporter!");
         }
 
-        if (exporter != null) {
-            exporter.exportObject(obj, port, csf, ssf, typeFilter);
-        } else {
+        if (daemon) {
             if (csf == null && ssf == null) {
-                new UnicastServerRef(new LiveRef(port), typeFilter).exportObject(obj, null, daemon);
+                new UnicastServerRef(port).exportObject(obj, null, true);
             } else {
-                new UnicastServerRef2(port, csf, ssf, typeFilter).exportObject(obj, null, daemon);
+                new UnicastServerRef2(port, csf, ssf).exportObject(obj, null, true);
             }
+        } else if (exporter != null) {
+            exporter.exportObject(obj, port, csf, ssf);
+        } else {
+            UnicastRemoteObject.exportObject(obj, port, csf, ssf);
         }
     }
 
@@ -180,7 +172,11 @@
      *            RMIJRMPServerImpl has not been exported yet.
      */
     public Remote toStub() throws IOException {
-        return RemoteObject.toStub(this);
+        if (exportedWrapper != null) {
+            return RemoteObject.toStub(exportedWrapper);
+        } else {
+            return RemoteObject.toStub(this);
+        }
     }
 
     /**
@@ -210,7 +206,7 @@
         RMIConnection client =
             new RMIConnectionImpl(this, connectionId, getDefaultClassLoader(),
                                   subject, env);
-        export(client, jmxRmiFilter);
+        export(client);
         return client;
     }
 
@@ -227,38 +223,56 @@
      * server failed.
      */
     protected void closeServer() throws IOException {
-        unexport(this, true);
+        if (exportedWrapper != null) {
+            unexport(exportedWrapper, true);
+        } else {
+            unexport(this, true);
+        }
     }
 
-    /**
-     * Check that a type in the remote invocation of {@link RMIServerImpl#newClient}
-     * is one of the {@code allowedTypes}.
-     *
-     * @param clazz       the class; may be null
-     * @param size        the size for arrays, otherwise is 0
-     * @param nObjectRefs the current number of object references
-     * @param depth       the current depth
-     * @param streamBytes the current number of bytes consumed
-     * @return {@code ObjectInputFilter.Status.ALLOWED} if the class is allowed,
-     *          otherwise {@code ObjectInputFilter.Status.REJECTED}
-     */
-    ObjectInputFilter.Status newClientCheckInput(ObjectInputFilter.FilterInfo filterInfo) {
-        ObjectInputFilter.Status status = ObjectInputFilter.Status.UNDECIDED;
-        if (allowedTypes != null && filterInfo.serialClass() != null) {
-            // If enabled, check type
-            String type = filterInfo.serialClass().getName();
-            if (allowedTypes.contains(type))
-                status = ObjectInputFilter.Status.ALLOWED;
-            else
-                status = ObjectInputFilter.Status.REJECTED;
-        }
-        return status;
-    }
     private final int port;
     private final RMIClientSocketFactory csf;
     private final RMIServerSocketFactory ssf;
     private final Map<String, ?> env;
-    private final Set<String> allowedTypes;
-    private final ObjectInputFilter jmxRmiFilter;
-    private final ObjectInputFilter cFilter;
+
+    private static class ExportedWrapper implements RMIServer, DeserializationChecker {
+        private final RMIServer impl;
+        private final List<String> allowedTypes;
+        private ExportedWrapper(RMIServer impl, List<String> credentialsTypes) {
+            this.impl = impl;
+            allowedTypes = credentialsTypes;
+        }
+
+        @Override
+        public String getVersion() throws RemoteException {
+            return impl.getVersion();
+        }
+
+        @Override
+        public RMIConnection newClient(Object credentials) throws IOException {
+            return impl.newClient(credentials);
+        }
+
+        @Override
+        public void check(Method method, ObjectStreamClass descriptor,
+                int paramIndex, int callID) {
+
+            String type = descriptor.getName();
+            if (!allowedTypes.contains(type)) {
+                throw new ClassCastException("Unsupported type: " + type);
+            }
+        }
+
+        @Override
+        public void checkProxyClass(Method method, String[] ifaces,
+                int paramIndex, int callID) {
+            if (ifaces != null && ifaces.length > 0) {
+                for (String iface : ifaces) {
+                    if (!allowedTypes.contains(iface)) {
+                        throw new ClassCastException("Unsupported type: " + iface);
+                    }
+                }
+            }
+        }
+    }
 }
diff --git a/jdk/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java b/jdk/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java
index 2bde891..56287ed 100644
--- a/jdk/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java
+++ b/jdk/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,7 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import sun.misc.ObjectInputFilter;
+import java.io.Serializable;
 import java.lang.management.ManagementFactory;
 import java.net.InetAddress;
 import java.net.MalformedURLException;
@@ -43,6 +43,7 @@
 import java.rmi.registry.Registry;
 import java.rmi.server.RMIClientSocketFactory;
 import java.rmi.server.RMIServerSocketFactory;
+import java.rmi.server.RMISocketFactory;
 import java.rmi.server.RemoteObject;
 import java.rmi.server.UnicastRemoteObject;
 import java.security.KeyStore;
@@ -82,7 +83,6 @@
 import sun.rmi.server.UnicastRef;
 import sun.rmi.server.UnicastServerRef;
 import sun.rmi.server.UnicastServerRef2;
-import sun.rmi.transport.LiveRef;
 
 /**
  * This class initializes and starts the RMIConnectorServer for JSR 163
@@ -141,8 +141,6 @@
                 "com.sun.management.jmxremote.ssl.need.client.auth";
         public static final String SSL_CONFIG_FILE_NAME =
                 "com.sun.management.jmxremote.ssl.config.file";
-        public static final String SERIAL_FILTER_PATTERN =
-                "com.sun.management.jmxremote.serial.filter.pattern";
     }
 
     /**
@@ -183,8 +181,7 @@
         public Remote exportObject(Remote obj,
                 int port,
                 RMIClientSocketFactory csf,
-                RMIServerSocketFactory ssf,
-                ObjectInputFilter filter)
+                RMIServerSocketFactory ssf)
                 throws RemoteException {
 
             synchronized (this) {
@@ -195,9 +192,9 @@
 
             final UnicastServerRef ref;
             if (csf == null && ssf == null) {
-                ref = new UnicastServerRef(new LiveRef(port), filter);
+                ref = new UnicastServerRef(port);
             } else {
-                ref = new UnicastServerRef2(port, csf, ssf, filter);
+                ref = new UnicastServerRef2(port, csf, ssf);
             }
             return ref.exportObject(obj, null, true);
         }
@@ -437,7 +434,6 @@
 
         final String bindAddress =
                 props.getProperty(PropertyNames.HOST);
-        final String jmxRmiFilter = props.getProperty(PropertyNames.SERIAL_FILTER_PATTERN);
 
         if (log.debugOn()) {
             log.debug("startRemoteConnectorServer",
@@ -474,7 +470,7 @@
                     sslConfigFileName, enabledCipherSuitesList,
                     enabledProtocolsList, sslNeedClientAuth,
                     useAuthentication, loginConfigName,
-                    passwordFileName, accessFileName, bindAddress, jmxRmiFilter);
+                    passwordFileName, accessFileName, bindAddress);
             cs = data.jmxConnectorServer;
             url = data.jmxRemoteURL;
             log.config("startRemoteConnectorServer",
@@ -514,7 +510,9 @@
         // This RMI server should not keep the VM alive
         Map<String, Object> env = new HashMap<>();
         env.put(RMIExporter.EXPORTER_ATTRIBUTE, new PermanentExporter());
-        env.put(EnvHelp.CREDENTIALS_FILTER_PATTERN, String.class.getName() + ";!*");
+        env.put(EnvHelp.CREDENTIAL_TYPES, new String[]{
+            String[].class.getName(), String.class.getName()
+        });
 
         // The local connector server need only be available via the
         // loopback connection.
@@ -730,8 +728,7 @@
             String loginConfigName,
             String passwordFileName,
             String accessFileName,
-            String bindAddress,
-            String jmxRmiFilter)
+            String bindAddress)
             throws IOException, MalformedURLException {
 
         /* Make sure we use non-guessable RMI object IDs.  Otherwise
@@ -746,11 +743,9 @@
         PermanentExporter exporter = new PermanentExporter();
 
         env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
-        env.put(EnvHelp.CREDENTIALS_FILTER_PATTERN, String.class.getName() + ";!*");
-
-        if(jmxRmiFilter != null && !jmxRmiFilter.isEmpty()) {
-            env.put(EnvHelp.SERIAL_FILTER_PATTERN, jmxRmiFilter);
-        }
+        env.put(EnvHelp.CREDENTIAL_TYPES, new String[]{
+            String[].class.getName(), String.class.getName()
+        });
 
         boolean useSocketFactory = bindAddress != null && !useSsl;
 
diff --git a/jdk/src/share/classes/sun/misc/JavaObjectInputStreamAccess.java b/jdk/src/share/classes/sun/misc/JavaObjectInputStreamAccess.java
new file mode 100644
index 0000000..8b6a7e1
--- /dev/null
+++ b/jdk/src/share/classes/sun/misc/JavaObjectInputStreamAccess.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.misc;
+
+import java.io.ObjectInputStream;
+
+/**
+ * The interface to specify methods for accessing {@code ObjectInputStream}
+ * @author sjiang
+ */
+public interface JavaObjectInputStreamAccess {
+    /**
+     * Sets a descriptor validating.
+     * @param ois stream to have the descriptors validated
+     * @param validator validator used to validate a descriptor.
+     */
+    public void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator);
+}
diff --git a/jdk/src/share/classes/sun/misc/ObjectStreamClassValidator.java b/jdk/src/share/classes/sun/misc/ObjectStreamClassValidator.java
new file mode 100644
index 0000000..f98a387
--- /dev/null
+++ b/jdk/src/share/classes/sun/misc/ObjectStreamClassValidator.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.misc;
+
+import java.io.ObjectStreamClass;
+
+/**
+ * A callback used by {@code ObjectInputStream} to do descriptor validation.
+ *
+ * @author sjiang
+ */
+public interface ObjectStreamClassValidator {
+    /**
+     * This method will be called by ObjectInputStream to
+     * check a descriptor just before creating an object described by this descriptor.
+     * The object will not be created if this method throws a {@code RuntimeException}.
+     * @param descriptor descriptor to be checked.
+     */
+    public void validateDescriptor(ObjectStreamClass descriptor);
+}
diff --git a/jdk/src/share/classes/sun/misc/SharedSecrets.java b/jdk/src/share/classes/sun/misc/SharedSecrets.java
index 5f8ee1b..cc3fc64 100644
--- a/jdk/src/share/classes/sun/misc/SharedSecrets.java
+++ b/jdk/src/share/classes/sun/misc/SharedSecrets.java
@@ -59,6 +59,7 @@
     private static JavaAWTAccess javaAWTAccess;
     private static JavaOISAccess javaOISAccess;
     private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess;
+    private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
 
     public static JavaUtilJarAccess javaUtilJarAccess() {
         if (javaUtilJarAccess == null) {
@@ -201,6 +202,18 @@
         return javaAWTAccess;
     }
 
+
+   public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() {
+        if (javaObjectInputStreamAccess == null) {
+            unsafe.ensureClassInitialized(ObjectInputStream.class);
+        }
+        return javaObjectInputStreamAccess;
+    }
+
+    public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) {
+        javaObjectInputStreamAccess = access;
+    }
+
     public static void setJavaxCryptoSealedObjectAccess(JavaxCryptoSealedObjectAccess jcsoa) {
         javaxCryptoSealedObjectAccess = jcsoa;
     }
diff --git a/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java b/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java
index 91be64b..ed13d45 100644
--- a/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java
+++ b/jdk/src/share/classes/sun/rmi/server/MarshalInputStream.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,8 @@
 import java.security.AccessControlException;
 import java.security.Permission;
 import java.rmi.server.RMIClassLoader;
+import sun.misc.ObjectStreamClassValidator;
+import sun.misc.SharedSecrets;
 
 /**
  * MarshalInputStream is an extension of ObjectInputStream.  When resolving
@@ -51,6 +53,11 @@
  * @author      Peter Jones
  */
 public class MarshalInputStream extends ObjectInputStream {
+    interface StreamChecker extends ObjectStreamClassValidator {
+        void checkProxyInterfaceNames(String[] ifaces);
+    }
+
+    private volatile StreamChecker streamChecker = null;
 
     /**
      * Value of "java.rmi.server.useCodebaseOnly" property,
@@ -237,6 +244,11 @@
     protected Class<?> resolveProxyClass(String[] interfaces)
         throws IOException, ClassNotFoundException
     {
+        StreamChecker checker = streamChecker;
+        if (checker != null) {
+            checker.checkProxyInterfaceNames(interfaces);
+        }
+
         /*
          * Always read annotation written by MarshalOutputStream.
          */
@@ -318,4 +330,28 @@
     void useCodebaseOnly() {
         useCodebaseOnly = true;
     }
+
+    synchronized void setStreamChecker(StreamChecker checker) {
+        streamChecker = checker;
+        SharedSecrets.getJavaObjectInputStreamAccess().setValidator(this, checker);
+    }
+    @Override
+    protected ObjectStreamClass readClassDescriptor() throws IOException,
+            ClassNotFoundException {
+        ObjectStreamClass descriptor = super.readClassDescriptor();
+
+        validateDesc(descriptor);
+
+        return descriptor;
+    }
+
+    private void validateDesc(ObjectStreamClass descriptor) {
+        StreamChecker checker;
+        synchronized (this) {
+            checker = streamChecker;
+        }
+        if (checker != null) {
+            checker.validateDescriptor(descriptor);
+        }
+    }
 }
diff --git a/jdk/src/share/classes/sun/rmi/server/UnicastServerRef.java b/jdk/src/share/classes/sun/rmi/server/UnicastServerRef.java
index 285dba5..d827460 100644
--- a/jdk/src/share/classes/sun/rmi/server/UnicastServerRef.java
+++ b/jdk/src/share/classes/sun/rmi/server/UnicastServerRef.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -29,6 +29,7 @@
 import java.io.ObjectInput;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutput;
+import java.io.ObjectStreamClass;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.rmi.AccessException;
@@ -331,15 +332,10 @@
             logCall(obj, method);
 
             // unmarshal parameters
-            Class<?>[] types = method.getParameterTypes();
-            Object[] params = new Object[types.length];
-
+            Object[] params = null;
             try {
                 unmarshalCustomCallData(in);
-                // Unmarshal the parameters
-                for (int i = 0; i < types.length; i++) {
-                    params[i] = unmarshalValue(types[i], in);
-                }
+                params = unmarshalParameters(obj, method, marshalStream);
 
             } catch (AccessException aex) {
                 // For compatibility, AccessException is not wrapped in UnmarshalException
@@ -609,4 +605,84 @@
         }
     }
 
+    /**
+     * Unmarshal parameters for the given method of the given instance over
+     * the given marshalinputstream. Perform any necessary checks.
+     */
+    private Object[] unmarshalParameters(Object obj, Method method, MarshalInputStream in)
+    throws IOException, ClassNotFoundException {
+        return (obj instanceof DeserializationChecker) ?
+            unmarshalParametersChecked((DeserializationChecker)obj, method, in) :
+            unmarshalParametersUnchecked(method, in);
+    }
+
+    /**
+     * Unmarshal parameters for the given method of the given instance over
+     * the given marshalinputstream. Do not perform any additional checks.
+     */
+    private Object[] unmarshalParametersUnchecked(Method method, ObjectInput in)
+    throws IOException, ClassNotFoundException {
+        Class<?>[] types = method.getParameterTypes();
+        Object[] params = new Object[types.length];
+        for (int i = 0; i < types.length; i++) {
+            params[i] = unmarshalValue(types[i], in);
+        }
+        return params;
+    }
+
+    /**
+     * Unmarshal parameters for the given method of the given instance over
+     * the given marshalinputstream. Do perform all additional checks.
+     */
+    private Object[] unmarshalParametersChecked(
+        DeserializationChecker checker,
+        Method method, MarshalInputStream in)
+    throws IOException, ClassNotFoundException {
+        int callID = methodCallIDCount.getAndIncrement();
+        MyChecker myChecker = new MyChecker(checker, method, callID);
+        in.setStreamChecker(myChecker);
+        try {
+            Class<?>[] types = method.getParameterTypes();
+            Object[] values = new Object[types.length];
+            for (int i = 0; i < types.length; i++) {
+                myChecker.setIndex(i);
+                values[i] = unmarshalValue(types[i], in);
+            }
+            myChecker.end(callID);
+            return values;
+        } finally {
+            in.setStreamChecker(null);
+        }
+    }
+
+    private static class MyChecker implements MarshalInputStream.StreamChecker {
+        private final DeserializationChecker descriptorCheck;
+        private final Method method;
+        private final int callID;
+        private int parameterIndex;
+
+        MyChecker(DeserializationChecker descriptorCheck, Method method, int callID) {
+            this.descriptorCheck = descriptorCheck;
+            this.method = method;
+            this.callID = callID;
+        }
+
+        @Override
+        public void validateDescriptor(ObjectStreamClass descriptor) {
+            descriptorCheck.check(method, descriptor, parameterIndex, callID);
+        }
+
+        @Override
+        public void checkProxyInterfaceNames(String[] ifaces) {
+            descriptorCheck.checkProxyClass(method, ifaces, parameterIndex, callID);
+        }
+
+        void setIndex(int parameterIndex) {
+            this.parameterIndex = parameterIndex;
+        }
+
+        void end(int callId) {
+            descriptorCheck.end(callId);
+        }
+    }
 }
diff --git a/jdk/src/share/lib/management/management.properties b/jdk/src/share/lib/management/management.properties
index 6b689e0..70efa2e 100644
--- a/jdk/src/share/lib/management/management.properties
+++ b/jdk/src/share/lib/management/management.properties
@@ -329,38 +329,3 @@
 #      The format of the value for that property is any string accepted
 #      by java.net.InetAddress.getByName(String).
 #
-
-# ################ Filter for ObjectInputStream #############################
-# com.sun.management.jmxremote.serial.filter.pattern=<filter-string>
-#   A filter, if configured, is used by java.io.ObjectInputStream during
-#   deserialization of parameters sent to the JMX default agent to validate the 
-#   contents of the stream.
-#   A filter is configured as a sequence of patterns, each pattern is either
-#   matched against the name of a class in the stream or defines a limit.
-#   Patterns are separated by ";" (semicolon).
-#   Whitespace is significant and is considered part of the pattern.
-#
-#   If a pattern includes a "=", it sets a limit.
-#   If a limit appears more than once the last value is used.
-#   Limits are checked before classes regardless of the order in the sequence of patterns.
-#   If any of the limits are exceeded, the filter status is REJECTED.
-#
-#       maxdepth=value - the maximum depth of a graph
-#       maxrefs=value  - the maximum number of internal references
-#       maxbytes=value - the maximum number of bytes in the input stream
-#       maxarray=value - the maximum array length allowed
-#
-#   Other patterns, from left to right, match the class or package name as
-#   returned from Class.getName.
-#   If the class is an array type, the class or package to be matched is the element type.
-#   Arrays of any number of dimensions are treated the same as the element type.
-#   For example, a pattern of "!example.Foo", rejects creation of any instance or
-#   array of example.Foo.
-#
-#   If the pattern starts with "!", the status is REJECTED if the remaining pattern
-#       is matched; otherwise the status is ALLOWED if the pattern matches.
-#   If the pattern ends with ".**" it matches any class in the package and all subpackages.
-#   If the pattern ends with ".*" it matches any class in the package.
-#   If the pattern ends with "*", it matches any class with the pattern as a prefix.
-#   If the pattern is equal to the class name, it matches.
-#   Otherwise, the status is UNDECIDED.
diff --git a/jdk/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java b/jdk/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java
index 4f59157..2ac2084 100644
--- a/jdk/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java
+++ b/jdk/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -46,7 +46,6 @@
 import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXServiceURL;
 import com.sun.jmx.remote.internal.RMIExporter;
-import sun.misc.ObjectInputFilter;
 
 public class RMIExporterTest {
 
@@ -60,8 +59,7 @@
         public Remote exportObject(Remote obj,
                                    int port,
                                    RMIClientSocketFactory csf,
-                                   RMIServerSocketFactory ssf,
-                                   ObjectInputFilter unused)
+                                   RMIServerSocketFactory ssf)
             throws RemoteException {
             System.out.println("CustomRMIExporter::exportObject():: " +
                                "Remote = " + obj);