changeset 11606:06c922a192a8 jdk8u76-b06

Merge
author asaha
date Mon, 01 Feb 2016 12:21:39 -0800
parents 0562abe86a70 (current diff) d6b69f2ba2a9 (diff)
children d7abede123c8
files .hgtags
diffstat 14 files changed, 480 insertions(+), 64 deletions(-) [+]
line wrap: on
line diff
--- a/.hgtags	Tue Jan 26 12:39:01 2016 -0800
+++ b/.hgtags	Mon Feb 01 12:21:39 2016 -0800
@@ -534,6 +534,12 @@
 d841d3fdae44f120883dab0a3a809a054cd0274b jdk8u72-b13
 f6d24d424cd2af4d2612f7737d3d9a25f58b882d jdk8u72-b14
 f3e86cc607260bae368b52d88d7bc8883ee767e3 jdk8u72-b15
+892eb9ab179650b89b7bab6bc42f079391c98624 jdk8u73-b00
+9b77d3ca0d66a117c3cc0e0a74b8059545b22f0e jdk8u73-b01
+2ab13901d6f14bab0dcf4823d5e378a421fba7e2 jdk8u73-b02
+9a843dc6f959f62c61014a3a71ec9aa329f1daf1 jdk8u74-b00
+e829ab80dfd828803aa8837411900faeaa1254a5 jdk8u74-b01
+32c49f4a16599e376e4e46bb33c7bcc486e52ff3 jdk8u74-b02
 1d4b343084874b1afa1cdd504b9b1e50bab7f121 jdk8u72-b31
 7cfd2c51c501df909833aa0fb6e40c50c61621ed jdk8u75-b00
 9e00a43602f87930c2318b2567002871ad9c59dd jdk8u75-b01
@@ -541,6 +547,7 @@
 dcacefa73649a2d821267b6bff1d70aa10a06801 jdk8u75-b03
 de91f05824c5398cb2d2f666ff404aaa165498de jdk8u75-b04
 4138b3f27ffea524185a604c3f4f149c7e5ba780 jdk8u75-b05
+32f64c19b5fba8beeae5236ca6e480bd8e99698a jdk8u75-b06
 39baa472e20c13c0eb1243eb5dce589e82f78143 jdk8u76-b00
 6ea3aea950d19d803475b3f4d704a2942e71b302 jdk8u76-b01
 4de4cffb5988cd68959ce4bbd14c6d4547078c91 jdk8u76-b02
