8187556: Backout of a fix reintroduced a dependency that had since been removed
authorjwilhelm
Thu, 14 Sep 2017 22:57:36 +0200
changeset 47425 96179f26139e
parent 47424 3a00eb4636e3
child 47426 7d5509425e4a
8187556: Backout of a fix reintroduced a dependency that had since been removed Reviewed-by: duke
src/java.base/share/classes/java/io/ObjectInputStream.java
src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/RMIExporter.java
src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectorServer.java
src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java
src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java
src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java
src/jdk.management.agent/share/classes/sun/management/jmxremote/ConnectorBootstrap.java
src/jdk.management.agent/share/conf/management.properties
test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java
test/jdk/javax/management/remote/mandatory/connection/NewRMIClientFilterTest.java
test/jdk/javax/management/remote/mandatory/connection/mgmt1.properties
test/jdk/javax/management/remote/mandatory/connection/mgmt2.properties
test/jdk/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java
--- a/src/java.base/share/classes/java/io/ObjectInputStream.java	Mon Aug 14 15:32:25 2017 +0530
+++ b/src/java.base/share/classes/java/io/ObjectInputStream.java	Thu Sep 14 22:57:36 2017 +0200
@@ -44,7 +44,6 @@
 
 import static java.io.ObjectStreamClass.processQueue;
 
-import jdk.internal.misc.ObjectStreamClassValidator;
 import jdk.internal.misc.SharedSecrets;
 import jdk.internal.misc.Unsafe;
 import sun.reflect.misc.ReflectUtil;
@@ -1767,9 +1766,6 @@
                 throw new StreamCorruptedException(
                     String.format("invalid type code: %02X", tc));
         }
-        if (descriptor != null) {
-            validateDescriptor(descriptor);
-        }
         return descriptor;
     }
 
@@ -4013,20 +4009,4 @@
         SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::checkArray);
     }
 
-    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);
-    }
 }
--- a/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/RMIExporter.java	Mon Aug 14 15:32:25 2017 +0530
+++ b/src/java.management.rmi/share/classes/com/sun/jmx/remote/internal/rmi/RMIExporter.java	Thu Sep 14 22:57:36 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 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
@@ -25,6 +25,7 @@
 
 package com.sun.jmx.remote.internal.rmi;
 
+import java.io.ObjectInputFilter;
 import java.rmi.NoSuchObjectException;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
@@ -51,7 +52,8 @@
     public Remote exportObject(Remote obj,
                                int port,
                                RMIClientSocketFactory csf,
-                               RMIServerSocketFactory ssf)
+                               RMIServerSocketFactory ssf,
+                               ObjectInputFilter filter)
             throws RemoteException;
 
     public boolean unexportObject(Remote obj, boolean force)
--- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectorServer.java	Mon Aug 14 15:32:25 2017 +0530
+++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIConnectorServer.java	Thu Sep 14 22:57:36 2017 +0200
@@ -32,6 +32,7 @@
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.ObjectInputFilter;
 import java.io.ObjectOutputStream;
 import java.net.MalformedURLException;
 import java.rmi.server.RMIClientSocketFactory;
@@ -101,19 +102,59 @@
         "jmx.remote.rmi.server.socket.factory";
 
     /**
-    * Name of the attribute that specifies a list of class names acceptable
-    * as parameters to the {@link RMIServer#newClient(java.lang.Object) RMIServer.newClient()}
+    * 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>
-    * This list of classes should correspond to the transitive closure of the
-    * credentials class (or classes) used by the installed {@linkplain JMXAuthenticator}
-    * associated with the {@linkplain RMIServer} implementation.
+    * The filter pattern must be in same format as used in
+    * {@link java.io.ObjectInputFilter.Config#createFilter}
     * <p>
-    * If the attribute is not set, or is null, then any class is
-    * deemed acceptable.
+    * 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 CREDENTIAL_TYPES =
-            "jmx.remote.rmi.server.credential.types";
+    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.RMIConnector client}
+     * 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>Makes an <code>RMIConnectorServer</code>.
--- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java	Mon Aug 14 15:32:25 2017 +0530
+++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java	Thu Sep 14 22:57:36 2017 +0200
@@ -26,6 +26,7 @@
 package javax.management.remote.rmi;
 
 import java.io.IOException;
+import java.io.ObjectInputFilter;
 import java.rmi.NoSuchObjectException;
 import java.rmi.Remote;
 import java.rmi.RemoteException;
@@ -39,15 +40,13 @@
 
 import com.sun.jmx.remote.internal.rmi.RMIExporter;
 import com.sun.jmx.remote.util.EnvHelp;
-import java.io.ObjectStreamClass;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 import sun.reflect.misc.ReflectUtil;
-import sun.rmi.server.DeserializationChecker;
 import sun.rmi.server.UnicastServerRef;
 import sun.rmi.server.UnicastServerRef2;
+import sun.rmi.transport.LiveRef;
 
 /**
  * <p>An {@link RMIServer} object that is exported through JRMP and that
@@ -60,8 +59,6 @@
  */
 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>
