-
Bug
-
Resolution: Fixed
-
P1
-
1.4.0
-
None
-
beta3
-
sparc
-
solaris_9
It is not possible to pass BasicPermission objects across RMI between Java 1.2.2 and Java 1.4,
due to mismatched serialVersionUID's. This is a serious problem for client-server environments
that need to provide backwards compatibility for downloaded code.
For example, the Solaris Management Console (SMC) employs the "applet" model, whereby applications
are downloaded from an application server and executed in the SMC console. While not specifically
Java Applets, the concept is the same. Anyone running Solaris 9 can run SMC by simply entering
/usr/sadm/bin/smc at a command prompt. By default client and server are the same machine and
everything works perfectly, where the default JRE is 1.4
Similarly, the same applies to Solaris 8 1/01 or greater, where the default JRE is 1.2.2, and
all works fine.
Now, it is important that SMC running on Solaris 9 clients be able to download tools from
Solaris 8 servers and manage those S8 machines. However this fails with the following exception
trace:
java.rmi.UnmarshalException: error unmarshalling return; nested
exception is:
java.io.InvalidClassException:
java.security.BasicPermissionCollection; local class incompatible:
stream classdesc serialVersionUID = 739301742472979399, local class
serialVersionUID = -1627748012524673683
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:167)
at
com.sun.management.viperimpl.services.authorization.AuthorizeService_Container_Stub.readUserPermissions(Unknown
Source)
at
com.sun.management.viperimpl.services.authorization.AuthorizeService_Agent.readUserPermissions(Unknown
Source)
at
com.sun.admin.serialmgr.client.ServiceWrapper.init(ServiceWrapper.java:142)
at
com.sun.admin.serialmgr.client.WbemServiceWrapper.init(WbemServiceWrapper.java:72)
at
com.sun.admin.serialmgr.client.ApplicationContext.getServiceWrapper(ApplicationContext.java:140)
at
com.sun.admin.serialmgr.client.VSerialMgr.init(VSerialMgr.java:177)
at
com.sun.management.viperimpl.console.BaseConsoleManager.initializeTool(BaseConsoleManager.java:1893)
at
com.sun.management.viperimpl.console.BaseConsoleManager.handleToolInitialization(BaseConsoleManager.java:1852)
at
com.sun.management.viperimpl.console.BaseConsoleManager.loadToolAndReplaceStub(BaseConsoleManager.java:2110)
at
com.sun.management.viperimpl.console.BaseConsoleManager$ClickLoader.run(BaseConsoleManager.java:2060)
at
com.sun.management.viper.util.ThreadPool$ThreadWorker.run(ThreadPool.java:138)
Caused by: java.io.InvalidClassException:
java.security.BasicPermissionCollection; local class incompatible:
stream classdesc serialVersionUID = 739301742472979399, local class
serialVersionUID = -1627748012524673683
at
java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:460)
at
java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1499)
at
java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1413)
at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1604)
at
java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1252)
at
java.io.ObjectInputStream.readObject(ObjectInputStream.java:323)
at java.util.Hashtable.readObject(Hashtable.java:799)
at sun.reflect.GeneratedMethodAccessor32.invoke(Unknown Source)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:28)
at java.lang.reflect.Method.invoke(Method.java:313)
at
java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:816)
at
java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1721)
at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1624)
at
java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1252)
at
java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1818)
at
java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1744)
at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1624)
at
java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1252)
at
java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1818)
at
java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1744)
at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1624)
at
java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1252)
at
java.io.ObjectInputStream.readObject(ObjectInputStream.java:323)
at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:300)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:149)
... 11 more
This can be easily reproduce by launching SMC on a Solaris 9 machine and connecting to a Solaris 8 1/01
or greater machine:
/usr/sadm/bin/smc
when the console comes up, invoke Console->Open Toolbox menu item
when the toolbox chooser comes up, enter the hostname of the Solaris 8 machine
in the Server field and click Load
Select "This Computer" in the Toolbox Selection list and click Ok
When the toolbox is loaded and the console is ready, double-click on one of the folders,
and then click on any of the tools under that folder.
After login, the tool will download and then execute - you will then get an authorization
error. Now you will not see the exact exception trace as above, because the tools are
not propagating up the exception, but I got that trace by insertting a printStackTrace()
at the point where the tools are eating the exception.
To better illustrate and prove the problem in a more simple case, run the following script on
any machine that has both Java 1.2 and 1.4 installed. Simply set JAVA_HOME appropriately
before each invocation of the script:
------------------------------------------------------------------------
#!/bin/sh
if [ ! -n "${JAVA_HOME}" ]; then
JAVA_HOME=/usr/java
export JAVA_HOME
fi
echo "JAVA_HOME=${JAVA_HOME}"
${JAVA_HOME}/bin/java -version
echo ""
ROOT=/tmp/serialBug
WORKDIR=${ROOT}/`basename ${JAVA_HOME}`
mkdir -p ${WORKDIR}/java/security
cd ${WORKDIR}
${JAVA_HOME}/bin/jar xvf ${JAVA_HOME}/jre/lib/rt.jar java/security/BasicPermission.class
${JAVA_HOME}/bin/jar xvf ${JAVA_HOME}/jre/lib/rt.jar java/security/BasicPermissionCollection.class
env CLASSPATH=${WORKDIR} ${JAVA_HOME}/bin/serialver java.security.BasicPermission
env CLASSPATH=${WORKDIR} ${JAVA_HOME}/bin/serialver java.security.BasicPermissionCollection
------------------------------------------------------------------------
Note how the serialVersionUIDs for BasicPermissionCollection are not the same. We must be able
to pass these objects across RMI between different JDK versions in order to manage S8 servers from
S9 clients. The solution to me seems to be to set a serialVersion UID for BasicPermissionCollection
to be the same value as computed on Java 1.2.2.
due to mismatched serialVersionUID's. This is a serious problem for client-server environments
that need to provide backwards compatibility for downloaded code.
For example, the Solaris Management Console (SMC) employs the "applet" model, whereby applications
are downloaded from an application server and executed in the SMC console. While not specifically
Java Applets, the concept is the same. Anyone running Solaris 9 can run SMC by simply entering
/usr/sadm/bin/smc at a command prompt. By default client and server are the same machine and
everything works perfectly, where the default JRE is 1.4
Similarly, the same applies to Solaris 8 1/01 or greater, where the default JRE is 1.2.2, and
all works fine.
Now, it is important that SMC running on Solaris 9 clients be able to download tools from
Solaris 8 servers and manage those S8 machines. However this fails with the following exception
trace:
java.rmi.UnmarshalException: error unmarshalling return; nested
exception is:
java.io.InvalidClassException:
java.security.BasicPermissionCollection; local class incompatible:
stream classdesc serialVersionUID = 739301742472979399, local class
serialVersionUID = -1627748012524673683
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:167)
at
com.sun.management.viperimpl.services.authorization.AuthorizeService_Container_Stub.readUserPermissions(Unknown
Source)
at
com.sun.management.viperimpl.services.authorization.AuthorizeService_Agent.readUserPermissions(Unknown
Source)
at
com.sun.admin.serialmgr.client.ServiceWrapper.init(ServiceWrapper.java:142)
at
com.sun.admin.serialmgr.client.WbemServiceWrapper.init(WbemServiceWrapper.java:72)
at
com.sun.admin.serialmgr.client.ApplicationContext.getServiceWrapper(ApplicationContext.java:140)
at
com.sun.admin.serialmgr.client.VSerialMgr.init(VSerialMgr.java:177)
at
com.sun.management.viperimpl.console.BaseConsoleManager.initializeTool(BaseConsoleManager.java:1893)
at
com.sun.management.viperimpl.console.BaseConsoleManager.handleToolInitialization(BaseConsoleManager.java:1852)
at
com.sun.management.viperimpl.console.BaseConsoleManager.loadToolAndReplaceStub(BaseConsoleManager.java:2110)
at
com.sun.management.viperimpl.console.BaseConsoleManager$ClickLoader.run(BaseConsoleManager.java:2060)
at
com.sun.management.viper.util.ThreadPool$ThreadWorker.run(ThreadPool.java:138)
Caused by: java.io.InvalidClassException:
java.security.BasicPermissionCollection; local class incompatible:
stream classdesc serialVersionUID = 739301742472979399, local class
serialVersionUID = -1627748012524673683
at
java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:460)
at
java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1499)
at
java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1413)
at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1604)
at
java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1252)
at
java.io.ObjectInputStream.readObject(ObjectInputStream.java:323)
at java.util.Hashtable.readObject(Hashtable.java:799)
at sun.reflect.GeneratedMethodAccessor32.invoke(Unknown Source)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:28)
at java.lang.reflect.Method.invoke(Method.java:313)
at
java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:816)
at
java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1721)
at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1624)
at
java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1252)
at
java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1818)
at
java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1744)
at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1624)
at
java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1252)
at
java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1818)
at
java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1744)
at
java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1624)
at
java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1252)
at
java.io.ObjectInputStream.readObject(ObjectInputStream.java:323)
at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:300)
at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:149)
... 11 more
This can be easily reproduce by launching SMC on a Solaris 9 machine and connecting to a Solaris 8 1/01
or greater machine:
/usr/sadm/bin/smc
when the console comes up, invoke Console->Open Toolbox menu item
when the toolbox chooser comes up, enter the hostname of the Solaris 8 machine
in the Server field and click Load
Select "This Computer" in the Toolbox Selection list and click Ok
When the toolbox is loaded and the console is ready, double-click on one of the folders,
and then click on any of the tools under that folder.
After login, the tool will download and then execute - you will then get an authorization
error. Now you will not see the exact exception trace as above, because the tools are
not propagating up the exception, but I got that trace by insertting a printStackTrace()
at the point where the tools are eating the exception.
To better illustrate and prove the problem in a more simple case, run the following script on
any machine that has both Java 1.2 and 1.4 installed. Simply set JAVA_HOME appropriately
before each invocation of the script:
------------------------------------------------------------------------
#!/bin/sh
if [ ! -n "${JAVA_HOME}" ]; then
JAVA_HOME=/usr/java
export JAVA_HOME
fi
echo "JAVA_HOME=${JAVA_HOME}"
${JAVA_HOME}/bin/java -version
echo ""
ROOT=/tmp/serialBug
WORKDIR=${ROOT}/`basename ${JAVA_HOME}`
mkdir -p ${WORKDIR}/java/security
cd ${WORKDIR}
${JAVA_HOME}/bin/jar xvf ${JAVA_HOME}/jre/lib/rt.jar java/security/BasicPermission.class
${JAVA_HOME}/bin/jar xvf ${JAVA_HOME}/jre/lib/rt.jar java/security/BasicPermissionCollection.class
env CLASSPATH=${WORKDIR} ${JAVA_HOME}/bin/serialver java.security.BasicPermission
env CLASSPATH=${WORKDIR} ${JAVA_HOME}/bin/serialver java.security.BasicPermissionCollection
------------------------------------------------------------------------
Note how the serialVersionUIDs for BasicPermissionCollection are not the same. We must be able
to pass these objects across RMI between different JDK versions in order to manage S8 servers from
S9 clients. The solution to me seems to be to set a serialVersion UID for BasicPermissionCollection
to be the same value as computed on Java 1.2.2.