DeserializationPermission Proposal

David M. Lloyd david.lloyd at redhat.com
Fri Feb 12 14:55:55 UTC 2016


Things are getting confused (for me anyway) so I'm going to try and 
spell out each idea separately.

Given a class hierarchy H of:

C -> B -> A -> NonSerializableClass -> Object

where C, B, and A are serializable classes, and protection domain M 
which is initiating deserialization, I think the following requirements 
definitely apply:

* When M deserializes an instance of A, both M and the protection domain 
of A must be sufficient to allow the deserialization of A
* When M deserializes an instance of B, both M and the protection domain 
of B must be sufficient to allow the deserialization of B
* When M deserializes an instance of C, both M and the protection domain 
of C must be sufficient to allow the deserialization of C
* Extrapolate generally

The following requirements have definite pros and cons, which is what I 
think we're touching on in this thread:

* When M deserializes an instance of B (or any subtype thereof), the 
protection domain of A must also be sufficient to allow the 
deserialization of B
* When M deserializes an instance of C (or any subtype thereof), the 
protection domains of both A and B must also be sufficient to allow the 
deserialization of C
* Extrapolate generally

Based on the above, the following requirements might or might not make 
sense:

* When M deserializes an instance of A, the protection domains of 
NonSerializableClass and also Object must also be sufficient to allow 
the deserialization of A
* Likewise for B & C, extrapolate generally

Regardless of which is the best set of requirements, one of the major 
complicating questions is, what is the ideal representation of the 
permission(s) needed to allow the above?  I can see several use cases:

1. Grant the ability for a serializable class S to deserialize itself
2. Grant the ability for M to deserialize a specific class (by name?)
3. Grant the ability to any (serializable?) class X to allow 
deserialization of a specific subtype (by name?)
4. Grant the ability to any (serializable?) class X to allow 
deserialization of any subtype (think java.lang.Object, or general (but 
harmless) base classes like java.util.EventObject)

The big problem with permissions by name is that names are completely 
relative.  It is totally valid (and happens in the wild today) that a 
serialization graph contains classes from a variety of class loaders 
which are isolated from one another - in fact, it's even possible to 
have more than one class with the same class name and the same 
superclass in the same graph!  Given this fact, a flat class namespace 
*cannot* be assumed.

I think that the *only* possible remedy for this is that it should be up 
to each class' class loader (and/or module) to determine what permission 
is required in order to deserialize that class.  In this way, the JDK 
(9) can use a permission of the form class+module name for installed 
module classes, Java EE systems could use permissions in the form of 
application+module+jar+class name for deployment, OSGi systems could use 
permissions including bundle identification information, etc.

To be secure, the default class loader implementation of this method 
would have to produce a result which causes all checks to fail, 
preventing deserialization in a security manager environment of classes 
whose class loaders do not explicitly allow for it.

On 02/12/2016 12:30 AM, Peter Firmstone wrote:
> Thanks David,
>
> I'd originally considered something like that, but I later realised I'd
> need to grant DeserializationPermission to other domains I might not
> want allow objects to be deserialized with, simply because their domain
> is included in the call stack.  It looked like it would widen the scope,
> which was contrary to the intended goal of minimising the attack
> surface.  In the end I decided to limit the context to only the domains
> of classes involved in deserialization.
>
> Cheers,
>
> Peter.
>
>> On 02/11/2016 03:52 AM, Peter Firmstone wrote:
>> >/  An example might be more useful.
>> />/
>> />/  Traditionally, when the first non serializable superclass zero
>> argument
>> />/  constructor is called, the domains of the subclasses aren't
>> present on
>> />/  the call stack.  Any security checks performed in the constructor
>> of the
>> />/  superclass will not include the subclasses domains.
>> />/
>> />/  In the proposed case, prior to construction, all domains in the
>> class
>> />/  heirarchy of the to be deserialized object via the local
>> />/  ObjectStreamClass, are added to an AccessControlContext, which is
>> then
>> />/  passed to the SecurityManager two argument permission check.
>> /
>> Sure, that makes sense; in fact this could be a very good
>> standalone/incremental enhancement.
>>
>> >/  Now an attacker will not be able to construct this object unless all
>> />/  domains have DeserializationPermission.
>> />/
>> />/  If we use the stack context, it won't contain the yet to be
>> deserialized
>> />/  classes.
>> /
>> True; perhaps the ideal solution would use the initial context plus a
>> per-deserializing-class context, so that both the original caller and
>> the class being deserialized have permissions.  This would have the
>> advantage of consistent behavior, and would also allow the PD of each
>> class to restrict whether it can be deserialized (which would apply
>> globally no matter who was doing the deserialization in the VM).
>>
>> --
>> - DML

-- 
- DML



More information about the core-libs-dev mailing list