--- a/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java	Tue Jan 26 12:39:01 2016 -0800
+++ b/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java	Mon Feb 01 12:21:39 2016 -0800
@@ -1,6 +1,6 @@
 
 /*
- * 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
@@ -55,6 +55,21 @@
 public class EnvHelp {
 
     /**
+    * Name of the attribute that specifies a list of class names acceptable
+    * as parameters to the {@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.
+    * <p>
+    * If the attribute is not set, or is null, then any class is
+    * deemed acceptable.
+    */
+    public static final String CREDENTIAL_TYPES =
+            "jmx.remote.rmi.server.credential.types";
+
+    /**
      * <p>Name of the attribute that specifies a default class loader
      * object.
      * The value associated with this attribute is a ClassLoader object</p>
--- a/src/share/classes/java/io/ObjectInputStream.java	Tue Jan 26 12:39:01 2016 -0800
+++ b/src/share/classes/java/io/ObjectInputStream.java	Mon Feb 01 12:21:39 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, 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
@@ -39,8 +39,10 @@
 import java.util.HashMap;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
-import java.util.concurrent.atomic.AtomicBoolean;
 import static java.io.ObjectStreamClass.processQueue;
+import sun.misc.ObjectStreamClassValidator;
+import sun.misc.SharedSecrets;
+import sun.misc.Unsafe;
 import sun.reflect.misc.ReflectUtil;
 
 /**
@@ -1504,23 +1506,28 @@
         throws IOException
     {
         byte tc = bin.peekByte();
+        ObjectStreamClass descriptor;
         switch (tc) {
             case TC_NULL:
-                return (ObjectStreamClass) readNull();
-
+                descriptor = (ObjectStreamClass) readNull();
+                break;
             case TC_REFERENCE:
-                return (ObjectStreamClass) readHandle(unshared);
-
+                descriptor = (ObjectStreamClass) readHandle(unshared);
+                break;
             case TC_PROXYCLASSDESC:
-                return readProxyDesc(unshared);
-
+                descriptor = readProxyDesc(unshared);
+                break;
             case TC_CLASSDESC:
-                return readNonProxyDesc(unshared);
-
+                descriptor = readNonProxyDesc(unshared);
+                break;
             default:
                 throw new StreamCorruptedException(
                     String.format("invalid type code: %02X", tc));
         }
+        if (descriptor != null) {
+            validateDescriptor(descriptor);
+        }
+        return descriptor;
     }
 
     private boolean isCustomSubclass() {
@@ -1933,7 +1940,7 @@
                     defaultDataEnd = false;
                 } else {
                     defaultReadFields(obj, slotDesc);
-                }
+                    }
 
                 if (slotDesc.hasWriteObjectData()) {
                     skipCustomData();
@@ -1949,7 +1956,7 @@
                 }
             }
         }
-    }
+            }
 
     /**
      * Skips over all block data and objects until TC_ENDBLOCKDATA is
@@ -1997,27 +2004,27 @@
         if (primVals == null || primVals.length < primDataSize) {
             primVals = new byte[primDataSize];
         }
-        bin.readFully(primVals, 0, primDataSize, false);
+            bin.readFully(primVals, 0, primDataSize, false);
         if (obj != null) {
             desc.setPrimFieldValues(obj, primVals);
         }
 
-        int objHandle = passHandle;
-        ObjectStreamField[] fields = desc.getFields(false);
+            int objHandle = passHandle;
+            ObjectStreamField[] fields = desc.getFields(false);
         Object[] objVals = new Object[desc.getNumObjFields()];
-        int numPrimFields = fields.length - objVals.length;
-        for (int i = 0; i < objVals.length; i++) {
-            ObjectStreamField f = fields[numPrimFields + i];
-            objVals[i] = readObject0(f.isUnshared());
-            if (f.getField() != null) {
-                handles.markDependency(objHandle, passHandle);
+            int numPrimFields = fields.length - objVals.length;
+            for (int i = 0; i < objVals.length; i++) {
+                ObjectStreamField f = fields[numPrimFields + i];
+                objVals[i] = readObject0(f.isUnshared());
+                if (f.getField() != null) {
+                    handles.markDependency(objHandle, passHandle);
+                }
             }
-        }
         if (obj != null) {
             desc.setObjFieldValues(obj, objVals);
         }
-        passHandle = objHandle;
-    }
+            passHandle = objHandle;
+        }
 
     /**
      * Reads in and returns IOException that caused serialization to abort.
@@ -3554,4 +3561,20 @@
         }
     }
 
+    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/share/classes/java/security/ProtectionDomain.java	Tue Jan 26 12:39:01 2016 -0800
+++ b/src/share/classes/java/security/ProtectionDomain.java	Mon Feb 01 12:21:39 2016 -0800
@@ -475,11 +475,6 @@
                         }
                     };
                 }
-
-                @Override
-                public boolean getStaticPermissionsField(ProtectionDomain pd) {
-                    return pd.staticPermissions;
-                }
             });
     }
 }
--- a/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java	Tue Jan 26 12:39:01 2016 -0800
+++ b/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java	Mon Feb 01 12:21:39 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2007, 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
@@ -39,6 +39,12 @@
 
 import com.sun.jmx.remote.internal.RMIExporter;
 import com.sun.jmx.remote.util.EnvHelp;
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import sun.reflect.misc.ReflectUtil;
+import sun.rmi.server.DeserializationChecker;
 import sun.rmi.server.UnicastServerRef;
 import sun.rmi.server.UnicastServerRef2;
 
@@ -52,6 +58,9 @@
  * @since 1.5
  */
 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>
