Depth and String handling in ObjectInputFilter

Robert Olofsson robert.olofsson at digpro.se
Fri Jan 17 15:26:25 UTC 2020


Hi!

I hope this is the correct mailing list, if not please tell me.

I was looking into using a ObjectInputFilter and try to improve the
security in some old code that uses serialization. After reading and
testing a bit I think the filtering works a bit strange and that it
does not provide enough information.

I have added a small test program below that I think illustrates the
problem. Running this on java 11 or java 13 gives the same result. The
program writes a small data structure to a an ObjectOutputStream and
then reads it in again, just to see what we get from the
ObjectInputFilter.

Output of example program:
roberto at roberto-d4:~/src/java$ ~/pkg/java/jdk-13.0.1+9/bin/java SerializationTest
Depth: 1, class: class Payload, array: -1
Depth: 2, class: class java.util.ArrayList, array: -1
Depth: 2, class: class [Ljava.lang.Object;, array: 2
Depth: 3, class: class X, array: -1
Depth: 3, class: null, array: -1

Problems:
1) It is not possible to filter long strings. So even when using
   a filter a long string will lead to OutOfMemoryError. The
   javadoc for ObjectInputFilter clearly states that this is how
   it is supposed to work. My thoughts are that I ought to be
   able to reject too long strings, at least TC_LONGSTRING that
   have an 8 byte length if I understand how ObjectInputStream
   works internally.

2) I do not understand how the depth is supposed to work in the
   example program. I get depth 2 for both the ArrayList and its
   contained Object[]. My expectations is that I ought to get the
   array at depth 3. Is depth 2 how it is supposed to work?

Do you have any clarification how should I think regarding the
ObjectInputFilter?

Thanks!
/robo

----------------------------------------------------------------------
import java.io.*;
import java.util.*;

class SerializationTest {
    public static void main(String[] args)
	throws IOException, ReflectiveOperationException {
	Payload p = new Payload ();
	byte[] data;
	try (ByteArrayOutputStream baos = new ByteArrayOutputStream ();
	     ObjectOutputStream os = new ObjectOutputStream (baos)) {
	    os.writeObject (p);
	    data = baos.toByteArray ();
	}
	try (ByteArrayInputStream bais = new ByteArrayInputStream (data);
	     ObjectInputStream is = new ObjectInputStream (bais)) {
	    is.setObjectInputFilter (SerializationTest::logInput);
	    Payload pp = (Payload)is.readObject ();
	}
    }

    private static ObjectInputFilter.Status
	logInput (ObjectInputFilter.FilterInfo info) {
	System.out.println ("Depth: " + info.depth () +
			    ", class: " + info.serialClass () +
			    ", array: " + info.arrayLength ());
	return ObjectInputFilter.Status.ALLOWED;
    }
}

class Payload implements Serializable {
    List<X> ls;

    public Payload () {
	ls = new ArrayList<> ();
	ls.add (new X ("one"));
	ls.add (new X ("two"));
    }
}

class X implements Serializable {
    String x;
    public X (String x) {
	this.x = x;
    }
}
----------------------------------------------------------------------



More information about the core-libs-dev mailing list