8344394: Remove SecurityManager and related calls from java.management.rmi

Reviewed-by: amenkov
This commit is contained in:
Kevin Walls 2024-11-28 17:16:41 +00:00
parent 3b21a298c2
commit fd742af0b7
4 changed files with 113 additions and 239 deletions

View file

@ -315,7 +315,6 @@ module java.base {
exports sun.reflect.misc to exports sun.reflect.misc to
java.desktop, java.desktop,
java.management, java.management,
java.management.rmi,
java.rmi, java.rmi,
java.sql.rowset; java.sql.rowset;
exports sun.security.internal.interfaces to exports sun.security.internal.interfaces to

View file

@ -29,24 +29,17 @@ import java.io.IOException;
import java.rmi.MarshalledObject; import java.rmi.MarshalledObject;
import java.rmi.UnmarshalException; import java.rmi.UnmarshalException;
import java.rmi.server.Unreferenced; import java.rmi.server.Unreferenced;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.Permission;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.PrivilegedActionException; import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.CompletionException;
import javax.management.*; import javax.management.*;
import javax.management.remote.JMXServerErrorException; import javax.management.remote.JMXServerErrorException;
import javax.management.remote.NotificationResult; import javax.management.remote.NotificationResult;
import javax.security.auth.Subject; import javax.security.auth.Subject;
import sun.reflect.misc.ReflectUtil;
import static javax.management.remote.rmi.RMIConnector.Util.cast; import static javax.management.remote.rmi.RMIConnector.Util.cast;
import com.sun.jmx.remote.internal.ServerCommunicatorAdmin; import com.sun.jmx.remote.internal.ServerCommunicatorAdmin;
@ -94,7 +87,6 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
* <code>RMIServerImpl</code>. Can be null, equivalent to an * <code>RMIServerImpl</code>. Can be null, equivalent to an
* empty map. * empty map.
*/ */
@SuppressWarnings("removal")
public RMIConnectionImpl(RMIServerImpl rmiServer, public RMIConnectionImpl(RMIServerImpl rmiServer,
String connectionId, String connectionId,
ClassLoader defaultClassLoader, ClassLoader defaultClassLoader,
@ -111,54 +103,13 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
this.mbeanServer = rmiServer.getMBeanServer(); this.mbeanServer = rmiServer.getMBeanServer();
final ClassLoader dcl = defaultClassLoader; final ClassLoader dcl = defaultClassLoader;
ClassLoaderRepository repository = mbeanServer.getClassLoaderRepository();
ClassLoaderRepository repository = AccessController.doPrivileged( classLoaderWithRepository = new ClassLoaderWithRepository(repository, dcl);
new PrivilegedAction<ClassLoaderRepository>() { defaultContextClassLoader = new CombinedClassLoader(Thread.currentThread().getContextClassLoader(), dcl);
public ClassLoaderRepository run() { serverCommunicatorAdmin = new RMIServerCommunicatorAdmin(EnvHelp.getServerConnectionTimeout(env));
return mbeanServer.getClassLoaderRepository();
}
},
withPermissions(new MBeanPermission("*", "getClassLoaderRepository"))
);
this.classLoaderWithRepository = AccessController.doPrivileged(
new PrivilegedAction<ClassLoaderWithRepository>() {
public ClassLoaderWithRepository run() {
return new ClassLoaderWithRepository(
repository,
dcl);
}
},
withPermissions(new RuntimePermission("createClassLoader"))
);
this.defaultContextClassLoader =
AccessController.doPrivileged(
new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return new CombinedClassLoader(Thread.currentThread().getContextClassLoader(),
dcl);
}
});
serverCommunicatorAdmin = new
RMIServerCommunicatorAdmin(EnvHelp.getServerConnectionTimeout(env));
this.env = env; this.env = env;
} }
@SuppressWarnings("removal")
private static AccessControlContext withPermissions(Permission ... perms){
Permissions col = new Permissions();
for (Permission thePerm : perms ) {
col.add(thePerm);
}
final ProtectionDomain pd = new ProtectionDomain(null, col);
return new AccessControlContext( new ProtectionDomain[] { pd });
}
private synchronized ServerNotifForwarder getServerNotifFwd() { private synchronized ServerNotifForwarder getServerNotifFwd() {
// Lazily created when first use. Mainly when // Lazily created when first use. Mainly when
// addNotificationListener is first called. // addNotificationListener is first called.
@ -397,7 +348,7 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
+", unwrapping params with MBean extended ClassLoader."); +", unwrapping params with MBean extended ClassLoader.");
values = nullIsEmpty(unwrap(params, values = nullIsEmpty(unwrap(params,
getClassLoader(loaderName), mbeanServer.getClassLoader(loaderName),
defaultClassLoader, defaultClassLoader,
Object[].class,delegationSubject)); Object[].class,delegationSubject));
@ -1249,7 +1200,6 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
} }
} }
@SuppressWarnings("removal")
public NotificationResult fetchNotifications(long clientSequenceNumber, public NotificationResult fetchNotifications(long clientSequenceNumber,
int maxNotifications, int maxNotifications,
long timeout) long timeout)
@ -1274,19 +1224,22 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
+ "returns null to force the client to stop fetching"); + "returns null to force the client to stop fetching");
return null; return null;
} }
final long csn = clientSequenceNumber;
final int mn = maxNotifications;
final long t = timeout;
PrivilegedAction<NotificationResult> action =
new PrivilegedAction<NotificationResult>() {
public NotificationResult run() {
return getServerNotifFwd().fetchNotifs(csn, t, mn);
}
};
if (subject == null) { if (subject == null) {
return action.run(); return getServerNotifFwd().fetchNotifs(clientSequenceNumber, timeout, maxNotifications);
} else { } else {
return Subject.doAs(subject, action); try {
return Subject.callAs(subject, () -> getServerNotifFwd().fetchNotifs(clientSequenceNumber, timeout, maxNotifications));
} catch (CompletionException ce) {
Throwable thr = ce.getCause();
if (thr instanceof SecurityException se) {
throw se;
} else if (thr instanceof IOException ioe) {
throw ioe;
} else {
throw new RuntimeException(thr);
}
}
} }
} finally { } finally {
serverCommunicatorAdmin.rspOutgoing(); serverCommunicatorAdmin.rspOutgoing();
@ -1311,25 +1264,6 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
// private classes // private classes
//------------------------------------------------------------------------ //------------------------------------------------------------------------
private class PrivilegedOperation
implements PrivilegedExceptionAction<Object> {
public PrivilegedOperation(int operation, Object[] params) {
this.operation = operation;
this.params = params;
}
public Object run() throws Exception {
return doOperation(operation, params);
}
private int operation;
private Object[] params;
}
//------------------------------------------------------------------------
// private classes
//------------------------------------------------------------------------
private class RMIServerCommunicatorAdmin extends ServerCommunicatorAdmin { private class RMIServerCommunicatorAdmin extends ServerCommunicatorAdmin {
public RMIServerCommunicatorAdmin(long timeout) { public RMIServerCommunicatorAdmin(long timeout) {
super(timeout); super(timeout);
@ -1352,44 +1286,13 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
// private methods // private methods
//------------------------------------------------------------------------ //------------------------------------------------------------------------
@SuppressWarnings("removal")
private ClassLoader getClassLoader(final ObjectName name)
throws InstanceNotFoundException {
try {
return
AccessController.doPrivileged(
new PrivilegedExceptionAction<ClassLoader>() {
public ClassLoader run() throws InstanceNotFoundException {
return mbeanServer.getClassLoader(name);
}
},
withPermissions(new MBeanPermission("*", "getClassLoader"))
);
} catch (PrivilegedActionException pe) {
throw (InstanceNotFoundException) extractException(pe);
}
}
@SuppressWarnings("removal")
private ClassLoader getClassLoaderFor(final ObjectName name) private ClassLoader getClassLoaderFor(final ObjectName name)
throws InstanceNotFoundException { throws InstanceNotFoundException {
try {
return (ClassLoader) return mbeanServer.getClassLoaderFor(name);
AccessController.doPrivileged(
new PrivilegedExceptionAction<Object>() {
public Object run() throws InstanceNotFoundException {
return mbeanServer.getClassLoaderFor(name);
}
},
withPermissions(new MBeanPermission("*", "getClassLoaderFor"))
);
} catch (PrivilegedActionException pe) {
throw (InstanceNotFoundException) extractException(pe);
}
} }
/** @throws UnsupportedOperationException {@inheritDoc} */ /** @throws UnsupportedOperationException {@inheritDoc} */
@SuppressWarnings("removal")
private Object doPrivilegedOperation(final int operation, private Object doPrivilegedOperation(final int operation,
final Object[] params, final Object[] params,
final Subject delegationSubject) final Subject delegationSubject)
@ -1402,10 +1305,9 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
} }
serverCommunicatorAdmin.reqIncoming(); serverCommunicatorAdmin.reqIncoming();
try { try {
PrivilegedOperation op = new PrivilegedOperation(operation, params);
if (subject == null) { if (subject == null) {
try { try {
return op.run(); return doOperation(operation, params);
} catch (Exception e) { } catch (Exception e) {
if (e instanceof RuntimeException) { if (e instanceof RuntimeException) {
throw (RuntimeException) e; throw (RuntimeException) e;
@ -1414,7 +1316,20 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
} }
} }
} else { } else {
return Subject.doAs(subject, op); try {
return Subject.callAs(subject, () -> doOperation(operation, params));
} catch (CompletionException ce) {
Throwable thr = ce.getCause();
if (thr instanceof SecurityException se) {
throw se;
} else if (thr instanceof IOException ioe) {
throw ioe;
} else if (thr instanceof Exception e1) {
throw new PrivilegedActionException(e1);
} else {
throw new RuntimeException(thr);
}
}
} }
} catch (Error e) { } catch (Error e) {
throw new JMXServerErrorException(e.toString(),e); throw new JMXServerErrorException(e.toString(),e);
@ -1545,24 +1460,15 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
} }
} }
private static class SetCcl implements PrivilegedExceptionAction<ClassLoader> { private static ClassLoader setCcl(ClassLoader classLoader) {
private final ClassLoader classLoader; Thread currentThread = Thread.currentThread();
ClassLoader old = currentThread.getContextClassLoader();
SetCcl(ClassLoader classLoader) { if (classLoader != old) {
this.classLoader = classLoader; currentThread.setContextClassLoader(classLoader);
}
public ClassLoader run() {
Thread currentThread = Thread.currentThread();
ClassLoader old = currentThread.getContextClassLoader();
if (classLoader != old) {
currentThread.setContextClassLoader(classLoader);
}
return old;
} }
return old;
} }
@SuppressWarnings("removal")
private <T> T unwrap(final MarshalledObject<?> mo, private <T> T unwrap(final MarshalledObject<?> mo,
final ClassLoader cl, final ClassLoader cl,
final Class<T> wrappedClass, final Class<T> wrappedClass,
@ -1578,32 +1484,33 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
return null; return null;
} }
try { try {
final ClassLoader old = AccessController.doPrivileged(new SetCcl(cl)); ClassLoader old = setCcl(cl);
try { try {
if (subject != null) { if (subject != null) {
return Subject.doAs(subject, (PrivilegedExceptionAction<T>) () -> wrappedClass.cast(mo.get())); try {
return Subject.callAs(subject, () -> wrappedClass.cast(mo.get()));
} catch (CompletionException ce) {
Throwable thr = ce.getCause();
if (thr instanceof Exception e) {
throw e;
} else {
throw new RuntimeException(thr);
}
}
} else { } else {
return wrappedClass.cast(mo.get()); return wrappedClass.cast(mo.get());
} }
} finally { } finally {
AccessController.doPrivileged(new SetCcl(old)); setCcl(old);
} }
} catch (PrivilegedActionException pe) { } catch (Exception e) {
Exception e = extractException(pe);
if (e instanceof IOException) { if (e instanceof IOException) {
throw (IOException) e; throw (IOException) e;
} }
if (e instanceof ClassNotFoundException) {
throw new UnmarshalException(e.toString(), e);
}
logger.warning("unwrap", "Failed to unmarshall object: " + e); logger.warning("unwrap", "Failed to unmarshall object: " + e);
logger.debug("unwrap", e); logger.debug("unwrap", e);
}catch (ClassNotFoundException ex) { throw new UnmarshalException(e.toString(), e);
logger.warning("unwrap", "Failed to unmarshall object: " + ex);
logger.debug("unwrap", ex);
throw new UnmarshalException(ex.toString(), ex);
} }
return null;
} }
private <T> T unwrap(final MarshalledObject<?> mo, private <T> T unwrap(final MarshalledObject<?> mo,
@ -1616,18 +1523,10 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
return null; return null;
} }
try { try {
@SuppressWarnings("removal") ClassLoader orderCL = new CombinedClassLoader(Thread.currentThread().getContextClassLoader(),
ClassLoader orderCL = AccessController.doPrivileged( new OrderClassLoaders(cl1, cl2));
new PrivilegedExceptionAction<ClassLoader>() {
public ClassLoader run() throws Exception {
return new CombinedClassLoader(Thread.currentThread().getContextClassLoader(),
new OrderClassLoaders(cl1, cl2));
}
}
);
return unwrap(mo, orderCL, wrappedClass,delegationSubject); return unwrap(mo, orderCL, wrappedClass,delegationSubject);
} catch (PrivilegedActionException pe) { } catch (Exception e) {
Exception e = extractException(pe);
if (e instanceof IOException) { if (e instanceof IOException) {
throw (IOException) e; throw (IOException) e;
} }
@ -1815,7 +1714,6 @@ public class RMIConnectionImpl implements RMIConnection, Unreferenced {
@Override @Override
protected Class<?> loadClass(String name, boolean resolve) protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException { throws ClassNotFoundException {
ReflectUtil.checkPackageAccess(name);
try { try {
super.loadClass(name, resolve); super.loadClass(name, resolve);
} catch(Exception e) { } catch(Exception e) {

View file

@ -54,9 +54,6 @@ import java.rmi.server.RMIClientSocketFactory;
import java.rmi.server.RemoteObject; import java.rmi.server.RemoteObject;
import java.rmi.server.RemoteObjectInvocationHandler; import java.rmi.server.RemoteObjectInvocationHandler;
import java.rmi.server.RemoteRef; import java.rmi.server.RemoteRef;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.PrivilegedExceptionAction;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
@ -102,7 +99,6 @@ import javax.naming.NamingException;
import javax.rmi.ssl.SslRMIClientSocketFactory; import javax.rmi.ssl.SslRMIClientSocketFactory;
import javax.security.auth.Subject; import javax.security.auth.Subject;
import jdk.internal.module.Modules; import jdk.internal.module.Modules;
import sun.reflect.misc.ReflectUtil;
import sun.rmi.server.UnicastRef2; import sun.rmi.server.UnicastRef2;
import sun.rmi.transport.LiveRef; import sun.rmi.transport.LiveRef;
import java.io.NotSerializableException; import java.io.NotSerializableException;
@ -1856,7 +1852,6 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
protected Class<?> resolveClass(ObjectStreamClass classDesc) protected Class<?> resolveClass(ObjectStreamClass classDesc)
throws IOException, ClassNotFoundException { throws IOException, ClassNotFoundException {
String name = classDesc.getName(); String name = classDesc.getName();
ReflectUtil.checkPackageAccess(name);
return Class.forName(name, false, Objects.requireNonNull(loader)); return Class.forName(name, false, Objects.requireNonNull(loader));
} }
@ -1964,51 +1959,7 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
"\4\0\1\0\14\0\0"; "\4\0\1\0\14\0\0";
final byte[] pRefByteCode = final byte[] pRefByteCode =
NoCallStackClassLoader.stringToBytes(pRefByteCodeString); NoCallStackClassLoader.stringToBytes(pRefByteCodeString);
PrivilegedExceptionAction<Constructor<?>> action =
new PrivilegedExceptionAction<Constructor<?>>() {
public Constructor<?> run() throws Exception {
Class<RMIConnector> thisClass = RMIConnector.class;
ClassLoader thisLoader = thisClass.getClassLoader();
ProtectionDomain thisProtectionDomain =
thisClass.getProtectionDomain();
String proxyRefCName = ProxyRef.class.getName();
ClassLoader cl =
new NoCallStackClassLoader(pRefClassName,
pRefByteCode,
new String[] { proxyRefCName },
thisLoader,
thisProtectionDomain);
Module jmxModule = ProxyRef.class.getModule();
Module rmiModule = RemoteRef.class.getModule();
String pkg = packageOf(pRefClassName);
assert pkg != null && pkg.length() > 0 &&
!pkg.equals(packageOf(proxyRefCName));
ModuleDescriptor descriptor =
ModuleDescriptor.newModule("jdk.remoteref", Set.of(SYNTHETIC))
.packages(Set.of(pkg))
.build();
Module m = Modules.defineModule(cl, descriptor, null);
// jdk.remoteref needs to read to java.base and jmxModule
Modules.addReads(m, Object.class.getModule());
Modules.addReads(m, jmxModule);
Modules.addReads(m, rmiModule);
// jdk.remoteref needs access to ProxyRef class
Modules.addExports(jmxModule, packageOf(proxyRefCName), m);
// java.management needs to instantiate the fabricated RemoteRef class
Modules.addReads(jmxModule, m);
Modules.addExports(m, pkg, jmxModule);
Class<?> c = cl.loadClass(pRefClassName);
return c.getConstructor(RemoteRef.class);
}
};
Class<?> serverStubClass; Class<?> serverStubClass;
try { try {
@ -2026,9 +1977,48 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
Constructor<?> constr; Constructor<?> constr;
try { try {
stubClass = Class.forName(rmiConnectionImplStubClassName); stubClass = Class.forName(rmiConnectionImplStubClassName);
@SuppressWarnings("removal")
Constructor<?> tmp = (Constructor<?>) AccessController.doPrivileged(action); Class<RMIConnector> thisClass = RMIConnector.class;
constr = tmp; ClassLoader thisLoader = thisClass.getClassLoader();
ProtectionDomain thisProtectionDomain =
thisClass.getProtectionDomain();
String proxyRefCName = ProxyRef.class.getName();
ClassLoader cl =
new NoCallStackClassLoader(pRefClassName,
pRefByteCode,
new String[] { proxyRefCName },
thisLoader,
thisProtectionDomain);
Module jmxModule = ProxyRef.class.getModule();
Module rmiModule = RemoteRef.class.getModule();
String pkg = packageOf(pRefClassName);
assert pkg != null && pkg.length() > 0 &&
!pkg.equals(packageOf(proxyRefCName));
ModuleDescriptor descriptor =
ModuleDescriptor.newModule("jdk.remoteref", Set.of(SYNTHETIC))
.packages(Set.of(pkg))
.build();
Module m = Modules.defineModule(cl, descriptor, null);
// jdk.remoteref needs to read to java.base and jmxModule
Modules.addReads(m, Object.class.getModule());
Modules.addReads(m, jmxModule);
Modules.addReads(m, rmiModule);
// jdk.remoteref needs access to ProxyRef class
Modules.addExports(jmxModule, packageOf(proxyRefCName), m);
// java.management needs to instantiate the fabricated RemoteRef class
Modules.addReads(jmxModule, m);
Modules.addExports(m, pkg, jmxModule);
Class<?> c = cl.loadClass(pRefClassName);
constr = c.getConstructor(RemoteRef.class);
} catch (Exception e) { } catch (Exception e) {
logger.error("<clinit>", logger.error("<clinit>",
"Failed to initialize proxy reference constructor "+ "Failed to initialize proxy reference constructor "+
@ -2172,33 +2162,22 @@ public class RMIConnector implements JMXConnector, Serializable, JMXAddressable
//-------------------------------------------------------------------- //--------------------------------------------------------------------
// Private stuff - Find / Set default class loader // Private stuff - Find / Set default class loader
//-------------------------------------------------------------------- //--------------------------------------------------------------------
@SuppressWarnings("removal")
private ClassLoader pushDefaultClassLoader() { private ClassLoader pushDefaultClassLoader() {
final Thread t = Thread.currentThread(); final Thread t = Thread.currentThread();
final ClassLoader old = t.getContextClassLoader(); final ClassLoader old = t.getContextClassLoader();
if (defaultClassLoader != null) if (defaultClassLoader != null) {
AccessController.doPrivileged(new PrivilegedAction<Void>() { if (t.getContextClassLoader() != defaultClassLoader) {
public Void run() { t.setContextClassLoader(defaultClassLoader);
if (t.getContextClassLoader() != defaultClassLoader) { }
t.setContextClassLoader(defaultClassLoader); }
} return old;
return null;
}
});
return old;
} }
@SuppressWarnings("removal")
private void popDefaultClassLoader(final ClassLoader old) { private void popDefaultClassLoader(final ClassLoader old) {
AccessController.doPrivileged(new PrivilegedAction<Void>() { Thread t = Thread.currentThread();
public Void run() { if (t.getContextClassLoader() != old) {
Thread t = Thread.currentThread(); t.setContextClassLoader(old);
if (t.getContextClassLoader() != old) { }
t.setContextClassLoader(old);
}
return null;
}
});
} }
//-------------------------------------------------------------------- //--------------------------------------------------------------------

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2002, 2022, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2002, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* *
* This code is free software; you can redistribute it and/or modify it * This code is free software; you can redistribute it and/or modify it
@ -43,7 +43,6 @@ import com.sun.jmx.remote.util.EnvHelp;
import java.util.Arrays; import java.util.Arrays;
import java.util.Set; import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import sun.reflect.misc.ReflectUtil;
import sun.rmi.server.UnicastServerRef; import sun.rmi.server.UnicastServerRef;
import sun.rmi.server.UnicastServerRef2; import sun.rmi.server.UnicastServerRef2;
import sun.rmi.transport.LiveRef; import sun.rmi.transport.LiveRef;
@ -119,7 +118,6 @@ public class RMIJRMPServerImpl extends RMIServerImpl {
else if (credentialsTypes != null) { else if (credentialsTypes != null) {
allowedTypes = Arrays.stream(credentialsTypes).filter( allowedTypes = Arrays.stream(credentialsTypes).filter(
s -> s!= null).collect(Collectors.toSet()); s -> s!= null).collect(Collectors.toSet());
allowedTypes.forEach(ReflectUtil::checkPackageAccess);
cFilter = this::newClientCheckInput; cFilter = this::newClientCheckInput;
} else { } else {
allowedTypes = null; allowedTypes = null;