@@ -100,33 +97,48 @@
         this.ssf = ssf;
         this.env = (env == null) ? Collections.<String, Object>emptyMap() : env;
 
+        // This attribute was represented by RMIConnectorServer.CREDENTIALS_TYPES.
+        // This attribute is superceded by
+        // RMIConnectorServer.CREDENTIALS_FILTER_PATTERN.
+        // Retaining this for backward compatibility.
         String[] credentialsTypes
-                = (String[]) this.env.get(RMIConnectorServer.CREDENTIAL_TYPES);
-        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);
-            }
+                = (String[]) this.env.get("jmx.remote.rmi.server.credential.types");
+
+        String credentialsFilter
+                = (String) this.env.get(RMIConnectorServer.CREDENTIALS_FILTER_PATTERN);
+
+        // It is impossible for both attributes to be specified
+        if(credentialsTypes != null && credentialsFilter != null)
+            throw new IllegalArgumentException("Cannot specify both \""
+                    + "jmx.remote.rmi.server.credential.types" + "\" and \""
+           + RMIConnectorServer.CREDENTIALS_FILTER_PATTERN + "\"");
+        else if(credentialsFilter != null){
+            cFilter = ObjectInputFilter.Config.createFilter(credentialsFilter);
+            allowedTypes = null;
         }
-        exportedWrapper = types != null ?
-                new ExportedWrapper(this, types) :
-                null;
+        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(RMIConnectorServer.SERIAL_FILTER_PATTERN);
+        if(userJmxFilter != null && !userJmxFilter.isEmpty())
+            jmxRmiFilter = ObjectInputFilter.Config.createFilter(userJmxFilter);
+        else
+            jmxRmiFilter = null;
     }
 
     protected void export() throws IOException {
-        if (exportedWrapper != null) {
-            export(exportedWrapper);
-        } else {
-            export(this);
-        }
+        export(this, cFilter);
     }
 
-    private void export(Remote obj) throws RemoteException {
+    private void export(Remote obj, ObjectInputFilter typeFilter) throws RemoteException {
         final RMIExporter exporter =
             (RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE);
         final boolean daemon = EnvHelp.isServerDaemon(env);
@@ -137,16 +149,14 @@
                     " cannot be used to specify an exporter!");
         }
 
-        if (daemon) {
+        if (exporter != null) {
+            exporter.exportObject(obj, port, csf, ssf, typeFilter);
+        } else {
             if (csf == null && ssf == null) {
-                new UnicastServerRef(port).exportObject(obj, null, true);
+                new UnicastServerRef(new LiveRef(port), typeFilter).exportObject(obj, null, daemon);
             } else {
-                new UnicastServerRef2(port, csf, ssf).exportObject(obj, null, true);
+                new UnicastServerRef2(port, csf, ssf, typeFilter).exportObject(obj, null, daemon);
             }
-        } else if (exporter != null) {
-            exporter.exportObject(obj, port, csf, ssf);
-        } else {
-            UnicastRemoteObject.exportObject(obj, port, csf, ssf);
         }
     }
 
