Explicit Serialization API and Security
chris.hegarty at oracle.com
Thu Jan 15 16:37:17 UTC 2015
On 15 Jan 2015, at 12:25, Peter Firmstone <peter.firmstone at zeus.net.au> wrote:
> Can you explain some of the detail in your failure atomicity work?
The current implementation of defaultReadObject sets non-primitive field values one at a time, without first checking that all their types are assignable. If, for example, the assignment of the last non-primitive value fails, a CCE is thrown, and the previously set fields remain set. The setting of field values can be deferred until after they have been "validated", at a minimum that the non-primitive types are assignable. This is achievable per Class in the hierarchy, and provides some additional level of confidence. A change along the lines of this should not be controversial ( either all fields will be set, or contain their default values ), but it is only per Class in the hierarchy.
Pushing on this a little, and ignoring cyclic references for now. For the first Serializable type in the hierarchy ( closest to j.l.Object ), there is no need to eagerly create the instance before “validating” the field values. If the field values are assignable, then the object can created and the values assigned. If a field value is found to be unassignable, then CCE is thrown, and there is no dangling object.
Pushing a little more. If there are no readObjectXXX methods in the hierarchy, then it would seem possible to read the field values for all the types in the hierarchy, and “validate” them ( ensure they are assignable ), before creating the object and assigning the values. I do not believe that there are any observable affects from doing this.
Cyclic references: Assumption, we do not want to leak our secure deserialized objects. It seems reasonable to not share the reference in the stream. This would rule out cyclic references. If you want sharing, then the implementation would create the referenced object, and assign the already read field values, when it encounters a cyclic reference. But you open the object to anything in the stream referencing it.
readObjectXX: Assumption, many readObject methods exist to check invariants of values read from the stream. If we had another mechanism, similar to the static validate(GetFields) method we discussed previously, then may readObject methods could be eliminated. In which case we can achieve whole hierarchy failure atomicity ( as described above ).
Given this, it seems like the natural place for a static invariant checker is between the reading and reconstitution of field values, and the assigning of them. If the invariant checker could be called by the serialization mechanism then the user code can use final fields, without needing to muck around with reflection, and also have the added benefit of, in many cases, not potential leaving the object in an inconsistent state.
There is no support in this proposal for subclass to superclass invariant checking.
I also believe that we can resolve the Finalization issue separately.
More information about the core-libs-dev