mirror of
https://github.com/openjdk/jdk.git
synced 2026-02-16 21:35:25 +00:00
6993206: Removing non-functional tests
Reviewed-by: mchung
This commit is contained in:
parent
523d43b1e3
commit
2c65efd85c
@ -1,29 +0,0 @@
|
||||
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: $
|
||||
@ -1,86 +0,0 @@
|
||||
/*
|
||||
* @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();
|
||||
}
|
||||
}
|
||||
@ -1,31 +0,0 @@
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
@ -1,79 +0,0 @@
|
||||
#!/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
|
||||
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
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
|
||||
@ -1,79 +0,0 @@
|
||||
#!/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
|
||||
@ -1,35 +0,0 @@
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user