提交 5f58b081 编写于 作者: R robm

8174770: Check registry registration location

Reviewed-by: rriggs
上级 4df780ba
...@@ -78,13 +78,6 @@ $(eval $(call SetupRMICompilation,RMI_12, \ ...@@ -78,13 +78,6 @@ $(eval $(call SetupRMICompilation,RMI_12, \
RUN_V12 := true)) RUN_V12 := true))
GENCLASSES += $(RMI_12) GENCLASSES += $(RMI_12)
$(eval $(call SetupRMICompilation,RMI_11, \
CLASSES := sun.rmi.registry.RegistryImpl, \
CLASSES_DIR := $(CLASSES_DIR), \
STUB_CLASSES_DIR := $(STUB_CLASSES_DIR), \
RUN_V11 := true))
GENCLASSES += $(RMI_11)
# For RMI/IIOP call rmic a second time with -standardPackage option # For RMI/IIOP call rmic a second time with -standardPackage option
# so that *_tie classes are generated in package without the prefix # so that *_tie classes are generated in package without the prefix
# org.omg.stub (6375696) # org.omg.stub (6375696)
...@@ -111,7 +104,7 @@ GENCLASSES += $(filter %.java, $(RMI_SRC)) ...@@ -111,7 +104,7 @@ GENCLASSES += $(filter %.java, $(RMI_SRC))
########################################################################################## ##########################################################################################
$(RMI_12) $(RMI_11) $(RMI_IIOP) $(RMI_SRC): $(BUILD_BOOTSTRAP_RMIC) $(RMI_12) $(RMI_IIOP) $(RMI_SRC): $(BUILD_BOOTSTRAP_RMIC)
$(RMIC_GENSRC_DIR)/_the.classes.removed: $(GENCLASSES) $(RMIC_GENSRC_DIR)/_the.classes.removed: $(GENCLASSES)
$(FIND) $(RMIC_GENSRC_DIR) -name "*.class" $(FIND_DELETE) $(FIND) $(RMIC_GENSRC_DIR) -name "*.class" $(FIND_DELETE)
......
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
package sun.management.jmxremote; package sun.management.jmxremote;
import sun.misc.ObjectInputFilter;
import java.rmi.AccessException; import java.rmi.AccessException;
import java.rmi.NotBoundException; import java.rmi.NotBoundException;
import java.rmi.Remote; import java.rmi.Remote;
...@@ -56,7 +57,7 @@ public class SingleEntryRegistry extends RegistryImpl { ...@@ -56,7 +57,7 @@ public class SingleEntryRegistry extends RegistryImpl {
String name, String name,
Remote object) Remote object)
throws RemoteException { throws RemoteException {
super(port, csf, ssf); super(port, csf, ssf, SingleEntryRegistry::singleRegistryFilter);
this.name = name; this.name = name;
this.object = object; this.object = object;
} }
...@@ -84,6 +85,23 @@ public class SingleEntryRegistry extends RegistryImpl { ...@@ -84,6 +85,23 @@ public class SingleEntryRegistry extends RegistryImpl {
throw new AccessException("Cannot modify this registry"); throw new AccessException("Cannot modify this registry");
} }
/**
* ObjectInputFilter to check parameters to SingleEntryRegistry.
* Since it is a read-only Registry, no classes are accepted.
* String arguments are accepted without passing them to the serialFilter.
*
* @param info a reference to the serialization filter information
* @return Status.REJECTED if parameters are out of range
*/
private static ObjectInputFilter.Status singleRegistryFilter(ObjectInputFilter.FilterInfo info) {
return (info.serialClass() != null ||
info.depth() > 2 ||
info.references() > 4 ||
info.arrayLength() >= 0)
? ObjectInputFilter.Status.REJECTED
: ObjectInputFilter.Status.ALLOWED;
}
private final String name; private final String name;
private final Remote object; private final Remote object;
......
...@@ -69,6 +69,10 @@ import sun.rmi.transport.LiveRef; ...@@ -69,6 +69,10 @@ import sun.rmi.transport.LiveRef;
* registry. * registry.
* *
* The LocateRegistry class is used to obtain registry for different hosts. * The LocateRegistry class is used to obtain registry for different hosts.
* <p>
* The default RegistryImpl exported restricts access to clients on the local host
* for the methods {@link #bind}, {@link #rebind}, {@link #unbind} by checking
* the client host in the skeleton.
* *
* @see java.rmi.registry.LocateRegistry * @see java.rmi.registry.LocateRegistry
*/ */
...@@ -136,6 +140,20 @@ public class RegistryImpl extends java.rmi.server.RemoteServer ...@@ -136,6 +140,20 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
RMIClientSocketFactory csf, RMIClientSocketFactory csf,
RMIServerSocketFactory ssf) RMIServerSocketFactory ssf)
throws RemoteException throws RemoteException
{
this(port, csf, ssf, RegistryImpl::registryFilter);
}
/**
* Construct a new RegistryImpl on the specified port with the
* given custom socket factory pair and ObjectInputFilter.
*/
public RegistryImpl(int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf,
ObjectInputFilter serialFilter)
throws RemoteException
{ {
if (port == Registry.REGISTRY_PORT && System.getSecurityManager() != null) { if (port == Registry.REGISTRY_PORT && System.getSecurityManager() != null) {
// grant permission for default port only. // grant permission for default port only.
...@@ -143,7 +161,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer ...@@ -143,7 +161,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
public Void run() throws RemoteException { public Void run() throws RemoteException {
LiveRef lref = new LiveRef(id, port, csf, ssf); LiveRef lref = new LiveRef(id, port, csf, ssf);
setup(new UnicastServerRef2(lref, RegistryImpl::registryFilter)); setup(new UnicastServerRef2(lref, serialFilter));
return null; return null;
} }
}, null, new SocketPermission("localhost:"+port, "listen,accept")); }, null, new SocketPermission("localhost:"+port, "listen,accept"));
...@@ -219,7 +237,8 @@ public class RegistryImpl extends java.rmi.server.RemoteServer ...@@ -219,7 +237,8 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
public void bind(String name, Remote obj) public void bind(String name, Remote obj)
throws RemoteException, AlreadyBoundException, AccessException throws RemoteException, AlreadyBoundException, AccessException
{ {
checkAccess("Registry.bind"); // The access check preventing remote access is done in the skeleton
// and is not applicable to local access.
synchronized (bindings) { synchronized (bindings) {
Remote curr = bindings.get(name); Remote curr = bindings.get(name);
if (curr != null) if (curr != null)
...@@ -236,7 +255,8 @@ public class RegistryImpl extends java.rmi.server.RemoteServer ...@@ -236,7 +255,8 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
public void unbind(String name) public void unbind(String name)
throws RemoteException, NotBoundException, AccessException throws RemoteException, NotBoundException, AccessException
{ {
checkAccess("Registry.unbind"); // The access check preventing remote access is done in the skeleton
// and is not applicable to local access.
synchronized (bindings) { synchronized (bindings) {
Remote obj = bindings.get(name); Remote obj = bindings.get(name);
if (obj == null) if (obj == null)
...@@ -252,7 +272,8 @@ public class RegistryImpl extends java.rmi.server.RemoteServer ...@@ -252,7 +272,8 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
public void rebind(String name, Remote obj) public void rebind(String name, Remote obj)
throws RemoteException, AccessException throws RemoteException, AccessException
{ {
checkAccess("Registry.rebind"); // The access check preventing remote access is done in the skeleton
// and is not applicable to local access.
bindings.put(name, obj); bindings.put(name, obj);
} }
...@@ -279,7 +300,6 @@ public class RegistryImpl extends java.rmi.server.RemoteServer ...@@ -279,7 +300,6 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
* The client must be on same the same host as this server. * The client must be on same the same host as this server.
*/ */
public static void checkAccess(String op) throws AccessException { public static void checkAccess(String op) throws AccessException {
try { try {
/* /*
* Get client host that this registry operation was made from. * Get client host that this registry operation was made from.
...@@ -305,7 +325,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer ...@@ -305,7 +325,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
if (clientHost.isAnyLocalAddress()) { if (clientHost.isAnyLocalAddress()) {
throw new AccessException( throw new AccessException(
"Registry." + op + " disallowed; origin unknown"); op + " disallowed; origin unknown");
} }
try { try {
...@@ -328,7 +348,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer ...@@ -328,7 +348,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
// must have been an IOException // must have been an IOException
throw new AccessException( throw new AccessException(
"Registry." + op + " disallowed; origin " + op + " disallowed; origin " +
clientHost + " is non-local host"); clientHost + " is non-local host");
} }
} }
...@@ -337,8 +357,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer ...@@ -337,8 +357,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
* Local call from this VM: allow access. * Local call from this VM: allow access.
*/ */
} catch (java.net.UnknownHostException ex) { } catch (java.net.UnknownHostException ex) {
throw new AccessException("Registry." + op + throw new AccessException(op + " disallowed; origin is unknown host");
" disallowed; origin is unknown host");
} }
} }
......
/*
* Copyright (c) 2017, 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.registry;
import java.io.IOException;
import java.io.InputStream;
import java.rmi.AccessException;
import java.rmi.server.RemoteCall;
import sun.rmi.transport.Connection;
import sun.rmi.transport.StreamRemoteCall;
import sun.rmi.transport.tcp.TCPConnection;
/**
* Skeleton to dispatch RegistryImpl methods.
* Originally generated by RMIC but frozen to match the stubs.
*/
@SuppressWarnings({"deprecation", "serial"})
public final class RegistryImpl_Skel
implements java.rmi.server.Skeleton {
private static final java.rmi.server.Operation[] operations = {
new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote)"),
new java.rmi.server.Operation("java.lang.String list()[]"),
new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String)"),
new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote)"),
new java.rmi.server.Operation("void unbind(java.lang.String)")
};
private static final long interfaceHash = 4905912898345647071L;
public java.rmi.server.Operation[] getOperations() {
return operations.clone();
}
public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash)
throws java.lang.Exception {
if (hash != interfaceHash)
throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch");
sun.rmi.registry.RegistryImpl server = (sun.rmi.registry.RegistryImpl) obj;
switch (opnum) {
case 0: // bind(String, Remote)
{
// Check access before reading the arguments
RegistryImpl.checkAccess("Registry.bind");
java.lang.String $param_String_1;
java.rmi.Remote $param_Remote_2;
try {
java.io.ObjectInput in = call.getInputStream();
$param_String_1 = (java.lang.String) in.readObject();
$param_Remote_2 = (java.rmi.Remote) in.readObject();
} catch (java.io.IOException | java.lang.ClassNotFoundException e) {
throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
} finally {
call.releaseInputStream();
}
server.bind($param_String_1, $param_Remote_2);
try {
call.getResultStream(true);
} catch (java.io.IOException e) {
throw new java.rmi.MarshalException("error marshalling return", e);
}
break;
}
case 1: // list()
{
call.releaseInputStream();
java.lang.String[] $result = server.list();
try {
java.io.ObjectOutput out = call.getResultStream(true);
out.writeObject($result);
} catch (java.io.IOException e) {
throw new java.rmi.MarshalException("error marshalling return", e);
}
break;
}
case 2: // lookup(String)
{
java.lang.String $param_String_1;
try {
java.io.ObjectInput in = call.getInputStream();
$param_String_1 = (java.lang.String) in.readObject();
} catch (java.io.IOException | java.lang.ClassNotFoundException e) {
throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
} finally {
call.releaseInputStream();
}
java.rmi.Remote $result = server.lookup($param_String_1);
try {
java.io.ObjectOutput out = call.getResultStream(true);
out.writeObject($result);
} catch (java.io.IOException e) {
throw new java.rmi.MarshalException("error marshalling return", e);
}
break;
}
case 3: // rebind(String, Remote)
{
// Check access before reading the arguments
RegistryImpl.checkAccess("Registry.rebind");
java.lang.String $param_String_1;
java.rmi.Remote $param_Remote_2;
try {
java.io.ObjectInput in = call.getInputStream();
$param_String_1 = (java.lang.String) in.readObject();
$param_Remote_2 = (java.rmi.Remote) in.readObject();
} catch (java.io.IOException | java.lang.ClassNotFoundException e) {
throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
} finally {
call.releaseInputStream();
}
server.rebind($param_String_1, $param_Remote_2);
try {
call.getResultStream(true);
} catch (java.io.IOException e) {
throw new java.rmi.MarshalException("error marshalling return", e);
}
break;
}
case 4: // unbind(String)
{
// Check access before reading the arguments
RegistryImpl.checkAccess("Registry.unbind");
java.lang.String $param_String_1;
try {
java.io.ObjectInput in = call.getInputStream();
$param_String_1 = (java.lang.String) in.readObject();
} catch (java.io.IOException | java.lang.ClassNotFoundException e) {
throw new java.rmi.UnmarshalException("error unmarshalling arguments", e);
} finally {
call.releaseInputStream();
}
server.unbind($param_String_1);
try {
call.getResultStream(true);
} catch (java.io.IOException e) {
throw new java.rmi.MarshalException("error marshalling return", e);
}
break;
}
default:
throw new java.rmi.UnmarshalException("invalid method number");
}
}
}
/*
* Copyright (c) 2017, 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.registry;
/**
* Stubs to invoke RegistryImpl remote methods.
* Originally generated from RMIC but frozen to match RegistryImpl_Skel.
*/
@SuppressWarnings({"deprecation", "serial"})
public final class RegistryImpl_Stub
extends java.rmi.server.RemoteStub
implements java.rmi.registry.Registry, java.rmi.Remote {
private static final java.rmi.server.Operation[] operations = {
new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote)"),
new java.rmi.server.Operation("java.lang.String list()[]"),
new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String)"),
new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote)"),
new java.rmi.server.Operation("void unbind(java.lang.String)")
};
private static final long interfaceHash = 4905912898345647071L;
// constructors
public RegistryImpl_Stub() {
super();
}
public RegistryImpl_Stub(java.rmi.server.RemoteRef ref) {
super(ref);
}
// methods from remote interfaces
// implementation of bind(String, Remote)
public void bind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
throws java.rmi.AccessException, java.rmi.AlreadyBoundException, java.rmi.RemoteException {
try {
java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 0, interfaceHash);
try {
java.io.ObjectOutput out = call.getOutputStream();
out.writeObject($param_String_1);
out.writeObject($param_Remote_2);
} catch (java.io.IOException e) {
throw new java.rmi.MarshalException("error marshalling arguments", e);
}
ref.invoke(call);
ref.done(call);
} catch (java.lang.RuntimeException e) {
throw e;
} catch (java.rmi.RemoteException e) {
throw e;
} catch (java.rmi.AlreadyBoundException e) {
throw e;
} catch (java.lang.Exception e) {
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
}
}
// implementation of list()
public java.lang.String[] list()
throws java.rmi.AccessException, java.rmi.RemoteException {
try {
java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 1, interfaceHash);
ref.invoke(call);
java.lang.String[] $result;
try {
java.io.ObjectInput in = call.getInputStream();
$result = (java.lang.String[]) in.readObject();
} catch (java.io.IOException e) {
throw new java.rmi.UnmarshalException("error unmarshalling return", e);
} catch (java.lang.ClassNotFoundException e) {
throw new java.rmi.UnmarshalException("error unmarshalling return", e);
} finally {
ref.done(call);
}
return $result;
} catch (java.lang.RuntimeException e) {
throw e;
} catch (java.rmi.RemoteException e) {
throw e;
} catch (java.lang.Exception e) {
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
}
}
// implementation of lookup(String)
public java.rmi.Remote lookup(java.lang.String $param_String_1)
throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException {
try {
java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 2, interfaceHash);
try {
java.io.ObjectOutput out = call.getOutputStream();
out.writeObject($param_String_1);
} catch (java.io.IOException e) {
throw new java.rmi.MarshalException("error marshalling arguments", e);
}
ref.invoke(call);
java.rmi.Remote $result;
try {
java.io.ObjectInput in = call.getInputStream();
$result = (java.rmi.Remote) in.readObject();
} catch (java.io.IOException e) {
throw new java.rmi.UnmarshalException("error unmarshalling return", e);
} catch (java.lang.ClassNotFoundException e) {
throw new java.rmi.UnmarshalException("error unmarshalling return", e);
} finally {
ref.done(call);
}
return $result;
} catch (java.lang.RuntimeException e) {
throw e;
} catch (java.rmi.RemoteException e) {
throw e;
} catch (java.rmi.NotBoundException e) {
throw e;
} catch (java.lang.Exception e) {
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
}
}
// implementation of rebind(String, Remote)
public void rebind(java.lang.String $param_String_1, java.rmi.Remote $param_Remote_2)
throws java.rmi.AccessException, java.rmi.RemoteException {
try {
java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 3, interfaceHash);
try {
java.io.ObjectOutput out = call.getOutputStream();
out.writeObject($param_String_1);
out.writeObject($param_Remote_2);
} catch (java.io.IOException e) {
throw new java.rmi.MarshalException("error marshalling arguments", e);
}
ref.invoke(call);
ref.done(call);
} catch (java.lang.RuntimeException e) {
throw e;
} catch (java.rmi.RemoteException e) {
throw e;
} catch (java.lang.Exception e) {
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
}
}
// implementation of unbind(String)
public void unbind(java.lang.String $param_String_1)
throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException {
try {
java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject) this, operations, 4, interfaceHash);
try {
java.io.ObjectOutput out = call.getOutputStream();
out.writeObject($param_String_1);
} catch (java.io.IOException e) {
throw new java.rmi.MarshalException("error marshalling arguments", e);
}
ref.invoke(call);
ref.done(call);
} catch (java.lang.RuntimeException e) {
throw e;
} catch (java.rmi.RemoteException e) {
throw e;
} catch (java.rmi.NotBoundException e) {
throw e;
} catch (java.lang.Exception e) {
throw new java.rmi.UnexpectedException("undeclared checked exception", e);
}
}
}
...@@ -30,6 +30,7 @@ import java.io.File; ...@@ -30,6 +30,7 @@ import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream; import java.io.ObjectInputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.PrintStream; import java.io.PrintStream;
...@@ -105,7 +106,6 @@ import sun.rmi.log.LogHandler; ...@@ -105,7 +106,6 @@ import sun.rmi.log.LogHandler;
import sun.rmi.log.ReliableLog; import sun.rmi.log.ReliableLog;
import sun.rmi.registry.RegistryImpl; import sun.rmi.registry.RegistryImpl;
import sun.rmi.runtime.NewThreadAction; import sun.rmi.runtime.NewThreadAction;
import sun.rmi.server.UnicastServerRef;
import sun.rmi.transport.LiveRef; import sun.rmi.transport.LiveRef;
import sun.security.action.GetBooleanAction; import sun.security.action.GetBooleanAction;
import sun.security.action.GetIntegerAction; import sun.security.action.GetIntegerAction;
...@@ -345,6 +345,7 @@ public class Activation implements Serializable { ...@@ -345,6 +345,7 @@ public class Activation implements Serializable {
throw new AccessException( throw new AccessException(
"binding ActivationSystem is disallowed"); "binding ActivationSystem is disallowed");
} else { } else {
RegistryImpl.checkAccess("ActivationSystem.bind");
super.bind(name, obj); super.bind(name, obj);
} }
} }
...@@ -356,6 +357,7 @@ public class Activation implements Serializable { ...@@ -356,6 +357,7 @@ public class Activation implements Serializable {
throw new AccessException( throw new AccessException(
"unbinding ActivationSystem is disallowed"); "unbinding ActivationSystem is disallowed");
} else { } else {
RegistryImpl.checkAccess("ActivationSystem.unbind");
super.unbind(name); super.unbind(name);
} }
} }
...@@ -368,6 +370,7 @@ public class Activation implements Serializable { ...@@ -368,6 +370,7 @@ public class Activation implements Serializable {
throw new AccessException( throw new AccessException(
"binding ActivationSystem is disallowed"); "binding ActivationSystem is disallowed");
} else { } else {
RegistryImpl.checkAccess("ActivationSystem.rebind");
super.rebind(name, obj); super.rebind(name, obj);
} }
} }
...@@ -458,6 +461,33 @@ public class Activation implements Serializable { ...@@ -458,6 +461,33 @@ public class Activation implements Serializable {
} }
/**
* SameHostOnlyServerRef checks that access is from a local client
* before the parameters are deserialized. The unmarshalCustomCallData
* hook is used to check the network address of the caller
* with RegistryImpl.checkAccess().
* The kind of access is retained for an exception if one is thrown.
*/
static class SameHostOnlyServerRef extends UnicastServerRef {
private static final long serialVersionUID = 1234L;
private String accessKind; // an exception message
/**
* Construct a new SameHostOnlyServerRef from a LiveRef.
* @param lref a LiveRef
*/
SameHostOnlyServerRef(LiveRef lref, String accessKind) {
super(lref);
this.accessKind = accessKind;
}
@Override
protected void unmarshalCustomCallData(ObjectInput in) throws IOException, ClassNotFoundException {
RegistryImpl.checkAccess(accessKind);
super.unmarshalCustomCallData(in);
}
}
class ActivationSystemImpl class ActivationSystemImpl
extends RemoteServer extends RemoteServer
implements ActivationSystem implements ActivationSystem
...@@ -475,7 +505,8 @@ public class Activation implements Serializable { ...@@ -475,7 +505,8 @@ public class Activation implements Serializable {
* 'this' can be exported. * 'this' can be exported.
*/ */
LiveRef lref = new LiveRef(new ObjID(4), port, null, ssf); LiveRef lref = new LiveRef(new ObjID(4), port, null, ssf);
UnicastServerRef uref = new UnicastServerRef(lref); UnicastServerRef uref = new SameHostOnlyServerRef(lref,
"ActivationSystem.nonLocalAccess");
ref = uref; ref = uref;
uref.exportObject(this, null); uref.exportObject(this, null);
} }
...@@ -484,8 +515,8 @@ public class Activation implements Serializable { ...@@ -484,8 +515,8 @@ public class Activation implements Serializable {
throws ActivationException, UnknownGroupException, RemoteException throws ActivationException, UnknownGroupException, RemoteException
{ {
checkShutdown(); checkShutdown();
RegistryImpl.checkAccess("ActivationSystem.registerObject"); // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
// during unmarshallCustomData and is not applicable to local access.
ActivationGroupID groupID = desc.getGroupID(); ActivationGroupID groupID = desc.getGroupID();
ActivationID id = new ActivationID(activatorStub); ActivationID id = new ActivationID(activatorStub);
getGroupEntry(groupID).registerObject(id, desc, true); getGroupEntry(groupID).registerObject(id, desc, true);
...@@ -496,15 +527,18 @@ public class Activation implements Serializable { ...@@ -496,15 +527,18 @@ public class Activation implements Serializable {
throws ActivationException, UnknownObjectException, RemoteException throws ActivationException, UnknownObjectException, RemoteException
{ {
checkShutdown(); checkShutdown();
RegistryImpl.checkAccess("ActivationSystem.unregisterObject"); // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
// during unmarshallCustomData and is not applicable to local access.
getGroupEntry(id).unregisterObject(id, true); getGroupEntry(id).unregisterObject(id, true);
} }
public ActivationGroupID registerGroup(ActivationGroupDesc desc) public ActivationGroupID registerGroup(ActivationGroupDesc desc)
throws ActivationException, RemoteException throws ActivationException, RemoteException
{ {
Thread.dumpStack();
checkShutdown(); checkShutdown();
RegistryImpl.checkAccess("ActivationSystem.registerGroup"); // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
// during unmarshallCustomData and is not applicable to local access.
checkArgs(desc, null); checkArgs(desc, null);
ActivationGroupID id = new ActivationGroupID(systemStub); ActivationGroupID id = new ActivationGroupID(systemStub);
...@@ -521,7 +555,8 @@ public class Activation implements Serializable { ...@@ -521,7 +555,8 @@ public class Activation implements Serializable {
throws ActivationException, UnknownGroupException, RemoteException throws ActivationException, UnknownGroupException, RemoteException
{ {
checkShutdown(); checkShutdown();
RegistryImpl.checkAccess("ActivationSystem.activeGroup"); // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
// during unmarshallCustomData and is not applicable to local access.
getGroupEntry(id).activeGroup(group, incarnation); getGroupEntry(id).activeGroup(group, incarnation);
return monitor; return monitor;
...@@ -531,7 +566,8 @@ public class Activation implements Serializable { ...@@ -531,7 +566,8 @@ public class Activation implements Serializable {
throws ActivationException, UnknownGroupException, RemoteException throws ActivationException, UnknownGroupException, RemoteException
{ {
checkShutdown(); checkShutdown();
RegistryImpl.checkAccess("ActivationSystem.unregisterGroup"); // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
// during unmarshallCustomData and is not applicable to local access.
// remove entry before unregister so state is updated before // remove entry before unregister so state is updated before
// logged // logged
...@@ -543,7 +579,8 @@ public class Activation implements Serializable { ...@@ -543,7 +579,8 @@ public class Activation implements Serializable {
throws ActivationException, UnknownObjectException, RemoteException throws ActivationException, UnknownObjectException, RemoteException
{ {
checkShutdown(); checkShutdown();
RegistryImpl.checkAccess("ActivationSystem.setActivationDesc"); // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
// during unmarshallCustomData and is not applicable to local access.
if (!getGroupID(id).equals(desc.getGroupID())) { if (!getGroupID(id).equals(desc.getGroupID())) {
throw new ActivationException( throw new ActivationException(
...@@ -557,8 +594,8 @@ public class Activation implements Serializable { ...@@ -557,8 +594,8 @@ public class Activation implements Serializable {
throws ActivationException, UnknownGroupException, RemoteException throws ActivationException, UnknownGroupException, RemoteException
{ {
checkShutdown(); checkShutdown();
RegistryImpl.checkAccess( // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
"ActivationSystem.setActivationGroupDesc"); // during unmarshallCustomData and is not applicable to local access.
checkArgs(desc, null); checkArgs(desc, null);
return getGroupEntry(id).setActivationGroupDesc(id, desc, true); return getGroupEntry(id).setActivationGroupDesc(id, desc, true);
...@@ -568,7 +605,8 @@ public class Activation implements Serializable { ...@@ -568,7 +605,8 @@ public class Activation implements Serializable {
throws ActivationException, UnknownObjectException, RemoteException throws ActivationException, UnknownObjectException, RemoteException
{ {
checkShutdown(); checkShutdown();
RegistryImpl.checkAccess("ActivationSystem.getActivationDesc"); // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
// during unmarshallCustomData and is not applicable to local access.
return getGroupEntry(id).getActivationDesc(id); return getGroupEntry(id).getActivationDesc(id);
} }
...@@ -577,8 +615,8 @@ public class Activation implements Serializable { ...@@ -577,8 +615,8 @@ public class Activation implements Serializable {
throws ActivationException, UnknownGroupException, RemoteException throws ActivationException, UnknownGroupException, RemoteException
{ {
checkShutdown(); checkShutdown();
RegistryImpl.checkAccess // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
("ActivationSystem.getActivationGroupDesc"); // during unmarshallCustomData and is not applicable to local access.
return getGroupEntry(id).desc; return getGroupEntry(id).desc;
} }
...@@ -588,7 +626,8 @@ public class Activation implements Serializable { ...@@ -588,7 +626,8 @@ public class Activation implements Serializable {
* the activation daemon and exits the activation daemon. * the activation daemon and exits the activation daemon.
*/ */
public void shutdown() throws AccessException { public void shutdown() throws AccessException {
RegistryImpl.checkAccess("ActivationSystem.shutdown"); // RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
// during unmarshallCustomData and is not applicable to local access.
Object lock = startupLock; Object lock = startupLock;
if (lock != null) { if (lock != null) {
......
...@@ -32,6 +32,7 @@ import java.io.ObjectOutput; ...@@ -32,6 +32,7 @@ import java.io.ObjectOutput;
import java.io.ObjectStreamClass; import java.io.ObjectStreamClass;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.rmi.AccessException;
import java.rmi.MarshalException; import java.rmi.MarshalException;
import java.rmi.Remote; import java.rmi.Remote;
import java.rmi.RemoteException; import java.rmi.RemoteException;
...@@ -290,20 +291,25 @@ public class UnicastServerRef extends UnicastRef ...@@ -290,20 +291,25 @@ public class UnicastServerRef extends UnicastRef
try { try {
in = call.getInputStream(); in = call.getInputStream();
num = in.readInt(); num = in.readInt();
if (num >= 0) { } catch (Exception readEx) {
if (skel != null) { throw new UnmarshalException("error unmarshalling call header",
oldDispatch(obj, call, num); readEx);
return; }
} else { if (num >= 0) {
throw new UnmarshalException( if (skel != null) {
"skeleton class not found but required " + oldDispatch(obj, call, num);
"for client version"); return;
} } else {
throw new UnmarshalException(
"skeleton class not found but required " +
"for client version");
} }
}
try {
op = in.readLong(); op = in.readLong();
} catch (Exception readEx) { } catch (Exception readEx) {
throw new UnmarshalException("error unmarshalling call header", throw new UnmarshalException("error unmarshalling call header",
readEx); readEx);
} }
/* /*
...@@ -331,6 +337,11 @@ public class UnicastServerRef extends UnicastRef ...@@ -331,6 +337,11 @@ public class UnicastServerRef extends UnicastRef
try { try {
unmarshalCustomCallData(in); unmarshalCustomCallData(in);
params = unmarshalParameters(obj, method, marshalStream); params = unmarshalParameters(obj, method, marshalStream);
} catch (AccessException aex) {
// For compatibility, AccessException is not wrapped in UnmarshalException
// disable saving any refs in the inputStream for GC
((StreamRemoteCall) call).discardPendingRefs();
throw aex;
} catch (java.io.IOException | ClassNotFoundException e) { } catch (java.io.IOException | ClassNotFoundException e) {
// disable saving any refs in the inputStream for GC // disable saving any refs in the inputStream for GC
((StreamRemoteCall) call).discardPendingRefs(); ((StreamRemoteCall) call).discardPendingRefs();
...@@ -367,6 +378,7 @@ public class UnicastServerRef extends UnicastRef ...@@ -367,6 +378,7 @@ public class UnicastServerRef extends UnicastRef
*/ */
} }
} catch (Throwable e) { } catch (Throwable e) {
Throwable origEx = e;
logCallException(e); logCallException(e);
ObjectOutput out = call.getResultStream(false); ObjectOutput out = call.getResultStream(false);
...@@ -382,6 +394,12 @@ public class UnicastServerRef extends UnicastRef ...@@ -382,6 +394,12 @@ public class UnicastServerRef extends UnicastRef
clearStackTraces(e); clearStackTraces(e);
} }
out.writeObject(e); out.writeObject(e);
// AccessExceptions should cause Transport.serviceCall
// to flag the connection as unusable.
if (origEx instanceof AccessException) {
throw new IOException("Connection is not reusable", origEx);
}
} finally { } finally {
call.releaseInputStream(); // in case skeleton doesn't call.releaseInputStream(); // in case skeleton doesn't
call.releaseOutputStream(); call.releaseOutputStream();
...@@ -413,62 +431,41 @@ public class UnicastServerRef extends UnicastRef ...@@ -413,62 +431,41 @@ public class UnicastServerRef extends UnicastRef
* Handle server-side dispatch using the RMI 1.1 stub/skeleton * Handle server-side dispatch using the RMI 1.1 stub/skeleton
* protocol, given a non-negative operation number that has * protocol, given a non-negative operation number that has
* already been read from the call stream. * already been read from the call stream.
* Exceptions are handled by the caller to be sent to the remote client.
* *
* @param obj the target remote object for the call * @param obj the target remote object for the call
* @param call the "remote call" from which operation and * @param call the "remote call" from which operation and
* method arguments can be obtained. * method arguments can be obtained.
* @param op the operation number * @param op the operation number
* @exception IOException if unable to marshal return result or * @throws Exception if unable to marshal return result or
* release input or output streams * release input or output streams
*/ */
public void oldDispatch(Remote obj, RemoteCall call, int op) private void oldDispatch(Remote obj, RemoteCall call, int op)
throws IOException throws Exception
{ {
long hash; // hash for matching stub with skeleton long hash; // hash for matching stub with skeleton
// read remote call header
ObjectInput in;
in = call.getInputStream();
try { try {
// read remote call header Class<?> clazz = Class.forName("sun.rmi.transport.DGCImpl_Skel");
ObjectInput in; if (clazz.isAssignableFrom(skel.getClass())) {
try { ((MarshalInputStream)in).useCodebaseOnly();
in = call.getInputStream();
try {
Class<?> clazz = Class.forName("sun.rmi.transport.DGCImpl_Skel");
if (clazz.isAssignableFrom(skel.getClass())) {
((MarshalInputStream)in).useCodebaseOnly();
}
} catch (ClassNotFoundException ignore) { }
hash = in.readLong();
} catch (Exception readEx) {
throw new UnmarshalException("error unmarshalling call header",
readEx);
} }
} catch (ClassNotFoundException ignore) { }
// if calls are being logged, write out object id and operation try {
logCall(obj, skel.getOperations()[op]); hash = in.readLong();
unmarshalCustomCallData(in); } catch (Exception ioe) {
// dispatch to skeleton for remote object throw new UnmarshalException("error unmarshalling call header", ioe);
skel.dispatch(obj, call, op, hash);
} catch (Throwable e) {
logCallException(e);
ObjectOutput out = call.getResultStream(false);
if (e instanceof Error) {
e = new ServerError(
"Error occurred in server thread", (Error) e);
} else if (e instanceof RemoteException) {
e = new ServerException(
"RemoteException occurred in server thread",
(Exception) e);
}
if (suppressStackTraces) {
clearStackTraces(e);
}
out.writeObject(e);
} finally {
call.releaseInputStream(); // in case skeleton doesn't
call.releaseOutputStream();
} }
// if calls are being logged, write out object id and operation
logCall(obj, skel.getOperations()[op]);
unmarshalCustomCallData(in);
// dispatch to skeleton for remote object
skel.dispatch(obj, call, op, hash);
} }
/** /**
......
/*
* Copyright (c) 2017, 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.
*
* 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.
*/
import java.net.InetAddress;
import java.rmi.AccessException;
import java.rmi.activation.ActivationSystem;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Set;
import java.util.HashSet;
/*
* @test
* @bug 8174770
* @summary Verify that ActivationSystem rejects non-local access.
* The test is manual because the (non-local) host running rmid must be supplied as a property.
* @run main/manual/othervm -Dactivation.host=rmid-host NonLocalActivationTest
*/
/**
* Lookup the ActivationSystem on a different host and invoke its remote interface methods.
* They should all throw an exception, non-local access is prohibited.
*
* This test is a manual test and uses rmid running on a *different* host.
* The default port (1098) for the Activation System is ok and expected.
* Login or ssh to the different host and invoke {@code $JDK_HOME/bin/rmid}.
* It will not show any output.
*
* On the first host modify the @run command above to replace "rmid-host"
* with the hostname or IP address of the different host and run the test with jtreg.
*/
public class NonLocalActivationTest
{
public static void main(String[] args) throws Exception {
String host = System.getProperty("activation.host");
if (host == null || host.isEmpty()) {
throw new RuntimeException("Specify host with system property: -Dactivation.host=<host>");
}
// Check if running the test on a local system; it only applies to remote
String myHostName = InetAddress.getLocalHost().getHostName();
Set<InetAddress> myAddrs = new HashSet<>();
InetAddress[] myAddrsArr = InetAddress.getAllByName(myHostName);
for (InetAddress a : myAddrsArr) {
myAddrs.add(a);
}
Set<InetAddress> hostAddrs = new HashSet<>();
InetAddress[] hostAddrsArr = InetAddress.getAllByName(host);
for (InetAddress a : hostAddrsArr) {
hostAddrs.add(a);
}
if (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i))
|| hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())) {
throw new RuntimeException("Error: property 'activation.host' must not be the local host%n");
}
// Locate the registry operated by the ActivationSystem
// Test SystemRegistryImpl
Registry registry = LocateRegistry.getRegistry(host, ActivationSystem.SYSTEM_PORT);
try {
// Verify it is an ActivationSystem registry
registry.lookup("java.rmi.activation.ActivationSystem");
} catch (Exception nf) {
throw new RuntimeException("Not a ActivationSystem registry, does not contain java.rmi.activation.ActivationSystem", nf);
}
try {
registry.bind("foo", null);
throw new RuntimeException("Remote access should not succeed for method: bind");
} catch (Exception e) {
assertIsAccessException(e, "Registry.bind");
}
try {
registry.rebind("foo", null);
throw new RuntimeException("Remote access should not succeed for method: rebind");
} catch (Exception e) {
assertIsAccessException(e, "Registry.rebind");
}
try {
registry.unbind("foo");
throw new RuntimeException("Remote access should not succeed for method: unbind");
} catch (Exception e) {
assertIsAccessException(e, "Registry.unbind");
}
// Locate the ActivationSystem on the specified host and default port.
// Test each of the ActivationSystem methods
ActivationSystem as = (ActivationSystem) registry.lookup("java.rmi.activation.ActivationSystem");
// Argument is not material, access check is before arg processing
try {
as.registerGroup(null);
} catch (Exception aex) {
assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
}
try {
as.getActivationDesc(null);
} catch (Exception aex) {
assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
}
try {
as.getActivationGroupDesc(null);
} catch (Exception aex) {
assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
}
try {
as.registerObject(null);
} catch (Exception aex) {
assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
}
try {
as.unregisterGroup(null);
} catch (Exception aex) {
assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
}
try {
as.unregisterObject(null);
} catch (Exception aex) {
assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
}
try {
as.setActivationDesc(null, null);
} catch (Exception aex) {
assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
}
try {
as.setActivationGroupDesc(null, null);
} catch (Exception aex) {
assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
}
}
/**
* Check the exception chain for the expected AccessException and message.
* @param ex the exception from the remote invocation.
*/
private static void assertIsAccessException(Exception ex, String msg1) {
Throwable t = ex;
System.out.println();
while (!(t instanceof AccessException) && t.getCause() != null) {
t = t.getCause();
}
if (t instanceof AccessException) {
String msg = t.getMessage();
int asIndex = msg.indexOf(msg1);
int disallowIndex = msg.indexOf("disallowed");
int nonLocalHostIndex = msg.indexOf("non-local host");
if (asIndex < 0 ||
disallowIndex < 0 ||
nonLocalHostIndex < 0 ) {
throw new RuntimeException("exception message is malformed", t);
}
System.out.printf("Found expected AccessException: %s%n", t);
} else {
throw new RuntimeException("AccessException did not occur", ex);
}
}
}
/*
* Copyright (c) 2017, 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.
*
* 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.
*/
import java.net.InetAddress;
import java.rmi.AccessException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Set;
import java.util.HashSet;
/* @test
* @bug 8174770
* @summary Verify that Registry rejects non-local access for bind, unbind, rebind.
* The test is manual because the (non-local) host running rmiregistry must be supplied as a property.
* @run main/othervm/manual -Dregistry.host=rmi-registry-host NonLocalRegistryTest
*/
/**
* Verify that access checks for Registry.bind(), .rebind(), and .unbind()
* are prevented on remote access to the registry.
*
* This test is a manual test and uses a standard rmiregistry running
* on a *different* host.
* The test verifies that the access check is performed *before* the object to be
* bound or rebound is deserialized.
*
* Login or ssh to the different host and invoke {@code $JDK_HOME/bin/rmiregistry}.
* It will not show any output.
*
* On the first host modify the @run command above to replace "rmi-registry-host"
* with the hostname or IP address of the different host and run the test with jtreg.
*/
public class NonLocalRegistryTest {
public static void main(String[] args) throws Exception {
String host = System.getProperty("registry.host");
if (host == null || host.isEmpty()) {
throw new RuntimeException("Specify host with system property: -Dregistry.host=<host>");
}
// Check if running the test on a local system; it only applies to remote
String myHostName = InetAddress.getLocalHost().getHostName();
Set<InetAddress> myAddrs = new HashSet<>();
InetAddress[] myAddrsArr = InetAddress.getAllByName(myHostName);
for (InetAddress a : myAddrsArr) {
myAddrs.add(a);
}
Set<InetAddress> hostAddrs = new HashSet<>();
InetAddress[] hostAddrsArr = InetAddress.getAllByName(host);
for (InetAddress a : hostAddrsArr) {
hostAddrs.add(a);
}
if (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i))
|| hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())) {
throw new RuntimeException("Error: property 'registry.host' must not be the local host%n");
}
Registry registry = LocateRegistry.getRegistry(host, Registry.REGISTRY_PORT);
try {
registry.bind("foo", null);
throw new RuntimeException("Remote access should not succeed for method: bind");
} catch (Exception e) {
assertIsAccessException(e);
}
try {
registry.rebind("foo", null);
throw new RuntimeException("Remote access should not succeed for method: rebind");
} catch (Exception e) {
assertIsAccessException(e);
}
try {
registry.unbind("foo");
throw new RuntimeException("Remote access should not succeed for method: unbind");
} catch (Exception e) {
assertIsAccessException(e);
}
}
/**
* Check the exception chain for the expected AccessException and message.
* @param ex the exception from the remote invocation.
*/
private static void assertIsAccessException(Throwable ex) {
Throwable t = ex;
while (!(t instanceof AccessException) && t.getCause() != null) {
t = t.getCause();
}
if (t instanceof AccessException) {
String msg = t.getMessage();
int asIndex = msg.indexOf("Registry");
int rrIndex = msg.indexOf("Registry.Registry"); // Obsolete error text
int disallowIndex = msg.indexOf("disallowed");
int nonLocalHostIndex = msg.indexOf("non-local host");
if (asIndex < 0 ||
rrIndex != -1 ||
disallowIndex < 0 ||
nonLocalHostIndex < 0 ) {
throw new RuntimeException("exception message is malformed", t);
}
System.out.printf("Found expected AccessException: %s%n%n", t);
} else {
throw new RuntimeException("AccessException did not occur when expected", ex);
}
}
}
/*
* Copyright (c) 2017, 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.
*
* 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.
*/
import java.net.InetAddress;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.Set;
import java.util.HashSet;
/* @test
* @bug 8174770
* @summary Verify that JMX Registry rejects non-local access for bind, unbind, rebind.
* The test is manual because the (non-local) host and port running JMX must be supplied as properties.
* @run main/othervm/manual -Djmx-registry.host=jmx-registry-host -Djmx-registry.port=jmx-registry-port NonLocalJMXRemoteTest
*/
/**
* Verify that access checks for the Registry exported by JMX Registry.bind(),
* .rebind(), and .unbind() are prevented on remote access to the registry.
* The test verifies that the access check is performed *before* the object to be
* bound or rebound is deserialized.
* This tests the SingleEntryRegistry implemented by JMX.
* This test is a manual test and uses JMX running on a *different* host.
* JMX can be enabled in any Java runtime; for example:
* login or ssh to the different host and invoke rmiregistry with arguments below.
* It will not show any output.
* {@code $JDK_HOME/bin/rmiregistry \
* -J-Dcom.sun.management.jmxremote.port=8888 \
* -J-Dcom.sun.management.jmxremote.local.only=false \
* -J-Dcom.sun.management.jmxremote.ssl=false \
* -J-Dcom.sun.management.jmxremote.authenticate=false
* }
* On the first host modify the @run command above to replace "jmx-registry-host"
* with the hostname or IP address of the different host and run the test with jtreg.
*/
public class NonLocalJMXRemoteTest {
public static void main(String[] args) throws Exception {
String host = System.getProperty("jmx-registry.host");
if (host == null || host.isEmpty()) {
throw new RuntimeException("Specify host with system property: -Djmx-registry.host=<host>");
}
int port = Integer.getInteger("jmx-registry.port", -1);
if (port <= 0) {
throw new RuntimeException("Specify port with system property: -Djmx-registry.port=<port>");
}
// Check if running the test on a local system; it only applies to remote
String myHostName = InetAddress.getLocalHost().getHostName();
Set<InetAddress> myAddrs = new HashSet<>();
InetAddress[] myAddrsArr = InetAddress.getAllByName(myHostName);
for (InetAddress a : myAddrsArr) {
myAddrs.add(a);
}
Set<InetAddress> hostAddrs = new HashSet<>();
InetAddress[] hostAddrsArr = InetAddress.getAllByName(host);
for (InetAddress a : hostAddrsArr) {
hostAddrs.add(a);
}
if (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i))
|| hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())) {
throw new RuntimeException("Error: property 'jmx-registry.host' must not be the local host%n");
}
Registry registry = LocateRegistry.getRegistry(host, port);
try {
// Verify it is a JMX Registry
registry.lookup("jmxrmi");
} catch (NotBoundException nf) {
throw new RuntimeException("Not a JMX registry, jmxrmi is not bound", nf);
}
try {
registry.bind("foo", null);
throw new RuntimeException("Remote access should not succeed for method: bind");
} catch (Exception e) {
assertIsAccessException(e);
}
try {
registry.rebind("foo", null);
throw new RuntimeException("Remote access should not succeed for method: rebind");
} catch (Exception e) {
assertIsAccessException(e);
}
try {
registry.unbind("foo");
throw new RuntimeException("Remote access should not succeed for method: unbind");
} catch (Exception e) {
assertIsAccessException(e);
}
}
/**
* Check the exception chain for the expected AccessException and message.
* @param ex the exception from the remote invocation.
*/
private static void assertIsAccessException(Throwable ex) {
Throwable t = ex;
while (!(t instanceof AccessException) && t.getCause() != null) {
t = t.getCause();
}
if (t instanceof AccessException) {
String msg = t.getMessage();
int asIndex = msg.indexOf("Registry");
int disallowIndex = msg.indexOf("disallowed");
int nonLocalHostIndex = msg.indexOf("non-local host");
if (asIndex < 0 ||
disallowIndex < 0 ||
nonLocalHostIndex < 0 ) {
throw new RuntimeException("exception message is malformed", t);
}
System.out.printf("Found expected AccessException: %s%n%n", t);
} else {
throw new RuntimeException("AccessException did not occur when expected", ex);
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册