@@ -89,10 +98,31 @@
         this.csf = csf;
         this.ssf = ssf;
         this.env = (env == null) ? Collections.<String, Object>emptyMap() : env;
+
+        String[] credentialsTypes
+                = (String[]) this.env.get(EnvHelp.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);
+            }
+        }
+        exportedWrapper = types != null ?
+                new ExportedWrapper(this, types) :
+                null;
     }
 
     protected void export() throws IOException {
-        export(this);
+        if (exportedWrapper != null) {
+            export(exportedWrapper);
+        } else {
+            export(this);
+        }
     }
 
     private void export(Remote obj) throws RemoteException {
@@ -142,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);
+        }
     }
 
     /**
@@ -189,11 +223,56 @@
      * server failed.
      */
     protected void closeServer() throws IOException {
-        unexport(this, true);
+        if (exportedWrapper != null) {
+            unexport(exportedWrapper, true);
+        } else {
+            unexport(this, true);
+        }
     }
 
     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);
+                    }
+                }
+            }
+        }
+    }
 }
--- a/src/share/classes/javax/security/auth/SubjectDomainCombiner.java	Tue Jan 26 12:39:01 2016 -0800
+++ b/src/share/classes/javax/security/auth/SubjectDomainCombiner.java	Mon Feb 01 12:21:39 2016 -0800
@@ -37,8 +37,6 @@
 import java.util.Set;
 import java.util.WeakHashMap;
 import java.lang.ref.WeakReference;
-import sun.misc.SharedSecrets;
-import sun.misc.JavaSecurityProtectionDomainAccess;
 
 /**
  * A {@code SubjectDomainCombiner} updates ProtectionDomains
@@ -67,9 +65,6 @@
     private static final boolean allowCaching =
                                         (useJavaxPolicy && cachePolicy());
 
-    private static final JavaSecurityProtectionDomainAccess pdAccess =
-        SharedSecrets.getJavaSecurityProtectionDomainAccess();
-
     /**
      * Associate the provided {@code Subject} with this
      * {@code SubjectDomainCombiner}.
@@ -244,15 +239,10 @@
                 subjectPd = cachedPDs.getValue(pd);
 
                 if (subjectPd == null) {
-                    if (pdAccess.getStaticPermissionsField(pd)) {
-                        // Need to keep static ProtectionDomain objects static
-                        subjectPd = pd;
-                    } else {
-                        subjectPd = new ProtectionDomain(pd.getCodeSource(),
+                    subjectPd = new ProtectionDomain(pd.getCodeSource(),
                                                 pd.getPermissions(),
                                                 pd.getClassLoader(),
                                                 principals);
-                    }
                     cachedPDs.putValue(pd, subjectPd);
                 } else {
                     allNew = false;
--- a/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java	Tue Jan 26 12:39:01 2016 -0800
+++ b/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java	Mon Feb 01 12:21:39 2016 -0800
@@ -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
@@ -46,7 +46,6 @@
 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;
@@ -68,6 +67,7 @@
 import com.sun.jmx.remote.internal.RMIExporter;
 import com.sun.jmx.remote.security.JMXPluggableAuthenticator;
 import com.sun.jmx.remote.util.ClassLogger;
+import com.sun.jmx.remote.util.EnvHelp;
 
 import sun.management.Agent;
 import sun.management.AgentConfigurationError;
@@ -498,6 +498,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.CREDENTIAL_TYPES, new String[]{
+            String[].class.getName(), String.class.getName()
+        });
 
         // The local connector server need only be available via the
         // loopback connection.
@@ -726,6 +729,9 @@
         PermanentExporter exporter = new PermanentExporter();
 
         env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
+        env.put(EnvHelp.CREDENTIAL_TYPES, new String[]{
+            String[].class.getName(), String.class.getName()
+        });
 
         if (useAuthentication) {
             if (loginConfigName != null) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/misc/JavaObjectInputStreamAccess.java	Mon Feb 01 12:21:39 2016 -0800
@@ -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);
+}
--- a/src/share/classes/sun/misc/JavaSecurityProtectionDomainAccess.java	Tue Jan 26 12:39:01 2016 -0800
+++ b/src/share/classes/sun/misc/JavaSecurityProtectionDomainAccess.java	Mon Feb 01 12:21:39 2016 -0800
@@ -36,9 +36,4 @@
      * Returns the ProtectionDomainCache.
      */
     ProtectionDomainCache getProtectionDomainCache();