@@ -173,11 +183,7 @@
      *            RMIJRMPServerImpl has not been exported yet.
      */
     public Remote toStub() throws IOException {
-        if (exportedWrapper != null) {
-            return RemoteObject.toStub(exportedWrapper);
-        } else {
-            return RemoteObject.toStub(this);
-        }
+        return RemoteObject.toStub(this);
     }
 
     /**
@@ -207,7 +213,7 @@
         RMIConnection client =
             new RMIConnectionImpl(this, connectionId, getDefaultClassLoader(),
                                   subject, env);
-        export(client);
+        export(client, jmxRmiFilter);
         return client;
     }
 
@@ -224,56 +230,39 @@
      * server failed.
      */
     protected void closeServer() throws IOException {
-        if (exportedWrapper != null) {
-            unexport(exportedWrapper, true);
-        } else {
-            unexport(this, true);
+        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 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);
-                    }
-                }
-            }
-        }
-    }
+    private final Set<String> allowedTypes;
+    private final ObjectInputFilter jmxRmiFilter;
+    private final ObjectInputFilter cFilter;
 }
--- a/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java	Mon Aug 14 15:32:25 2017 +0530
+++ b/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java	Thu Sep 14 22:57:36 2017 +0200
@@ -35,8 +35,6 @@
 import java.security.Permission;
 import java.rmi.server.RMIClassLoader;
 import java.security.PrivilegedAction;
-import jdk.internal.misc.ObjectStreamClassValidator;
-import jdk.internal.misc.SharedSecrets;
 
 /**
  * MarshalInputStream is an extension of ObjectInputStream.  When resolving
@@ -54,11 +52,6 @@
  * @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,
@@ -245,11 +238,6 @@
     protected Class<?> resolveProxyClass(String[] interfaces)
         throws IOException, ClassNotFoundException
     {
-        StreamChecker checker = streamChecker;
-        if (checker != null) {
-            checker.checkProxyInterfaceNames(interfaces);
-        }
-
         /*
          * Always read annotation written by MarshalOutputStream.
          */
@@ -330,28 +318,4 @@
     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);
-        }
-    }
 }
--- a/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java	Mon Aug 14 15:32:25 2017 +0530
+++ b/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java	Thu Sep 14 22:57:36 2017 +0200
@@ -30,7 +30,6 @@
 import java.io.ObjectInputFilter;
 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;
@@ -330,11 +329,16 @@
             logCall(obj, method);
 
             // unmarshal parameters
-            Object[] params = null;
+            Class<?>[] types = method.getParameterTypes();
+            Object[] params = new Object[types.length];
 
             try {
                 unmarshalCustomCallData(in);
-                params = unmarshalParameters(obj, method, marshalStream);
+                // Unmarshal the parameters
+                for (int i = 0; i < types.length; i++) {
+                    params[i] = unmarshalValue(types[i], in);
+                }
+
             } catch (AccessException aex) {
                 // For compatibility, AccessException is not wrapped in UnmarshalException
                 // disable saving any refs in the inputStream for GC
@@ -600,84 +604,4 @@
         }
     }
 
