JEP 187: Serialization 2.0

Florian Weimer fweimer at redhat.com
Thu Feb 13 11:05:05 UTC 2014


On 01/23/2014 03:30 PM, Chris Hegarty wrote:
> On 22 Jan 2014, at 15:14, Florian Weimer <fweimer at redhat.com> wrote:
>
>> On 01/22/2014 03:47 PM, Chris Hegarty wrote:
>>> On 22/01/14 13:57, Florian Weimer wrote:
>>>> On 01/14/2014 01:26 AM, mark.reinhold at oracle.com wrote:
>>>>> Posted: http://openjdk.java.net/jeps/187
>>>>
>>>> There's another aspect of the current approach to serialization that is
>>>> not mentioned: the type information does not come from the calling
>>>> context, but exclusively from the input stream.
>>>
>>> Have you overlooked resolveClass [1], or are you looking for additional
>>> context?
>>
>> I mean something slightly different, so here's a concrete example: Assume we are deserializing an instance of a class with a String field.  The current framework deserializes whatever is in the input stream, and will bail out with a ClassCastException if the deserialized object turns out unusable.  Contrast this with an alternative approach that uses the knowledge that the field String and will refuse to read anything else from the input stream.
>
> Sorry, but I may still be missing your point. From my reading of the code, CCE will only be thrown if the object being deserialized contains a field with a type that does not match the type of the similarly named field in the class loaded by the deserializing context.

This is from the method 
ObjectStreamClass.FieldReflector::setObjFieldValues(Object, Object[]), 
called indirectly from ObjectInputStream::readObject0(boolean):

                 Object val = vals[offsets[i]];
                 if (val != null &&
                     !types[i - numPrimFields].isInstance(val))
                 {
                     Field f = fields[i].getField();
                     throw new ClassCastException(
                         "cannot assign instance of " +
                         val.getClass().getName() + " to field " +
                         f.getDeclaringClass().getName() + "." +
                         f.getName() + " of type " +
                         f.getType().getName() + " in instance of " +
                           obj.getClass().getName());
                 }

So the exception is thrown after the object val has been read from the 
stream, which involves its construction and deserialization.  This means 
that you always expose the full serialization functionality, no matter 
with which types you start.

> Are you thinking specifically about corrupt/malicious streams, or evolving serializable types? Or a performance optimisation?

Mostly the former.  Sorry, I should have said so.

There are serialization frameworks which restrict the types of 
deserializable objects based on the type of the top-level object being 
requested.  Or in Java serialization terms, they won't load and 
instantiate arbitrary classes even if the programmer did not provide a 
customer, restrictive resolveClass() implementation.  I get that 
type-erased generics make it complicated to achieve this in current 
Java.  (But so is writing a correct resolveClass() because it breaks 
encapsulation.)

Knowing in advance which types to expect in the stream would allow for a 
performance optimization, but something like that could be added to the 
current framework as well.

-- 
Florian Weimer / Red Hat Product Security Team



More information about the core-libs-dev mailing list