-
-    /**
-     * Returns the staticPermissions field of the specified object
-     */
-    boolean getStaticPermissionsField(ProtectionDomain pd);
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/misc/ObjectStreamClassValidator.java	Mon Feb 01 12:21:39 2016 -0800
@@ -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);
+}
--- a/src/share/classes/sun/misc/SharedSecrets.java	Tue Jan 26 12:39:01 2016 -0800
+++ b/src/share/classes/sun/misc/SharedSecrets.java	Mon Feb 01 12:21:39 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002, 2013, 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
@@ -28,6 +28,7 @@
 import java.util.jar.JarFile;
 import java.io.Console;
 import java.io.FileDescriptor;
+import java.io.ObjectInputStream;
 import java.security.ProtectionDomain;
 
 import java.security.AccessController;
@@ -55,6 +56,7 @@
     private static JavaSecurityAccess javaSecurityAccess;
     private static JavaUtilZipFileAccess javaUtilZipFileAccess;
     private static JavaAWTAccess javaAWTAccess;
+    private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
 
     public static JavaUtilJarAccess javaUtilJarAccess() {
         if (javaUtilJarAccess == null) {
@@ -184,4 +186,15 @@
         }
         return javaAWTAccess;
     }
+
+    public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() {
+        if (javaObjectInputStreamAccess == null) {
+            unsafe.ensureClassInitialized(ObjectInputStream.class);
+        }
+        return javaObjectInputStreamAccess;
+    }
+
+    public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) {
+        javaObjectInputStreamAccess = access;
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/rmi/server/DeserializationChecker.java	Mon Feb 01 12:21:39 2016 -0800
@@ -0,0 +1,93 @@
+/*
+ * 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.rmi.server;
+
+import java.io.ObjectStreamClass;
+import java.lang.reflect.Method;
+
+/**
+ * Implementing this interface to have a deserialization control when RMI
+ * dispatches a remote request. If an exported object implements this interface,
+ * RMI dispatching mechanism will call the method {@code check} every time
+ * deserialising a remote object for invoking a method of the exported object.
+ *
+ * @author sjiang
+ */
+public interface DeserializationChecker {
+    /**
+     * Will be called to check a descriptor.
+     * This method may be called 2 times, the first time is when a descriptor is read
+     * from the stream, the second is just before creating an object described
+     * by this descriptor.
+     *
+     * @param method the method invoked from a remote request.
+     * @param descriptor The descriptor of the class of any object deserialised
+     *  while deserialising the parameter. The first descriptor will be that of
+     *  the top level object (the concrete class of the parameter itself);
+     *  Subsequent calls with the same {@code method}, {@code paramIndex} and
+     *  {@code callID} will correspond to objects contained in the parameter.
+     * @param paramIndex an index indicates the position of a parameter in the
+     * method. This index will be reused for deserialising all
+     * objects contained in the parameter object. For example, the parameter
+     * being deserialised is a {@code List}, all deserialisation calls for its
+     * elements will have same index.
+     * @param callID a unique ID identifying one
+     * time method invocation, the same ID is used for deserialization call of
+     * all parameters within the method.
+     */
+    public void check(Method method,
+            ObjectStreamClass descriptor,
+            int paramIndex,
+            int callID);
+
+    /**
+     * Will be called to validate a Proxy interfaces from a remote user before loading it.
+     * @param method the method invoked from a remote request.
+     * @param ifaces a string table of all interfaces implemented by the proxy to be checked.
+     * @param paramIndex an index indicates the position of a parameter in the
+     * method. This index will be reused for deserialising all
+     * objects contained in the parameter object. For example, the parameter
+     * being deserialised is a {@code List}, all deserialisation calls for its
+     * elements will have same index.
+     * @param callID a unique ID identifying one
+     * time method invocation, the same ID is used for deserialization call of
+     * all parameters within the method.
+     */
+    public void checkProxyClass(Method method,
+            String[] ifaces,
+            int paramIndex,
+            int callID);
+
+    /**
+     * Inform of the completion of parameter deserialisation for a method invocation.
+     * This is useful if the last parameter is a complex  object, like a {@code List}
+     * which elements are complex object too.
+     *
+     * The default implementation does nothing.
+     * @param callID the ID identifying a method invocation.
+     */
+    public default void end(int callID) {}
+}
--- a/src/share/classes/sun/rmi/server/MarshalInputStream.java	Tue Jan 26 12:39:01 2016 -0800
+++ b/src/share/classes/sun/rmi/server/MarshalInputStream.java	Mon Feb 01 12:21:39 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, 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
@@ -30,12 +30,12 @@
 import java.io.ObjectInputStream;
 import java.io.ObjectStreamClass;
 import java.io.StreamCorruptedException;
-import java.net.URL;
 import java.util.*;
 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
@@ -53,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,
@@ -122,7 +127,7 @@
         throws IOException, StreamCorruptedException
     {
         super(in);
-    }
+                    }
 
     /**
      * Returns a callback previously registered via the setDoneCallback
@@ -239,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 +328,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);
+        }
+    }
 }
--- a/src/share/classes/sun/rmi/server/UnicastServerRef.java	Tue Jan 26 12:39:01 2016 -0800
+++ b/src/share/classes/sun/rmi/server/UnicastServerRef.java	Mon Feb 01 12:21:39 2016 -0800
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1996, 2013, 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
@@ -28,7 +28,7 @@
 import java.io.IOException;
 import java.io.ObjectInput;
 import java.io.ObjectOutput;
-import java.io.PrintStream;
+import java.io.ObjectStreamClass;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.rmi.MarshalException;
@@ -52,7 +52,9 @@
 import java.util.HashMap;
 import java.util.Map;
 import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
 import sun.rmi.runtime.Log;
+import static sun.rmi.server.UnicastRef.marshalValue;
 import sun.rmi.transport.LiveRef;
 import sun.rmi.transport.Target;
 import sun.rmi.transport.tcp.TCPTransport;
@@ -118,6 +120,8 @@
     private static final Map<Class<?>,?> withoutSkeletons =
         Collections.synchronizedMap(new WeakHashMap<Class<?>,Void>());
 
+    private final AtomicInteger methodCallIDCount = new AtomicInteger(0);
+
     /**
      * Create a new (empty) Unicast server remote reference.
      */
@@ -299,14 +303,11 @@
             logCall(obj, method);
 
             // unmarshal parameters
-            Class<?>[] types = method.getParameterTypes();
-            Object[] params = new Object[types.length];
+            Object[] params = null;
 
             try {
                 unmarshalCustomCallData(in);
-                for (int i = 0; i < types.length; i++) {
-                    params[i] = unmarshalValue(types[i], in);
-                }
+                params = unmarshalParameters(obj, method, marshalStream);
             } catch (java.io.IOException e) {
                 throw new UnmarshalException(
                     "error unmarshalling arguments", e);
@@ -567,4 +568,85 @@
             return map;
         }
     }
+
+    /**
+     * 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);
+        }
+    }
 }