From 3b586b88ab971c554ec32ec0f1f09657107832c4 Mon Sep 17 00:00:00 2001 From: shshahma Date: Fri, 2 Mar 2018 01:03:12 -0800 Subject: [PATCH] 8198662: Incompatible internal API change in JDK8u161: signature of method exportObject() Reviewed-by: dfuchs, robm, jwilhelm, rriggs --- .../sun/jmx/remote/internal/RMIExporter.java | 6 +- .../com/sun/jmx/remote/util/EnvHelp.java | 57 +------ .../classes/java/io/ObjectInputStream.java | 22 +++ .../remote/rmi/RMIConnectorServer.java | 3 +- .../remote/rmi/RMIJRMPServerImpl.java | 148 ++++++++++-------- .../jmxremote/ConnectorBootstrap.java | 33 ++-- .../sun/misc/JavaObjectInputStreamAccess.java | 41 +++++ .../sun/misc/ObjectStreamClassValidator.java | 43 +++++ src/share/classes/sun/misc/SharedSecrets.java | 13 ++ .../sun/rmi/server/MarshalInputStream.java | 38 ++++- .../sun/rmi/server/UnicastServerRef.java | 92 ++++++++++- .../lib/management/management.properties | 35 ----- .../connectorServer/RMIExporterTest.java | 6 +- 13 files changed, 341 insertions(+), 196 deletions(-) create mode 100644 src/share/classes/sun/misc/JavaObjectInputStreamAccess.java create mode 100644 src/share/classes/sun/misc/ObjectStreamClassValidator.java diff --git a/src/share/classes/com/sun/jmx/remote/internal/RMIExporter.java b/src/share/classes/com/sun/jmx/remote/internal/RMIExporter.java index ead4a4d24..8568aa95f 100644 --- a/src/share/classes/com/sun/jmx/remote/internal/RMIExporter.java +++ b/src/share/classes/com/sun/jmx/remote/internal/RMIExporter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -25,7 +25,6 @@ package com.sun.jmx.remote.internal; -import sun.misc.ObjectInputFilter; import java.rmi.NoSuchObjectException; import java.rmi.Remote; import java.rmi.RemoteException; @@ -52,8 +51,7 @@ public interface RMIExporter { public Remote exportObject(Remote obj, int port, RMIClientSocketFactory csf, - RMIServerSocketFactory ssf, - ObjectInputFilter filter) + RMIServerSocketFactory ssf) throws RemoteException; public boolean unexportObject(Remote obj, boolean force) diff --git a/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java b/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java index 8856d6b00..9d924a300 100644 --- a/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java +++ b/src/share/classes/com/sun/jmx/remote/util/EnvHelp.java @@ -1,6 +1,6 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -69,61 +69,6 @@ public class EnvHelp { public static final String CREDENTIAL_TYPES = "jmx.remote.rmi.server.credential.types"; - /** - * Name of the attribute that specifies an - * {@link ObjectInputFilter} pattern string to filter classes acceptable - * for {@link RMIServer#newClient(java.lang.Object) RMIServer.newClient()} - * remote method call. - *

- * The filter pattern must be in same format as used in - * {@link java.io.ObjectInputFilter.Config.createFilter} - *

- * This list of classes allowed by filter should correspond to the - * transitive closure of the credentials class (or classes) used by the - * installed {@linkplain JMXAuthenticator} associated with the - * {@linkplain RMIServer} implementation. - * If the attribute is not set then any class is deemed acceptable. - * @see ObjectInputFilter - */ - public static final String CREDENTIALS_FILTER_PATTERN = - "jmx.remote.rmi.server.credentials.filter.pattern"; - - /** - * This attribute defines a pattern from which to create a - * {@link java.io.ObjectInputFilter} that will be used when deserializing - * objects sent to the {@code JMXConnectorServer} by any client. - *

- * 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. - *

- * To be functional, the filter should allow at least all the - * concrete types in the transitive closure of all objects that - * might get serialized when serializing all JMX classes referred - * as parameters in the {@link - * javax.management.remote.rmi.RMIConnection} interface, - * plus all classes that a {@link javax.management.remote.rmi.RMIConnectorClient} - * might need to transmit wrapped in {@linkplain java.rmi.MarshalledObject - * marshalled objects} in order to interoperate with the MBeans registered - * in the {@code MBeanServer}. That would potentially include all the - * concrete {@linkplain javax.management.openmbean JMX OpenTypes} and the - * classes they use in their serial form. - *

- * 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"; - /** *

Name of the attribute that specifies a default class loader * object. diff --git a/src/share/classes/java/io/ObjectInputStream.java b/src/share/classes/java/io/ObjectInputStream.java index e43d46148..7e173ebd3 100644 --- a/src/share/classes/java/io/ObjectInputStream.java +++ b/src/share/classes/java/io/ObjectInputStream.java @@ -45,6 +45,8 @@ import static java.io.ObjectStreamClass.processQueue; import sun.misc.SharedSecrets; import sun.misc.ObjectInputFilter; +import sun.misc.ObjectStreamClassValidator; +import sun.misc.SharedSecrets; import sun.reflect.misc.ReflectUtil; import sun.misc.JavaOISAccess; import sun.util.logging.PlatformLogger; @@ -1750,6 +1752,9 @@ public class ObjectInputStream throw new StreamCorruptedException( String.format("invalid type code: %02X", tc)); } + if (descriptor != null) { + validateDescriptor(descriptor); + } return descriptor; } @@ -3895,4 +3900,21 @@ public class ObjectInputStream throw new AssertionError(); } } + + private void validateDescriptor(ObjectStreamClass descriptor) { + ObjectStreamClassValidator validating = validator; + if (validating != null) { + validating.validateDescriptor(descriptor); + } + } + + // controlled access to ObjectStreamClassValidator + private volatile ObjectStreamClassValidator validator; + + private static void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator) { + ois.validator = validator; + } + static { + SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::setValidator); + } } diff --git a/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java b/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java index 621bccbc8..4cdb092c6 100644 --- a/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java +++ b/src/share/classes/javax/management/remote/rmi/RMIConnectorServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,7 +33,6 @@ import com.sun.jmx.remote.util.EnvHelp; import java.io.ByteArrayOutputStream; import java.io.IOException; -import sun.misc.ObjectInputFilter; import java.io.ObjectOutputStream; import java.net.MalformedURLException; import java.rmi.server.RMIClientSocketFactory; diff --git a/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java b/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java index c16936b0d..562de79f6 100644 --- a/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java +++ b/src/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -26,7 +26,6 @@ package javax.management.remote.rmi; import java.io.IOException; -import sun.misc.ObjectInputFilter; import java.rmi.NoSuchObjectException; import java.rmi.Remote; import java.rmi.RemoteException; @@ -48,11 +47,6 @@ import sun.reflect.misc.ReflectUtil; import sun.rmi.server.DeserializationChecker; import sun.rmi.server.UnicastServerRef; import sun.rmi.server.UnicastServerRef2; -import java.util.Arrays; -import java.util.Set; -import java.util.stream.Collectors; -import sun.rmi.transport.LiveRef; - /** *

An {@link RMIServer} object that is exported through JRMP and that @@ -65,6 +59,8 @@ import sun.rmi.transport.LiveRef; */ public class RMIJRMPServerImpl extends RMIServerImpl { + private final ExportedWrapper exportedWrapper; + /** *

Creates a new {@link RMIServer} object that will be exported * on the given port using the given socket factories.

@@ -105,37 +101,31 @@ public class RMIJRMPServerImpl extends RMIServerImpl { String[] credentialsTypes = (String[]) this.env.get(EnvHelp.CREDENTIAL_TYPES); - - String credentialsFilter - = (String) this.env.get(EnvHelp.CREDENTIALS_FILTER_PATTERN); - - if(credentialsFilter != null){ - cFilter = ObjectInputFilter.Config.createFilter(credentialsFilter); - allowedTypes = null; - } - 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; + List 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 userJmxFilter = - (String) this.env.get(EnvHelp.SERIAL_FILTER_PATTERN); - if(userJmxFilter != null && !userJmxFilter.isEmpty()) - jmxRmiFilter = ObjectInputFilter.Config.createFilter(userJmxFilter); - else - jmxRmiFilter = null; + exportedWrapper = types != null ? + new ExportedWrapper(this, types) : + null; } protected void export() throws IOException { - export(this, cFilter); + if (exportedWrapper != null) { + export(exportedWrapper); + } else { + export(this); + } } - private void export(Remote obj, ObjectInputFilter typeFilter) throws RemoteException { + private void export(Remote obj) throws RemoteException { final RMIExporter exporter = (RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE); final boolean daemon = EnvHelp.isServerDaemon(env); @@ -146,14 +136,16 @@ public class RMIJRMPServerImpl extends RMIServerImpl { " cannot be used to specify an exporter!"); } - if (exporter != null) { - exporter.exportObject(obj, port, csf, ssf, typeFilter); - } else { + if (daemon) { if (csf == null && ssf == null) { - new UnicastServerRef(new LiveRef(port), typeFilter).exportObject(obj, null, daemon); + new UnicastServerRef(port).exportObject(obj, null, true); } else { - new UnicastServerRef2(port, csf, ssf, typeFilter).exportObject(obj, null, daemon); + new UnicastServerRef2(port, csf, ssf).exportObject(obj, null, true); } + } else if (exporter != null) { + exporter.exportObject(obj, port, csf, ssf); + } else { + UnicastRemoteObject.exportObject(obj, port, csf, ssf); } } @@ -180,7 +172,11 @@ public class RMIJRMPServerImpl extends RMIServerImpl { * RMIJRMPServerImpl has not been exported yet. */ public Remote toStub() throws IOException { - return RemoteObject.toStub(this); + if (exportedWrapper != null) { + return RemoteObject.toStub(exportedWrapper); + } else { + return RemoteObject.toStub(this); + } } /** @@ -210,7 +206,7 @@ public class RMIJRMPServerImpl extends RMIServerImpl { RMIConnection client = new RMIConnectionImpl(this, connectionId, getDefaultClassLoader(), subject, env); - export(client, jmxRmiFilter); + export(client); return client; } @@ -227,38 +223,56 @@ public class RMIJRMPServerImpl extends RMIServerImpl { * server failed. */ protected void closeServer() throws IOException { - 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; + if (exportedWrapper != null) { + unexport(exportedWrapper, true); + } else { + unexport(this, true); } - return status; } + private final int port; private final RMIClientSocketFactory csf; private final RMIServerSocketFactory ssf; private final Map env; - private final Set allowedTypes; - private final ObjectInputFilter jmxRmiFilter; - private final ObjectInputFilter cFilter; + + private static class ExportedWrapper implements RMIServer, DeserializationChecker { + private final RMIServer impl; + private final List allowedTypes; + private ExportedWrapper(RMIServer impl, List credentialsTypes) { + this.impl = impl; + allowedTypes = credentialsTypes; + } + + @Override + public String getVersion() throws RemoteException { + return impl.getVersion(); + } + + @Override + public RMIConnection newClient(Object credentials) throws IOException { + return impl.newClient(credentials); + } + + @Override + public void check(Method method, ObjectStreamClass descriptor, + int paramIndex, int callID) { + + String type = descriptor.getName(); + if (!allowedTypes.contains(type)) { + throw new ClassCastException("Unsupported type: " + type); + } + } + + @Override + public void checkProxyClass(Method method, String[] ifaces, + int paramIndex, int callID) { + if (ifaces != null && ifaces.length > 0) { + for (String iface : ifaces) { + if (!allowedTypes.contains(iface)) { + throw new ClassCastException("Unsupported type: " + iface); + } + } + } + } + } } diff --git a/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java b/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java index 2bde8911b..56287edbd 100644 --- a/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java +++ b/src/share/classes/sun/management/jmxremote/ConnectorBootstrap.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -30,7 +30,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import sun.misc.ObjectInputFilter; +import java.io.Serializable; import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.MalformedURLException; @@ -43,6 +43,7 @@ import java.rmi.RemoteException; import java.rmi.registry.Registry; import java.rmi.server.RMIClientSocketFactory; import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.RMISocketFactory; import java.rmi.server.RemoteObject; import java.rmi.server.UnicastRemoteObject; import java.security.KeyStore; @@ -82,7 +83,6 @@ import sun.management.FileSystem; import sun.rmi.server.UnicastRef; import sun.rmi.server.UnicastServerRef; import sun.rmi.server.UnicastServerRef2; -import sun.rmi.transport.LiveRef; /** * This class initializes and starts the RMIConnectorServer for JSR 163 @@ -141,8 +141,6 @@ public final class ConnectorBootstrap { "com.sun.management.jmxremote.ssl.need.client.auth"; public static final String SSL_CONFIG_FILE_NAME = "com.sun.management.jmxremote.ssl.config.file"; - public static final String SERIAL_FILTER_PATTERN = - "com.sun.management.jmxremote.serial.filter.pattern"; } /** @@ -183,8 +181,7 @@ public final class ConnectorBootstrap { public Remote exportObject(Remote obj, int port, RMIClientSocketFactory csf, - RMIServerSocketFactory ssf, - ObjectInputFilter filter) + RMIServerSocketFactory ssf) throws RemoteException { synchronized (this) { @@ -195,9 +192,9 @@ public final class ConnectorBootstrap { final UnicastServerRef ref; if (csf == null && ssf == null) { - ref = new UnicastServerRef(new LiveRef(port), filter); + ref = new UnicastServerRef(port); } else { - ref = new UnicastServerRef2(port, csf, ssf, filter); + ref = new UnicastServerRef2(port, csf, ssf); } return ref.exportObject(obj, null, true); } @@ -437,7 +434,6 @@ public final class ConnectorBootstrap { final String bindAddress = props.getProperty(PropertyNames.HOST); - final String jmxRmiFilter = props.getProperty(PropertyNames.SERIAL_FILTER_PATTERN); if (log.debugOn()) { log.debug("startRemoteConnectorServer", @@ -474,7 +470,7 @@ public final class ConnectorBootstrap { sslConfigFileName, enabledCipherSuitesList, enabledProtocolsList, sslNeedClientAuth, useAuthentication, loginConfigName, - passwordFileName, accessFileName, bindAddress, jmxRmiFilter); + passwordFileName, accessFileName, bindAddress); cs = data.jmxConnectorServer; url = data.jmxRemoteURL; log.config("startRemoteConnectorServer", @@ -514,7 +510,9 @@ public final class ConnectorBootstrap { // This RMI server should not keep the VM alive Map env = new HashMap<>(); env.put(RMIExporter.EXPORTER_ATTRIBUTE, new PermanentExporter()); - env.put(EnvHelp.CREDENTIALS_FILTER_PATTERN, String.class.getName() + ";!*"); + env.put(EnvHelp.CREDENTIAL_TYPES, new String[]{ + String[].class.getName(), String.class.getName() + }); // The local connector server need only be available via the // loopback connection. @@ -730,8 +728,7 @@ public final class ConnectorBootstrap { String loginConfigName, String passwordFileName, String accessFileName, - String bindAddress, - String jmxRmiFilter) + String bindAddress) throws IOException, MalformedURLException { /* Make sure we use non-guessable RMI object IDs. Otherwise @@ -746,11 +743,9 @@ public final class ConnectorBootstrap { PermanentExporter exporter = new PermanentExporter(); env.put(RMIExporter.EXPORTER_ATTRIBUTE, exporter); - env.put(EnvHelp.CREDENTIALS_FILTER_PATTERN, String.class.getName() + ";!*"); - - if(jmxRmiFilter != null && !jmxRmiFilter.isEmpty()) { - env.put(EnvHelp.SERIAL_FILTER_PATTERN, jmxRmiFilter); - } + env.put(EnvHelp.CREDENTIAL_TYPES, new String[]{ + String[].class.getName(), String.class.getName() + }); boolean useSocketFactory = bindAddress != null && !useSsl; diff --git a/src/share/classes/sun/misc/JavaObjectInputStreamAccess.java b/src/share/classes/sun/misc/JavaObjectInputStreamAccess.java new file mode 100644 index 000000000..8b6a7e152 --- /dev/null +++ b/src/share/classes/sun/misc/JavaObjectInputStreamAccess.java @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.misc; + +import java.io.ObjectInputStream; + +/** + * The interface to specify methods for accessing {@code ObjectInputStream} + * @author sjiang + */ +public interface JavaObjectInputStreamAccess { + /** + * Sets a descriptor validating. + * @param ois stream to have the descriptors validated + * @param validator validator used to validate a descriptor. + */ + public void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator); +} diff --git a/src/share/classes/sun/misc/ObjectStreamClassValidator.java b/src/share/classes/sun/misc/ObjectStreamClassValidator.java new file mode 100644 index 000000000..f98a387db --- /dev/null +++ b/src/share/classes/sun/misc/ObjectStreamClassValidator.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package sun.misc; + +import java.io.ObjectStreamClass; + +/** + * A callback used by {@code ObjectInputStream} to do descriptor validation. + * + * @author sjiang + */ +public interface ObjectStreamClassValidator { + /** + * This method will be called by ObjectInputStream to + * check a descriptor just before creating an object described by this descriptor. + * The object will not be created if this method throws a {@code RuntimeException}. + * @param descriptor descriptor to be checked. + */ + public void validateDescriptor(ObjectStreamClass descriptor); +} diff --git a/src/share/classes/sun/misc/SharedSecrets.java b/src/share/classes/sun/misc/SharedSecrets.java index 5f8ee1b4a..cc3fc642a 100644 --- a/src/share/classes/sun/misc/SharedSecrets.java +++ b/src/share/classes/sun/misc/SharedSecrets.java @@ -59,6 +59,7 @@ public class SharedSecrets { private static JavaAWTAccess javaAWTAccess; private static JavaOISAccess javaOISAccess; private static JavaxCryptoSealedObjectAccess javaxCryptoSealedObjectAccess; + private static JavaObjectInputStreamAccess javaObjectInputStreamAccess; public static JavaUtilJarAccess javaUtilJarAccess() { if (javaUtilJarAccess == null) { @@ -201,6 +202,18 @@ public class SharedSecrets { return javaAWTAccess; } + + public static JavaObjectInputStreamAccess getJavaObjectInputStreamAccess() { + if (javaObjectInputStreamAccess == null) { + unsafe.ensureClassInitialized(ObjectInputStream.class); + } + return javaObjectInputStreamAccess; + } + + public static void setJavaObjectInputStreamAccess(JavaObjectInputStreamAccess access) { + javaObjectInputStreamAccess = access; + } + public static void setJavaxCryptoSealedObjectAccess(JavaxCryptoSealedObjectAccess jcsoa) { javaxCryptoSealedObjectAccess = jcsoa; } diff --git a/src/share/classes/sun/rmi/server/MarshalInputStream.java b/src/share/classes/sun/rmi/server/MarshalInputStream.java index 91be64bc4..ed13d45c2 100644 --- a/src/share/classes/sun/rmi/server/MarshalInputStream.java +++ b/src/share/classes/sun/rmi/server/MarshalInputStream.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,8 @@ import java.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 @@ -51,6 +53,11 @@ import java.rmi.server.RMIClassLoader; * @author Peter Jones */ public class MarshalInputStream extends ObjectInputStream { + interface StreamChecker extends ObjectStreamClassValidator { + void checkProxyInterfaceNames(String[] ifaces); + } + + private volatile StreamChecker streamChecker = null; /** * Value of "java.rmi.server.useCodebaseOnly" property, @@ -237,6 +244,11 @@ public class MarshalInputStream extends ObjectInputStream { protected Class resolveProxyClass(String[] interfaces) throws IOException, ClassNotFoundException { + StreamChecker checker = streamChecker; + if (checker != null) { + checker.checkProxyInterfaceNames(interfaces); + } + /* * Always read annotation written by MarshalOutputStream. */ @@ -318,4 +330,28 @@ public class MarshalInputStream extends ObjectInputStream { void useCodebaseOnly() { useCodebaseOnly = true; } + + synchronized void setStreamChecker(StreamChecker checker) { + streamChecker = checker; + SharedSecrets.getJavaObjectInputStreamAccess().setValidator(this, checker); + } + @Override + protected ObjectStreamClass readClassDescriptor() throws IOException, + ClassNotFoundException { + ObjectStreamClass descriptor = super.readClassDescriptor(); + + validateDesc(descriptor); + + return descriptor; + } + + private void validateDesc(ObjectStreamClass descriptor) { + StreamChecker checker; + synchronized (this) { + checker = streamChecker; + } + if (checker != null) { + checker.validateDescriptor(descriptor); + } + } } diff --git a/src/share/classes/sun/rmi/server/UnicastServerRef.java b/src/share/classes/sun/rmi/server/UnicastServerRef.java index 285dba5e0..d82746030 100644 --- a/src/share/classes/sun/rmi/server/UnicastServerRef.java +++ b/src/share/classes/sun/rmi/server/UnicastServerRef.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 1996, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -29,6 +29,7 @@ import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; +import java.io.ObjectStreamClass; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.rmi.AccessException; @@ -331,15 +332,10 @@ public class UnicastServerRef extends UnicastRef logCall(obj, method); // unmarshal parameters - Class[] types = method.getParameterTypes(); - Object[] params = new Object[types.length]; - + Object[] params = null; try { unmarshalCustomCallData(in); - // Unmarshal the parameters - for (int i = 0; i < types.length; i++) { - params[i] = unmarshalValue(types[i], in); - } + params = unmarshalParameters(obj, method, marshalStream); } catch (AccessException aex) { // For compatibility, AccessException is not wrapped in UnmarshalException @@ -609,4 +605,84 @@ public class UnicastServerRef extends UnicastRef } } + /** + * Unmarshal parameters for the given method of the given instance over + * the given marshalinputstream. Perform any necessary checks. + */ + private Object[] unmarshalParameters(Object obj, Method method, MarshalInputStream in) + throws IOException, ClassNotFoundException { + return (obj instanceof DeserializationChecker) ? + unmarshalParametersChecked((DeserializationChecker)obj, method, in) : + unmarshalParametersUnchecked(method, in); + } + + /** + * Unmarshal parameters for the given method of the given instance over + * the given marshalinputstream. Do not perform any additional checks. + */ + private Object[] unmarshalParametersUnchecked(Method method, ObjectInput in) + throws IOException, ClassNotFoundException { + Class[] types = method.getParameterTypes(); + Object[] params = new Object[types.length]; + for (int i = 0; i < types.length; i++) { + params[i] = unmarshalValue(types[i], in); + } + return params; + } + + /** + * Unmarshal parameters for the given method of the given instance over + * the given marshalinputstream. Do perform all additional checks. + */ + private Object[] unmarshalParametersChecked( + DeserializationChecker checker, + Method method, MarshalInputStream in) + throws IOException, ClassNotFoundException { + int callID = methodCallIDCount.getAndIncrement(); + MyChecker myChecker = new MyChecker(checker, method, callID); + in.setStreamChecker(myChecker); + try { + Class[] types = method.getParameterTypes(); + Object[] values = new Object[types.length]; + for (int i = 0; i < types.length; i++) { + myChecker.setIndex(i); + values[i] = unmarshalValue(types[i], in); + } + myChecker.end(callID); + return values; + } finally { + in.setStreamChecker(null); + } + } + + private static class MyChecker implements MarshalInputStream.StreamChecker { + private final DeserializationChecker descriptorCheck; + private final Method method; + private final int callID; + private int parameterIndex; + + MyChecker(DeserializationChecker descriptorCheck, Method method, int callID) { + this.descriptorCheck = descriptorCheck; + this.method = method; + this.callID = callID; + } + + @Override + public void validateDescriptor(ObjectStreamClass descriptor) { + descriptorCheck.check(method, descriptor, parameterIndex, callID); + } + + @Override + public void checkProxyInterfaceNames(String[] ifaces) { + descriptorCheck.checkProxyClass(method, ifaces, parameterIndex, callID); + } + + void setIndex(int parameterIndex) { + this.parameterIndex = parameterIndex; + } + + void end(int callId) { + descriptorCheck.end(callId); + } + } } diff --git a/src/share/lib/management/management.properties b/src/share/lib/management/management.properties index 6b689e0b3..70efa2eef 100644 --- a/src/share/lib/management/management.properties +++ b/src/share/lib/management/management.properties @@ -329,38 +329,3 @@ # The format of the value for that property is any string accepted # by java.net.InetAddress.getByName(String). # - -# ################ Filter for ObjectInputStream ############################# -# com.sun.management.jmxremote.serial.filter.pattern= -# A filter, if configured, is used by java.io.ObjectInputStream during -# deserialization of parameters sent to the JMX default agent to validate the -# contents of the stream. -# A filter is configured as a sequence of patterns, each pattern is either -# matched against the name of a class in the stream or defines a limit. -# Patterns are separated by ";" (semicolon). -# Whitespace is significant and is considered part of the pattern. -# -# If a pattern includes a "=", it sets a limit. -# If a limit appears more than once the last value is used. -# Limits are checked before classes regardless of the order in the sequence of patterns. -# If any of the limits are exceeded, the filter status is REJECTED. -# -# maxdepth=value - the maximum depth of a graph -# maxrefs=value - the maximum number of internal references -# maxbytes=value - the maximum number of bytes in the input stream -# maxarray=value - the maximum array length allowed -# -# Other patterns, from left to right, match the class or package name as -# returned from Class.getName. -# If the class is an array type, the class or package to be matched is the element type. -# Arrays of any number of dimensions are treated the same as the element type. -# For example, a pattern of "!example.Foo", rejects creation of any instance or -# array of example.Foo. -# -# If the pattern starts with "!", the status is REJECTED if the remaining pattern -# is matched; otherwise the status is ALLOWED if the pattern matches. -# If the pattern ends with ".**" it matches any class in the package and all subpackages. -# If the pattern ends with ".*" it matches any class in the package. -# If the pattern ends with "*", it matches any class with the pattern as a prefix. -# If the pattern is equal to the class name, it matches. -# Otherwise, the status is UNDECIDED. diff --git a/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java b/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java index 4f591572b..2ac2084a6 100644 --- a/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java +++ b/test/javax/management/remote/mandatory/connectorServer/RMIExporterTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2017, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,6 @@ import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import com.sun.jmx.remote.internal.RMIExporter; -import sun.misc.ObjectInputFilter; public class RMIExporterTest { @@ -60,8 +59,7 @@ public class RMIExporterTest { public Remote exportObject(Remote obj, int port, RMIClientSocketFactory csf, - RMIServerSocketFactory ssf, - ObjectInputFilter unused) + RMIServerSocketFactory ssf) throws RemoteException { System.out.println("CustomRMIExporter::exportObject():: " + "Remote = " + obj); -- GitLab