8174770: Check registry registration location
Reviewed-by: dfuchs, smarks, chegar
This commit is contained in:
parent
558e2a6350
commit
4ce7b5f280
@ -40,15 +40,9 @@ $(eval $(call SetupRMICompilation,RMI_12, \
|
||||
RUN_V12 := true))
|
||||
GENCLASSES += $(RMI_12)
|
||||
|
||||
$(eval $(call SetupRMICompilation,RMI_11, \
|
||||
CLASSES := sun.rmi.registry.RegistryImpl, \
|
||||
CLASSES_DIR := $(CLASSES_DIR)/java.rmi, \
|
||||
STUB_CLASSES_DIR := $(STUB_CLASSES_DIR)/java.rmi, \
|
||||
RUN_V11 := true))
|
||||
GENCLASSES += $(RMI_11)
|
||||
|
||||
################################################################################
|
||||
|
||||
all: $(RMI_11) $(RMI_12)
|
||||
all: $(RMI_12)
|
||||
|
||||
.PHONY: all
|
||||
|
@ -75,6 +75,10 @@ import sun.rmi.transport.LiveRef;
|
||||
* registry.
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
@ -143,6 +147,20 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
|
||||
RMIClientSocketFactory csf,
|
||||
RMIServerSocketFactory ssf)
|
||||
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) {
|
||||
// grant permission for default port only.
|
||||
@ -150,7 +168,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
|
||||
AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
|
||||
public Void run() throws RemoteException {
|
||||
LiveRef lref = new LiveRef(id, port, csf, ssf);
|
||||
setup(new UnicastServerRef2(lref, RegistryImpl::registryFilter));
|
||||
setup(new UnicastServerRef2(lref, serialFilter));
|
||||
return null;
|
||||
}
|
||||
}, null, new SocketPermission("localhost:"+port, "listen,accept"));
|
||||
@ -226,7 +244,8 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
|
||||
public void bind(String name, Remote obj)
|
||||
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) {
|
||||
Remote curr = bindings.get(name);
|
||||
if (curr != null)
|
||||
@ -243,7 +262,8 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
|
||||
public void unbind(String name)
|
||||
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) {
|
||||
Remote obj = bindings.get(name);
|
||||
if (obj == null)
|
||||
@ -259,7 +279,8 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
|
||||
public void rebind(String name, Remote obj)
|
||||
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);
|
||||
}
|
||||
|
||||
@ -312,7 +333,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
|
||||
|
||||
if (clientHost.isAnyLocalAddress()) {
|
||||
throw new AccessException(
|
||||
"Registry." + op + " disallowed; origin unknown");
|
||||
op + " disallowed; origin unknown");
|
||||
}
|
||||
|
||||
try {
|
||||
@ -335,7 +356,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
|
||||
// must have been an IOException
|
||||
|
||||
throw new AccessException(
|
||||
"Registry." + op + " disallowed; origin " +
|
||||
op + " disallowed; origin " +
|
||||
clientHost + " is non-local host");
|
||||
}
|
||||
}
|
||||
@ -344,8 +365,7 @@ public class RegistryImpl extends java.rmi.server.RemoteServer
|
||||
* Local call from this VM: allow access.
|
||||
*/
|
||||
} catch (java.net.UnknownHostException ex) {
|
||||
throw new AccessException("Registry." + op +
|
||||
" disallowed; origin is unknown host");
|
||||
throw new AccessException(op + " disallowed; origin is unknown host");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.ObjectInput;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
@ -105,7 +106,6 @@ import sun.rmi.log.LogHandler;
|
||||
import sun.rmi.log.ReliableLog;
|
||||
import sun.rmi.registry.RegistryImpl;
|
||||
import sun.rmi.runtime.NewThreadAction;
|
||||
import sun.rmi.server.UnicastServerRef;
|
||||
import sun.rmi.transport.LiveRef;
|
||||
import sun.security.provider.PolicyFile;
|
||||
import com.sun.rmi.rmid.ExecPermission;
|
||||
@ -375,6 +375,7 @@ public class Activation implements Serializable {
|
||||
throw new AccessException(
|
||||
"binding ActivationSystem is disallowed");
|
||||
} else {
|
||||
RegistryImpl.checkAccess("ActivationSystem.bind");
|
||||
super.bind(name, obj);
|
||||
}
|
||||
}
|
||||
@ -386,6 +387,7 @@ public class Activation implements Serializable {
|
||||
throw new AccessException(
|
||||
"unbinding ActivationSystem is disallowed");
|
||||
} else {
|
||||
RegistryImpl.checkAccess("ActivationSystem.unbind");
|
||||
super.unbind(name);
|
||||
}
|
||||
}
|
||||
@ -398,6 +400,7 @@ public class Activation implements Serializable {
|
||||
throw new AccessException(
|
||||
"binding ActivationSystem is disallowed");
|
||||
} else {
|
||||
RegistryImpl.checkAccess("ActivationSystem.rebind");
|
||||
super.rebind(name, obj);
|
||||
}
|
||||
}
|
||||
@ -488,6 +491,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
|
||||
extends RemoteServer
|
||||
implements ActivationSystem
|
||||
@ -505,7 +535,8 @@ public class Activation implements Serializable {
|
||||
* 'this' can be exported.
|
||||
*/
|
||||
LiveRef lref = new LiveRef(new ObjID(4), port, null, ssf);
|
||||
UnicastServerRef uref = new UnicastServerRef(lref);
|
||||
UnicastServerRef uref = new SameHostOnlyServerRef(lref,
|
||||
"ActivationSystem.nonLocalAccess");
|
||||
ref = uref;
|
||||
uref.exportObject(this, null);
|
||||
}
|
||||
@ -514,8 +545,8 @@ public class Activation implements Serializable {
|
||||
throws ActivationException, UnknownGroupException, RemoteException
|
||||
{
|
||||
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();
|
||||
ActivationID id = new ActivationID(activatorStub);
|
||||
getGroupEntry(groupID).registerObject(id, desc, true);
|
||||
@ -526,7 +557,8 @@ public class Activation implements Serializable {
|
||||
throws ActivationException, UnknownObjectException, RemoteException
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@ -534,7 +566,8 @@ public class Activation implements Serializable {
|
||||
throws ActivationException, RemoteException
|
||||
{
|
||||
checkShutdown();
|
||||
RegistryImpl.checkAccess("ActivationSystem.registerGroup");
|
||||
// RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
|
||||
// during unmarshallCustomData and is not applicable to local access.
|
||||
checkArgs(desc, null);
|
||||
|
||||
ActivationGroupID id = new ActivationGroupID(systemStub);
|
||||
@ -551,7 +584,8 @@ public class Activation implements Serializable {
|
||||
throws ActivationException, UnknownGroupException, RemoteException
|
||||
{
|
||||
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);
|
||||
return monitor;
|
||||
@ -561,7 +595,8 @@ public class Activation implements Serializable {
|
||||
throws ActivationException, UnknownGroupException, RemoteException
|
||||
{
|
||||
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
|
||||
// logged
|
||||
@ -573,7 +608,8 @@ public class Activation implements Serializable {
|
||||
throws ActivationException, UnknownObjectException, RemoteException
|
||||
{
|
||||
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())) {
|
||||
throw new ActivationException(
|
||||
@ -587,8 +623,8 @@ public class Activation implements Serializable {
|
||||
throws ActivationException, UnknownGroupException, RemoteException
|
||||
{
|
||||
checkShutdown();
|
||||
RegistryImpl.checkAccess(
|
||||
"ActivationSystem.setActivationGroupDesc");
|
||||
// RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
|
||||
// during unmarshallCustomData and is not applicable to local access.
|
||||
|
||||
checkArgs(desc, null);
|
||||
return getGroupEntry(id).setActivationGroupDesc(id, desc, true);
|
||||
@ -598,7 +634,8 @@ public class Activation implements Serializable {
|
||||
throws ActivationException, UnknownObjectException, RemoteException
|
||||
{
|
||||
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);
|
||||
}
|
||||
@ -607,8 +644,8 @@ public class Activation implements Serializable {
|
||||
throws ActivationException, UnknownGroupException, RemoteException
|
||||
{
|
||||
checkShutdown();
|
||||
RegistryImpl.checkAccess
|
||||
("ActivationSystem.getActivationGroupDesc");
|
||||
// RegistryImpl.checkAccess() is done in the SameHostOnlyServerRef
|
||||
// during unmarshallCustomData and is not applicable to local access.
|
||||
|
||||
return getGroupEntry(id).desc;
|
||||
}
|
||||
@ -618,7 +655,8 @@ public class Activation implements Serializable {
|
||||
* the activation daemon and exits the activation daemon.
|
||||
*/
|
||||
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;
|
||||
if (lock != null) {
|
||||
|
@ -33,6 +33,7 @@ import java.io.ObjectOutput;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.rmi.AccessException;
|
||||
import java.rmi.MarshalException;
|
||||
import java.rmi.Remote;
|
||||
import java.rmi.RemoteException;
|
||||
@ -288,21 +289,26 @@ public class UnicastServerRef extends UnicastRef
|
||||
try {
|
||||
in = call.getInputStream();
|
||||
num = in.readInt();
|
||||
if (num >= 0) {
|
||||
if (skel != null) {
|
||||
oldDispatch(obj, call, num);
|
||||
return;
|
||||
} else {
|
||||
throw new UnmarshalException(
|
||||
"skeleton class not found but required " +
|
||||
"for client version");
|
||||
}
|
||||
}
|
||||
op = in.readLong();
|
||||
} catch (Exception readEx) {
|
||||
throw new UnmarshalException("error unmarshalling call header",
|
||||
readEx);
|
||||
}
|
||||
if (num >= 0) {
|
||||
if (skel != null) {
|
||||
oldDispatch(obj, call, num);
|
||||
return;
|
||||
} else {
|
||||
throw new UnmarshalException(
|
||||
"skeleton class not found but required " +
|
||||
"for client version");
|
||||
}
|
||||
}
|
||||
try {
|
||||
op = in.readLong();
|
||||
} catch (Exception readEx) {
|
||||
throw new UnmarshalException("error unmarshalling call header",
|
||||
readEx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Since only system classes (with null class loaders) will be on
|
||||
@ -329,6 +335,11 @@ public class UnicastServerRef extends UnicastRef
|
||||
try {
|
||||
unmarshalCustomCallData(in);
|
||||
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) {
|
||||
// disable saving any refs in the inputStream for GC
|
||||
((StreamRemoteCall) call).discardPendingRefs();
|
||||
@ -365,6 +376,7 @@ public class UnicastServerRef extends UnicastRef
|
||||
*/
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Throwable origEx = e;
|
||||
logCallException(e);
|
||||
|
||||
ObjectOutput out = call.getResultStream(false);
|
||||
@ -380,6 +392,12 @@ public class UnicastServerRef extends UnicastRef
|
||||
clearStackTraces(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 {
|
||||
call.releaseInputStream(); // in case skeleton doesn't
|
||||
call.releaseOutputStream();
|
||||
@ -408,62 +426,41 @@ public class UnicastServerRef extends UnicastRef
|
||||
* Handle server-side dispatch using the RMI 1.1 stub/skeleton
|
||||
* protocol, given a non-negative operation number that has
|
||||
* 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 call the "remote call" from which operation and
|
||||
* method arguments can be obtained.
|
||||
* @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
|
||||
*/
|
||||
public void oldDispatch(Remote obj, RemoteCall call, int op)
|
||||
throws IOException
|
||||
private void oldDispatch(Remote obj, RemoteCall call, int op)
|
||||
throws Exception
|
||||
{
|
||||
long hash; // hash for matching stub with skeleton
|
||||
|
||||
// read remote call header
|
||||
ObjectInput in;
|
||||
in = call.getInputStream();
|
||||
try {
|
||||
// read remote call header
|
||||
ObjectInput in;
|
||||
try {
|
||||
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);
|
||||
Class<?> clazz = Class.forName("sun.rmi.transport.DGCImpl_Skel");
|
||||
if (clazz.isAssignableFrom(skel.getClass())) {
|
||||
((MarshalInputStream)in).useCodebaseOnly();
|
||||
}
|
||||
} catch (ClassNotFoundException ignore) { }
|
||||
|
||||
// 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);
|
||||
|
||||
} 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();
|
||||
try {
|
||||
hash = in.readLong();
|
||||
} catch (Exception ioe) {
|
||||
throw new UnmarshalException("error unmarshalling call header", ioe);
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -32,6 +32,7 @@
|
||||
|
||||
package sun.management.jmxremote;
|
||||
|
||||
import java.io.ObjectInputFilter;
|
||||
import java.rmi.AccessException;
|
||||
import java.rmi.NotBoundException;
|
||||
import java.rmi.Remote;
|
||||
@ -56,7 +57,7 @@ public class SingleEntryRegistry extends RegistryImpl {
|
||||
String name,
|
||||
Remote object)
|
||||
throws RemoteException {
|
||||
super(port, csf, ssf);
|
||||
super(port, csf, ssf, SingleEntryRegistry::singleRegistryFilter);
|
||||
this.name = name;
|
||||
this.object = object;
|
||||
}
|
||||
@ -84,6 +85,23 @@ public class SingleEntryRegistry extends RegistryImpl {
|
||||
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 Remote object;
|
||||
|
||||
|
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* @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 = Set.of(InetAddress.getAllByName(myHostName));
|
||||
Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* @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 = Set.of(InetAddress.getAllByName(myHostName));
|
||||
Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,133 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/* @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 = Set.of(InetAddress.getAllByName(myHostName));
|
||||
Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host));
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user