Explicit Serialization API and Security
Chris Hegarty
chris.hegarty at oracle.com
Mon Jan 12 11:37:06 UTC 2015
On 08/01/15 20:10, Brian Goetz wrote:
>> 1) Validate invariants
>>
>> A clear and easy to understand mechanism that can validate the
>> deserialized
>> fields. Does not prevent the use of final fields, as the
>> serialization framework
>> will be responsible for setting them. Something along the lines
>> of what David
>> suggested:
>>
>> private static void validate(GetField fields) {
>> if (fields.getInt("lo") > fields.getInt("hi")) { ... }
>> }
>>
>> This could be a “special” method, or annotation driven. TBD.
>>
>> Note: the validate method is static, so the object instance is
>> not required to
>> be created before running the validation.
>
> Sort of...
>
> This is true if the fields participating in the invariant are
> primitives. But if they're refs, what do you do? What if you want to
> validate something like
>
> count == list.size() // fields are int count, List list
>
> ? Then wouldn't GetField.getObject have to deserialize the object
> referred to by that field?
Yes it would.
For clarity, I would like to describe how things currently work.
1) Allocate a new instance of the deserialized type.
2) Call the first non-Serializable types no-arg constructor
( may be j.l.Object ).
3) For each type in the deserialized types hierarchy, starting
with the top most ( closest to j.l.Object ),
3a) create objects representing all fields values for the type
[this step is recursive and will go to 1 until all
non-primitive types have been created ]
3b) [ holder for invariant validation ]
3c) assign objects to their respective members of the
containing instance
[ For simplicity, ignore cyclic references are readObjectXXX for now,
I will address them separately. ]
Without any user visible side-effects, no readObjectXXX methods, it
would appear that there is no reason why 1 & 2 must happen before 3a.
Since objects representing field values are created recursively, then
all the objects representing the field values are created, per class in
the hierarchy, before being assigned. If we have no reaObjectXXX
methods, then the objects being created in 3a could be stored locally,
repeating 3a as needed, and only assign after all types in the hierarchy
have been walked. Essentially the sequence of steps could be, 3, 3a+,
[3b], 1, 2, 3c+.
Given this, an the invariant could be validated at 3b, without the need
for the creation of the containing object.
Cyclic references: If we encounter a cyclic reference, then we can
"de-optimize"; stop, create the required instances reachable in the
graph, fill in whatever fields are currently known, then continue.
readObjectXXX: Since these are instance methods then they must have
visibility to any deserialized state in the super type. These can be
handled similarly to cyclic references, but can be determine up front,
at step 3, rather than in the flow.
-Chris.
More information about the core-libs-dev
mailing list