felix-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From David Jencks <david_jen...@yahoo.com.INVALID>
Subject Re: OSGi and ObjectInputStream.readObject() deserialization classloading
Date Thu, 03 Nov 2016 17:04:30 GMT
I think I’m repeating what Christian said….

Deseriailizing arbitrary classes usually results in a giant security exposure, as there are
exploits that result in arbitrary code execution on deserialization (not use!) of some commonly
used library class instances.  Most of the projects I’m involved in recently spent a lot
of time rewriting their ObjectInputStreams to whitelist allowable classes.

One approach I have used is for a bundle with classes that need to be deserialized to register
those class names together with the bundle with the class loading apparatus.

david jencks

> On Oct 27, 2016, at 6:11 AM, Christopher BROWN <brown@reflexe.fr> wrote:
> Hi Scott, Hi Carsten,
> Overridding ObjectInputStream::resolveClass was what I needed.  My
> "fetch" method has 3 variants:
> /* uses Thread::getContextClassLoader */
> Object fetch(String id)
> /* uses type.getClass().getClassLoader(), may not work if "type" is an
> interface or superclass, mainly useful for a bundle's internal types
> only */
> <T> T fetchAs(String id, Class<T> type)
> /* more flexible, caller must understand how things work, eg: type can
> be an interface type, the definer can be a lambda capable of providing
> a reference to an implementation bundle's classloader */
> <T> T fetchAs(String id, Class<T> type, Supplier<ClassLoader> definer)
> The last signature variant makes it possible to get similar behavior
> to the IClassResolver example suggested by Scott (the filter approach
> is clever, but might have a higher maintenance cost ; the use of a
> Supplier function makes it possible to delegate to such an
> implementation however).  I considered the PackageAdmin (bundle
> wiring) suggestion by Carsten, but I figured it might deserialise the
> wrong class version if multiple bundles define similar classes (the
> first match might be incorrect, it seems non-trivial to correctly and
> efficiently select a classloader without a "brute force, trial and
> error" approach).
> I had also considered providing my service using a ServiceFactory,
> which could access the consumer's bundle classloader automatically,
> however if the code calling "store" is in a different bundle from that
> calling "fetch", it wouldn't help much.  Perhaps it would be possible
> to combine this approach with use of WeakReferences (referring to the
> classloader of the bundle that invoked "store"), automatically
> invaliding the stored (serialized) object if the "storer" classloader
> was de-referenced... but I felt that that approach was _too_
> aggressive (because all I can assume was that the "storer" classloader
> was able to find the classloader -- via imported packages -- and not
> assume that it was the actual classloader).
> For my use cases, that seems like the best trade-off for deterministic
> behavior, small API surface, and flexibility (all the other "smart"
> cases would seem to be vulnerable to side effects).
> Thanks for your suggestions, I hope this message (once archived) is of
> use to others.
> --
> Christopher
> On 26 October 2016 at 20:21, Scott Lewis <slewis@composent.com> wrote:
>> Another (somewhat similar to Carsten's) approach to this is the one that
>> we've implemented in ECF's Remote Services/RSA implementation [1].
>> We've got a service interface:  IClassResolver [2] and a ObjectInputStream
>> subclass called ClassResolverObjectInputStream. The way that this works is
>> that when creating a ClassResolverInputStream one specifies a filter for
>> finding (via service registry) the IClassResolver service instance to use to
>> resolve the class upon first deserialization.   For example, a particular
>> bundle (with version) that is to be responsible for resolving the classes
>> (bundle.loadClass) for that ObjectInputStream [4].   Of course, other/custom
>> implementations of IClassResolver are possible as well, but so far we have
>> found the BundleClassResolver + ClassResolverObjectInputStream useful.
>> Scott
>> [1] http://wiki.eclipse.org/Eclipse_Communication_Framework_Project
>> [2]
>> http://download.eclipse.org/rt/ecf/latest/javadoc/org/eclipse/ecf/core/util/IClassResolver.html
>> [3]
>> http://download.eclipse.org/rt/ecf/latest/javadoc/org/eclipse/ecf/core/util/ClassResolverObjectInputStream.html
>> [4]
>> http://download.eclipse.org/rt/ecf/latest/javadoc/org/eclipse/ecf/core/util/BundleClassResolver.html
>> On 10/26/2016 9:03 AM, Carsten Ziegeler wrote:
>>> Christopher Brown wrote
>>>> Hello,
>>>> I need to define an API for an OSGi service capable of persisting
>>>> arbitrary
>>>> Serializable objects as byte arrays (to disk, or over the network), and
>>>> then capable of deserializing the object via the API.  The objects to be
>>>> persisted will almost always be defined by another bundle, so the bundle
>>>> actually performing the serialization is almost always going to be unable
>>>> to access the classloader that originally provided the definition of the
>>>> serialized class (and any non-primitive attributes of that class).
>>>> Any ideas upon how to use java.io.ObjectInputStream such that its
>>>> .readObject() method can be forced to use an appropriate classloader?  I
>>>> can't see how to override its default behavior.
>>>> As for the API I need to implement (my service), it would be along the
>>>> lines of:
>>>> void service.store(String id, Object value);
>>>> <T> T service.fetch(String id, Class<T> implementationType)
>>>> ...where implementationType would need to be equivalent to
>>>> value.getClass()
>>>> (and not a superclass or implemented interface).  The "fetch" method
>>>> would
>>>> need the "implementationType" parameter to access the CURRENT version of
>>>> the classloader (I can't store the classloader in the "store" method,
>>>> first
>>>> off because I can't serialize arbitrary classloaders -- via
>>>> value.getClass().getClassloader() -- and also because the classloader
>>>> might
>>>> be the wrong version, if "value" was defined by a bundle that has since
>>>> been reloaded).
>>>> Even if I replaced the "implementationType" parameter with a classloader
>>>> reference (assuming the caller of the code knew which classloader to
>>>> use),
>>>> I still don't know how to override ObjectInputStream's default
>>>> classloading
>>>> behavior.
>>>> Any ideas ?
>>> You can create a subclass of ObjectInputStream and overwrite the
>>> resolveClass method to solve the first project.
>>> Some time ago we wrote some code, that was using a dynamic class loader
>>> in such a subclass that simply used Package Admin to find the bundle
>>> providing the class and then using the corresponding class loader. Of
>>> course this requires that the classes you want to load are publicly
>>> exported.
>>> I'm not saying this is the best solution, but it did the trick for us.
>>> Regards
>>>  Carsten
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
>> For additional commands, e-mail: users-help@felix.apache.org
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
> For additional commands, e-mail: users-help@felix.apache.org

To unsubscribe, e-mail: users-unsubscribe@felix.apache.org
For additional commands, e-mail: users-help@felix.apache.org

View raw message