--- a/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java Wed Jan 20 20:51:45 2016 +0000
+++ b/jdk/src/java.base/share/classes/java/io/ObjectInputStream.java Fri Jan 22 13:27:09 2016 +0100
@@ -40,6 +40,9 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import static java.io.ObjectStreamClass.processQueue;
+import jdk.internal.misc.JavaObjectInputStreamAccess;
+import jdk.internal.misc.ObjectStreamClassValidator;
+import jdk.internal.misc.SharedSecrets;
import jdk.internal.misc.Unsafe;
import sun.reflect.misc.ReflectUtil;
@@ -1509,23 +1512,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() {
@@ -3658,4 +3666,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);
+ }
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/JavaObjectInputStreamAccess.java Fri Jan 22 13:27:09 2016 +0100
@@ -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 jdk.internal.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);
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/ObjectStreamClassValidator.java Fri Jan 22 13:27:09 2016 +0100
@@ -0,0 +1,42 @@
+/*
+ * 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 jdk.internal.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/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Wed Jan 20 20:51:45 2016 +0000
+++ b/jdk/src/java.base/share/classes/jdk/internal/misc/SharedSecrets.java Fri Jan 22 13:27:09 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, 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
@@ -29,9 +29,9 @@
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;
-import jdk.internal.misc.Unsafe;
/** A repository of "shared secrets", which are a mechanism for
calling implementation-private methods in another package without
@@ -63,6 +63,7 @@
private static JavaAWTAccess javaAWTAccess;
private static JavaAWTFontAccess javaAWTFontAccess;
private static JavaBeansAccess javaBeansAccess;
+ private static JavaObjectInputStreamAccess javaObjectInputStreamAccess;
public static JavaUtilJarAccess javaUtilJarAccess() {
if (javaUtilJarAccess == null) {
@@ -262,4 +263,15 @@
public static void setJavaUtilResourceBundleAccess(JavaUtilResourceBundleAccess access) {
javaUtilResourceBundleAccess = access;
}
+
+ public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() {
+ if (javaObjectInputStreamAccess == null) {
+ unsafe.ensureClassInitialized(ObjectInputStream.class);
+ }
+ return javaObjectInputStreamAccess;
+ }
+
+ public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) {
+ javaObjectInputStreamAccess = access;
+ }
}
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java Wed Jan 20 20:51:45 2016 +0000
+++ b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIConnectorServer.java Fri Jan 22 13:27:09 2016 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002, 2015, 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
@@ -45,6 +45,7 @@
import javax.management.InstanceNotFoundException;
import javax.management.MBeanServer;
+import javax.management.remote.JMXAuthenticator;
import javax.management.remote.JMXConnectionNotification;
import javax.management.remote.JMXConnector;
@@ -100,6 +101,21 @@
"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()}
+ * 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>Makes an <code>RMIConnectorServer</code>.
* This is equivalent to calling {@link #RMIConnectorServer(
* JMXServiceURL,Map,RMIServerImpl,MBeanServer)
--- a/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java Wed Jan 20 20:51:45 2016 +0000
+++ b/jdk/src/java.management/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java Fri Jan 22 13:27:09 2016 +0100
@@ -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,13 @@
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.Arrays;
+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 +59,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 +99,31 @@
this.csf = csf;
this.ssf = ssf;
this.env = (env == null) ? Collections.<String, Object>emptyMap() : env;
+
+ 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);
+ }
+ }
+ 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 +173,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 +224,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/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java Wed Jan 20 20:51:45 2016 +0000
+++ b/jdk/src/java.management/share/classes/sun/management/jmxremote/ConnectorBootstrap.java Fri Jan 22 13:27:09 2016 +0100
@@ -510,6 +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(RMIConnectorServer.CREDENTIAL_TYPES, new String[]{
+ String[].class.getName(), String.class.getName()
+ });
// The local connector server need only be available via the
// loopback connection.
@@ -740,6 +743,9 @@
PermanentExporter exporter = new PermanentExporter();
env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter);
+ env.put(RMIConnectorServer.CREDENTIAL_TYPES, new String[]{
+ String[].class.getName(), String.class.getName()
+ });
boolean useSocketFactory = bindAddress != null && !useSsl;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/DeserializationChecker.java Fri Jan 22 13:27:09 2016 +0100
@@ -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/jdk/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java Wed Jan 20 20:51:45 2016 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/MarshalInputStream.java Fri Jan 22 13:27:09 2016 +0100
@@ -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,13 +30,13 @@
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 java.security.PrivilegedAction;
+import jdk.internal.misc.ObjectStreamClassValidator;
+import jdk.internal.misc.SharedSecrets;
/**
* MarshalInputStream is an extension of ObjectInputStream. When resolving
@@ -54,6 +54,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,
@@ -123,7 +128,7 @@
throws IOException, StreamCorruptedException
{
super(in);
- }
+ }
/**
* Returns a callback previously registered via the setDoneCallback
@@ -240,6 +245,11 @@
protected Class<?> resolveProxyClass(String[] interfaces)
throws IOException, ClassNotFoundException
{
+ StreamChecker checker = streamChecker;
+ if (checker != null) {
+ checker.checkProxyInterfaceNames(interfaces);
+ }
+
/*
* Always read annotation written by MarshalOutputStream.
*/
@@ -319,4 +329,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/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java Wed Jan 20 20:51:45 2016 +0000
+++ b/jdk/src/java.rmi/share/classes/sun/rmi/server/UnicastServerRef.java Fri Jan 22 13:27:09 2016 +0100
@@ -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,6 +52,7 @@
import java.util.HashMap;
import java.util.Map;
import java.util.WeakHashMap;
+import java.util.concurrent.atomic.AtomicInteger;
import sun.rmi.runtime.Log;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.Target;
@@ -116,6 +117,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.
*/
@@ -297,14 +300,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);
@@ -565,4 +565,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);
+ }
+ }
}