diff -r 3a00eb4636e3 -r 96179f26139e src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java --- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java Mon Aug 14 15:32:25 2017 +0530 +++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java Thu Sep 14 22:57:36 2017 +0200 @@ -26,6 +26,7 @@ package javax.management.remote.rmi; import java.io.IOException; +import java.io.ObjectInputFilter; import java.rmi.NoSuchObjectException; import java.rmi.Remote; import java.rmi.RemoteException; @@ -39,15 +40,13 @@ import com.sun.jmx.remote.internal.rmi.RMIExporter; import com.sun.jmx.remote.util.EnvHelp; -import java.io.ObjectStreamClass; -import java.lang.reflect.Method; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; import sun.reflect.misc.ReflectUtil; -import sun.rmi.server.DeserializationChecker; import sun.rmi.server.UnicastServerRef; import sun.rmi.server.UnicastServerRef2; +import sun.rmi.transport.LiveRef; /** *

An {@link RMIServer} object that is exported through JRMP and that @@ -60,8 +59,6 @@ */ 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.

@@ -100,33 +97,48 @@ this.ssf = ssf; this.env = (env == null) ? Collections.emptyMap() : env; + // This attribute was represented by RMIConnectorServer.CREDENTIALS_TYPES. + // This attribute is superceded by + // RMIConnectorServer.CREDENTIALS_FILTER_PATTERN. + // Retaining this for backward compatibility. String[] credentialsTypes - = (String[]) this.env.get(RMIConnectorServer.CREDENTIAL_TYPES); - List types = null; - if (credentialsTypes != null) { - types = new ArrayList<>(); - for (String type : credentialsTypes) { - if (type == null) { - throw new IllegalArgumentException("A credential type is null."); - } - ReflectUtil.checkPackageAccess(type); - types.add(type); - } + = (String[]) this.env.get("jmx.remote.rmi.server.credential.types"); + + String credentialsFilter + = (String) this.env.get(RMIConnectorServer.CREDENTIALS_FILTER_PATTERN); + + // It is impossible for both attributes to be specified + if(credentialsTypes != null && credentialsFilter != null) + throw new IllegalArgumentException("Cannot specify both \"" + + "jmx.remote.rmi.server.credential.types" + "\" and \"" + + RMIConnectorServer.CREDENTIALS_FILTER_PATTERN + "\""); + else if(credentialsFilter != null){ + cFilter = ObjectInputFilter.Config.createFilter(credentialsFilter); + allowedTypes = null; } - exportedWrapper = types != null ? - new ExportedWrapper(this, types) : - null; + else if (credentialsTypes != null) { + allowedTypes = Arrays.stream(credentialsTypes).filter( + s -> s!= null).collect(Collectors.toSet()); + allowedTypes.stream().forEach(ReflectUtil::checkPackageAccess); + cFilter = this::newClientCheckInput; + } else { + allowedTypes = null; + cFilter = null; + } + + String userJmxFilter = + (String) this.env.get(RMIConnectorServer.SERIAL_FILTER_PATTERN); + if(userJmxFilter != null && !userJmxFilter.isEmpty()) + jmxRmiFilter = ObjectInputFilter.Config.createFilter(userJmxFilter); + else + jmxRmiFilter = null; } protected void export() throws IOException { - if (exportedWrapper != null) { - export(exportedWrapper); - } else { - export(this); - } + export(this, cFilter); } - private void export(Remote obj) throws RemoteException { + private void export(Remote obj, ObjectInputFilter typeFilter) throws RemoteException { final RMIExporter exporter = (RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE); final boolean daemon = EnvHelp.isServerDaemon(env); @@ -137,16 +149,14 @@ " cannot be used to specify an exporter!"); } - if (daemon) { + if (exporter != null) { + exporter.exportObject(obj, port, csf, ssf, typeFilter); + } else { if (csf == null && ssf == null) { - new UnicastServerRef(port).exportObject(obj, null, true); + new UnicastServerRef(new LiveRef(port), typeFilter).exportObject(obj, null, daemon); } else { - new UnicastServerRef2(port, csf, ssf).exportObject(obj, null, true); + new UnicastServerRef2(port, csf, ssf, typeFilter).exportObject(obj, null, daemon); } - } else if (exporter != null) { - exporter.exportObject(obj, port, csf, ssf); - } else { - UnicastRemoteObject.exportObject(obj, port, csf, ssf); } } @@ -173,11 +183,7 @@ * RMIJRMPServerImpl has not been exported yet. */ public Remote toStub() throws IOException { - if (exportedWrapper != null) { - return RemoteObject.toStub(exportedWrapper); - } else { - return RemoteObject.toStub(this); - } + return RemoteObject.toStub(this); } /** @@ -207,7 +213,7 @@ RMIConnection client = new RMIConnectionImpl(this, connectionId, getDefaultClassLoader(), subject, env); - export(client); + export(client, jmxRmiFilter); return client; } @@ -224,56 +230,39 @@ * server failed. */ protected void closeServer() throws IOException { - if (exportedWrapper != null) { - unexport(exportedWrapper, true); - } else { - unexport(this, true); + unexport(this, true); + } + + /** + * Check that a type in the remote invocation of {@link RMIServerImpl#newClient} + * is one of the {@code allowedTypes}. + * + * @param clazz the class; may be null + * @param size the size for arrays, otherwise is 0 + * @param nObjectRefs the current number of object references + * @param depth the current depth + * @param streamBytes the current number of bytes consumed + * @return {@code ObjectInputFilter.Status.ALLOWED} if the class is allowed, + * otherwise {@code ObjectInputFilter.Status.REJECTED} + */ + ObjectInputFilter.Status newClientCheckInput(ObjectInputFilter.FilterInfo filterInfo) { + ObjectInputFilter.Status status = ObjectInputFilter.Status.UNDECIDED; + if (allowedTypes != null && filterInfo.serialClass() != null) { + // If enabled, check type + String type = filterInfo.serialClass().getName(); + if (allowedTypes.contains(type)) + status = ObjectInputFilter.Status.ALLOWED; + else + status = ObjectInputFilter.Status.REJECTED; } + return status; } private final int port; private final RMIClientSocketFactory csf; private final RMIServerSocketFactory ssf; private final Map env; - - 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); - } - } - } - } - } + private final Set allowedTypes; + private final ObjectInputFilter jmxRmiFilter; + private final ObjectInputFilter cFilter; }