-    /**
-     * 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);
-        }
-    }
 }
--- a/src/jdk.management.agent/share/classes/sun/management/jmxremote/ConnectorBootstrap.java	Mon Aug 14 15:32:25 2017 +0530
+++ b/src/jdk.management.agent/share/classes/sun/management/jmxremote/ConnectorBootstrap.java	Thu Sep 14 22:57:36 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2012, 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
@@ -32,7 +32,7 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.Serializable;
+import java.io.ObjectInputFilter;
 import java.lang.management.ManagementFactory;
 import java.net.InetAddress;
 import java.net.MalformedURLException;
@@ -45,14 +45,12 @@
 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;
 import java.security.Principal;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
@@ -84,6 +82,7 @@
 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
@@ -142,6 +141,8 @@
                 "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";
     }
 
     /**
@@ -182,7 +183,8 @@
         public Remote exportObject(Remote obj,
                 int port,
                 RMIClientSocketFactory csf,
-                RMIServerSocketFactory ssf)
+                RMIServerSocketFactory ssf,
+                ObjectInputFilter filter)
                 throws RemoteException {
 
             synchronized (this) {
@@ -193,9 +195,9 @@
 
             final UnicastServerRef ref;
             if (csf == null && ssf == null) {
-                ref = new UnicastServerRef(port);
+                ref = new UnicastServerRef(new LiveRef(port), filter);
             } else {
-                ref = new UnicastServerRef2(port, csf, ssf);
+                ref = new UnicastServerRef2(port, csf, ssf, filter);
             }
             return ref.exportObject(obj, null, true);
         }
@@ -435,6 +437,7 @@
 
         final String bindAddress =
                 props.getProperty(PropertyNames.HOST);
+        final String jmxRmiFilter = props.getProperty(PropertyNames.SERIAL_FILTER_PATTERN);
 
         if (logger.isLoggable(Level.DEBUG)) {
             logger.log(Level.DEBUG, "startRemoteConnectorServer",
@@ -471,7 +474,7 @@
                     sslConfigFileName, enabledCipherSuitesList,
                     enabledProtocolsList, sslNeedClientAuth,
                     useAuthentication, loginConfigName,
-                    passwordFileName, accessFileName, bindAddress);
+                    passwordFileName, accessFileName, bindAddress, jmxRmiFilter);
             cs = data.jmxConnectorServer;
             url = data.jmxRemoteURL;
             config("startRemoteConnectorServer",
@@ -511,9 +514,7 @@
         // This RMI server should not keep the VM alive
         Map<String, Object> env = new HashMap<>();
         env.put(RMIExporter.EXPORTER_ATTRIBUTE, new PermanentExporter());
-        env.put(RMIConnectorServer.CREDENTIAL_TYPES, new String[]{
-            String[].class.getName(), String.class.getName()
-        });
+        env.put(RMIConnectorServer.CREDENTIALS_FILTER_PATTERN, String.class.getName() + ";!*");
 
         // The local connector server need only be available via the
         // loopback connection.
@@ -729,7 +730,8 @@
             String loginConfigName,
             String passwordFileName,
             String accessFileName,
-            String bindAddress)
+            String bindAddress,
+            String jmxRmiFilter)
             throws IOException, MalformedURLException {
 
         /* Make sure we use non-guessable RMI object IDs.  Otherwise
@@ -744,9 +746,11 @@
         PermanentExporter exporter = new PermanentExporter();
 
         env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
-        env.put(RMIConnectorServer.CREDENTIAL_TYPES, new String[]{
-            String[].class.getName(), String.class.getName()
-        });
+        env.put(RMIConnectorServer.CREDENTIALS_FILTER_PATTERN, String.class.getName() + ";!*");
+
+        if(jmxRmiFilter != null && !jmxRmiFilter.isEmpty()) {
+            env.put(RMIConnectorServer.SERIAL_FILTER_PATTERN, jmxRmiFilter);
+        }
 
         boolean useSocketFactory = bindAddress != null && !useSsl;
 
--- a/src/jdk.management.agent/share/conf/management.properties	Mon Aug 14 15:32:25 2017 +0530
+++ b/src/jdk.management.agent/share/conf/management.properties	Thu Sep 14 22:57:36 2017 +0200
@@ -329,3 +329,42 @@
 #      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 contains "/", the non-empty prefix up to the "/" is the module name;
+#       if the module name matches the module name of the class then
+#       the remaining pattern is matched with the class name.
+#   If there is no "/", the module name is not compared.
+#   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.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/management/remote/mandatory/connection/DefaultAgentFilterTest.java	Thu Sep 14 22:57:36 2017 +0200
@@ -0,0 +1,333 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+ /*
+ * @test
+ * @bug 8159377
+ * @library /lib/testlibrary
+ * @summary Tests ObjectFilter on default agent
+ * @author Harsha Wardhana B
+ * @modules java.management
+ * @build jdk.testlibrary.* DefaultAgentFilterTest
+ * @run main/othervm/timeout=600 -XX:+UsePerfData DefaultAgentFilterTest
+ */
+import java.io.EOFException;
+import java.io.File;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.net.BindException;
+import java.rmi.UnmarshalException;
+import java.rmi.registry.LocateRegistry;
+import java.rmi.registry.Registry;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicBoolean;
+import javax.management.MBeanServerConnection;
+import javax.management.ObjectName;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXServiceURL;
+
+import jdk.testlibrary.ProcessTools;
+import jdk.testlibrary.Utils;
+
+public class DefaultAgentFilterTest {
+
+    public static class MyTestObject implements Serializable {
+
+        String a;
+        int id;
+    }
+
+    public interface TestMBean {
+
+        public void op1(HashSet<Object> params);
+
+        public void op2(String s, HashSet<String> params);
+
+        public void op3(MyTestObject obj, String s, HashMap<String, String> param);
+    }
+
+    public static class Test implements TestMBean {
+
+        @Override
+        public void op1(HashSet<Object> params) {
+            System.out.println("Invoked op1");
+        }
+
+        @Override
+        public void op2(String s, HashSet<String> params) {
+            System.out.println("Invoked op2");
+        }
+
+        @Override
+        public void op3(MyTestObject obj, String s, HashMap<String, String> param) {
+            System.out.println("Invoked op3");
+        }
+    }
+
+    private static class TestAppRun implements AutoCloseable {
+
+        private Process p;
+        private final ProcessBuilder pb;
+        private final String name;
+        private final AtomicBoolean started = new AtomicBoolean(false);
+        private volatile long pid = -1;
+
+        public TestAppRun(ProcessBuilder pb, String name) {
+            this.pb = pb;
+            this.name = name;
+        }
+
+        public synchronized void start() throws Exception {
+            if (started.compareAndSet(false, true)) {
+                try {
+                    AtomicBoolean error = new AtomicBoolean(false);
+                    AtomicBoolean bindError = new AtomicBoolean(false);
+                    p = ProcessTools.startProcess(
+                            TEST_APP_NAME + "{" + name + "}",
+                            pb,
+                            (line) -> {
+                                if (line.toLowerCase().contains("exception")
+                                || line.toLowerCase().contains("error")) {
+                                    error.set(true);
+                                }
+                                bindError.set(line.toLowerCase().contains("bindexception"));
+                                return true;
+                            });
+                    if (bindError.get()) {
+                        throw new BindException("Process could not be started");
+                    } else if (error.get()) {
+                        throw new RuntimeException();
+                    }
+                    pid = p.pid();
+                } catch (Exception ex) {
+                    if (p != null) {
+                        p.destroy();
+                        p.waitFor();
+                    }
+                    throw ex;
+                }
+            }
+        }
+
+        public long getPid() {
+            return pid;
+        }
+
+        public synchronized void stop()
+                throws IOException, InterruptedException {
+            if (started.compareAndSet(true, false)) {
+                p.getOutputStream().write(0);
+                p.getOutputStream().flush();
+                int ec = p.waitFor();
+                if (ec != 0) {
+                    StringBuilder msg = new StringBuilder();
+                    msg.append("Test application '").append(name);
+                    msg.append("' failed with exit code: ");
+                    msg.append(ec);
+                    System.err.println(msg);
+                }
+            }
+        }
+
+        @Override
+        public void close() throws Exception {
+            stop();
+        }
+    }
+
+    private static final String TEST_APP_NAME = "TestApp";
+
+    private static void testDefaultAgent(String propertyFile) throws Exception {
+        int port = Utils.getFreePort();
+        String propFile = System.getProperty("test.src") + File.separator + propertyFile;
+        List<String> pbArgs = new ArrayList<>(Arrays.asList(
+                "-cp",
+                System.getProperty("test.class.path"),
+                "-XX:+UsePerfData"
+        ));
+        String[] args = new String[]{
+            "-Dcom.sun.management.jmxremote.port=" + port,
+            "-Dcom.sun.management.jmxremote.authenticate=false",
+            "-Dcom.sun.management.jmxremote.ssl=false",
+            "-Dcom.sun.management.config.file=" + propFile
+        };
+        pbArgs.addAll(Arrays.asList(args));
+        pbArgs.add(TEST_APP_NAME);
+
+        ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
+                pbArgs.toArray(new String[pbArgs.size()])
+        );
+
+        try (TestAppRun s = new TestAppRun(pb, DefaultAgentFilterTest.class.getSimpleName())) {
+            s.start();
+            JMXServiceURL url = testConnect(port);
+            testMBeanOperations(url);
+        }
+    }
+
+    private static JMXServiceURL testConnect(int port) throws Exception {
+        EOFException lastException = null;
+        JMXServiceURL url = null;
+        // factor adjusted timeout (5 seconds) for the RMI to become available
+        long timeout = System.currentTimeMillis() + Utils.adjustTimeout(5000);
+        do {
+            lastException = null;
+            try {
+                Registry registry = LocateRegistry.getRegistry(port);
+                String[] relist = registry.list();
+                for (int i = 0; i < relist.length; ++i) {
+                    System.out.println("Got registry: " + relist[i]);
+                }
+                String jmxUrlStr = String.format(
+                        "service:jmx:rmi:///jndi/rmi://localhost:%d/jmxrmi",
+                        port);
+                url = new JMXServiceURL(jmxUrlStr);
+
+                try (JMXConnector c = JMXConnectorFactory.connect(url, null)) {
+                    MBeanServerConnection conn = c.getMBeanServerConnection();
+                    ObjectName name = new ObjectName("jtreg:type=Test");
+                    conn.createMBean(Test.class.getName(), name);
+                }
+            } catch (Exception ex) {
+                if (ex instanceof EOFException) {
+                    lastException = (EOFException) ex;
+                    System.out.println("Error establishing RMI connection. Retrying in 500ms.");
+                    Thread.sleep(500);
+                } else {
+                    throw ex;
+                }
+            }
+        } while (lastException != null && System.currentTimeMillis() < timeout);
+        if (lastException != null) {
+            throw lastException;
+        }
+        return url;
+    }
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("---" + DefaultAgentFilterTest.class.getName() + "-main: starting ...");
+
+        boolean retry = false;
+        do {
+            try {
+                // blacklist String
+                testDefaultAgent("mgmt1.properties");
+                System.out.println("----\tTest FAILED !!");
+                throw new RuntimeException("---" + DefaultAgentFilterTest.class.getName() + " - No exception reported");
+            } catch (Exception ex) {
+                if (ex instanceof InvocationTargetException) {
+                    if (ex.getCause() instanceof BindException
+                            || ex.getCause() instanceof java.rmi.ConnectException) {
+                        System.out.println("Failed to allocate ports. Retrying ...");
+                        retry = true;
+                    }
+                } else if (ex instanceof InvalidClassException) {
+                    System.out.println("----\tTest PASSED !!");
+                } else if (ex instanceof UnmarshalException
+                        && ((UnmarshalException) ex).getCause() instanceof InvalidClassException) {
+                    System.out.println("----\tTest PASSED !!");
+                } else {
+                    System.out.println(ex);
+                    System.out.println("----\tTest FAILED !!");
+                    throw ex;
+                }
+            }
+        } while (retry);
+        retry = false;
+        do {
+            try {
+                // blacklist non-existent class
+                testDefaultAgent("mgmt2.properties");
+                System.out.println("----\tTest PASSED !!");
+            } catch (Exception ex) {
+                if (ex instanceof InvocationTargetException) {
+                    if (ex.getCause() instanceof BindException
+                            || ex.getCause() instanceof java.rmi.ConnectException) {
+                        System.out.println("Failed to allocate ports. Retrying ...");
+                        retry = true;
+                    }
+                } else {
+                    System.out.println(ex);
+                    System.out.println("----\tTest FAILED !!");
+                    throw ex;
+                }
+            }
+        } while (retry);
+
+        System.out.println("---" + DefaultAgentFilterTest.class.getName() + "-main: finished ...");
+    }
+
+    private static void testMBeanOperations(JMXServiceURL serverUrl) throws Exception {
+        Map<String, Object> clientEnv = new HashMap<>(1);
+        ObjectName name = new ObjectName("jtreg:type=Test");
+        try (JMXConnector client = JMXConnectorFactory.connect(serverUrl, clientEnv)) {
+            MBeanServerConnection conn = client.getMBeanServerConnection();
+
+            HashSet<String> set = new HashSet<>();
+            set.add("test1");
+            set.add("test2");
+
+            String a = "A";
+
+            Object[] params1 = {set};
+            String[] sig1 = {HashSet.class.getName()};
+            conn.invoke(name, "op1", params1, sig1);
+
+            Object[] params2 = {a, set};
+            String[] sig2 = {String.class.getName(), HashSet.class.getName()};
+            conn.invoke(name, "op2", params2, sig2);
+
+            HashMap<String, String> map = new HashMap<>();
+            map.put("a", "A");
+            map.put("b", "B");
+
+            Object[] params3 = {new MyTestObject(), a, map};
+            String[] sig3 = {MyTestObject.class.getName(), String.class.getName(),
+                HashMap.class.getName()};
+            conn.invoke(name, "op3", params3, sig3);
+        }
+    }
+}
+
+class TestApp {
+
+    private static void doSomething() throws IOException {
+        int r = System.in.read();
+        System.out.println("read: " + r);
+    }
+
+    public static void main(String args[]) throws Exception {
+        System.out.println("main enter");
+        System.out.flush();
+        doSomething();
+        System.out.println("main exit");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/management/remote/mandatory/connection/NewRMIClientFilterTest.java	Thu Sep 14 22:57:36 2017 +0200
@@ -0,0 +1,147 @@
+/*
+ * 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.
+ *
+ * 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.
+ */
+
+ /*
+ * @test
+ * @bug 8159377
+ * @summary Tests ObjectInputFilter on RMIServer.newClient
+ * @author Harsha Wardhana B
+ * @modules java.management
+ * @run clean NewRMIClientFilterTest
+ * @run build NewRMIClientFilterTest
+ * @run main NewRMIClientFilterTest
+ */
+import java.io.InvalidClassException;
+import java.io.Serializable;
+import java.lang.management.ManagementFactory;
+import java.util.HashMap;
+import java.util.Map;
+import javax.management.remote.JMXConnector;
+import javax.management.remote.JMXConnectorFactory;
+import javax.management.remote.JMXConnectorServer;
+import javax.management.remote.JMXConnectorServerFactory;
+import javax.management.remote.JMXServiceURL;
+import javax.management.remote.rmi.RMIConnectorServer;
+
+public class NewRMIClientFilterTest {
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("---NewRMIClientFilterTest-main: starting ...");
+        String filter1 = java.lang.String.class.getName() + ";!*";
+        String filter2 = java.lang.String.class.getName() + ";" + MyCredentials.class.getName() + ";!*";
+
+        JMXServiceURL url = new JMXServiceURL("rmi", null, 0);
+        JMXServiceURL serverUrl = null;
+        Map<String, Object> env = new HashMap<>(1);
+        JMXConnectorServer server = null;
+
+        System.out.println("\n---NewRMIClientFilterTest-main: testing types = null");
+        server = newServer(url, null);
+        serverUrl = server.getAddress();
+        doTest(serverUrl, null);
+        doTest(serverUrl, new String[]{"toto", "titi"});
+        doTest(serverUrl, new Object[]{new MyCredentials(), "toto"});
+        server.stop();
+
+        System.out.println("\n---NewRMIClientFilterTest-main: testing types = String[]");
+        env.put(RMIConnectorServer.CREDENTIALS_FILTER_PATTERN,
+                filter1);
+        server = newServer(url, env);
+        serverUrl = server.getAddress();
+        doTest(serverUrl, null);
+        doTest(serverUrl, new String[]{"toto", "titi"});
+        try {
+            doTest(serverUrl, new MyCredentials());
+            throw new Error("Bad client is not refused!");
+        } catch (Exception e) {
+            isInvalidClassEx(e);
+        } finally {
+            server.stop();
+        }
+
+        System.out.println("\n---NewRMIClientFilterTest-main: testing user specific types = String, MyCredentials");
+        env.put(RMIConnectorServer.CREDENTIALS_FILTER_PATTERN,
+                filter2);
+        server = newServer(url, env);
+        serverUrl = server.getAddress();
+        doTest(serverUrl, null);
+        doTest(serverUrl, new String[]{"toto", "titi"});
+        doTest(serverUrl, new MyCredentials[]{new MyCredentials(), (MyCredentials) null});
+        try {
+            doTest(serverUrl, new Object[]{"toto", new byte[3]});
+            throw new Error("Bad client is not refused!");
+        } catch (Exception e) {
+            isInvalidClassEx(e);
+        } finally {
+            server.stop();
+        }
+
+        System.out.println("---NewRMIClientFilterTest-main PASSED!!!");
+    }
+
+    private static void doTest(JMXServiceURL serverAddr, Object credentials) throws Exception {
+        System.out.println("---NewRMIClientFilterTest-test:\n\tserver address: "
+                + serverAddr + "\n\tcredentials: " + credentials);
+
+        Map<String, Object> env = new HashMap<>(1);
+        env.put("jmx.remote.credentials", credentials);
+        JMXConnector client = null;
+        try {
+            client = JMXConnectorFactory.connect(serverAddr, env);
+            client.getMBeanServerConnection().getDefaultDomain();
+        } finally {
+            try {
+                client.close();
+            } catch (Exception e) {
+            }
+        }
+        System.out.println("---NewRMIClientFilterTest-test: PASSED!");
+    }
+
+    private static JMXConnectorServer newServer(JMXServiceURL url, Map<String, Object> env)
+            throws Exception {
+        JMXConnectorServer server = JMXConnectorServerFactory.newJMXConnectorServer(
+                url,
+                env,
+                ManagementFactory.getPlatformMBeanServer());
+
+        server.start();
+        return server;
+    }
+
+    private static class MyCredentials implements Serializable {
+    }
+
+    private static void isInvalidClassEx(Exception e) {
+        Throwable cause = e;
+        while (cause != null) {
+            if (cause instanceof InvalidClassException) {
+                System.out.println("---NewRMIClientFilterTest-InvalidClassException expected: " + cause);
+                return;
+            }
+            cause = cause.getCause();
+        }
+        e.printStackTrace();
+        throw new RuntimeException("Did not get expected InvalidClassException!");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/management/remote/mandatory/connection/mgmt1.properties	Thu Sep 14 22:57:36 2017 +0200
@@ -0,0 +1,38 @@
+# ################ Filter for ObjectInputStream #############################
+com.sun.management.jmxremote.serial.filter.pattern=!DefaultAgentFilterTest$MyTestObject
+#   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 contains "/", the non-empty prefix up to the "/" is the module name;
+#       if the module name matches the module name of the class then
+#       the remaining pattern is matched with the class name.
+#   If there is no "/", the module name is not compared.
+#   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.
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/javax/management/remote/mandatory/connection/mgmt2.properties	Thu Sep 14 22:57:36 2017 +0200
@@ -0,0 +1,38 @@
+# ################ Filter for ObjectInputStream #############################
+com.sun.management.jmxremote.serial.filter.pattern=!DefaultAgentFilterTest$ThisTypeIsNotUsed
+#   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 contains "/", the non-empty prefix up to the "/" is the module name;
+#       if the module name matches the module name of the class then
+#       the remaining pattern is matched with the class name.
+#   If there is no "/", the module name is not compared.
+#   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.
\ No newline at end of file
--- a/test/jdk/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java	Mon Aug 14 15:32:25 2017 +0530
+++ b/test/jdk/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java	Thu Sep 14 22:57:36 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 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
@@ -47,6 +47,7 @@
 import javax.management.remote.JMXConnectorServerFactory;
 import javax.management.remote.JMXServiceURL;
 import com.sun.jmx.remote.internal.rmi.RMIExporter;
+import java.io.ObjectInputFilter;
 
 public class RMIExporterTest {
 
@@ -60,7 +61,8 @@
         public Remote exportObject(Remote obj,
                                    int port,
                                    RMIClientSocketFactory csf,
-                                   RMIServerSocketFactory ssf)
+                                   RMIServerSocketFactory ssf,
+                                   ObjectInputFilter unused)
             throws RemoteException {
             System.out.println("CustomRMIExporter::exportObject():: " +
                                "Remote = " + obj);