river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Date Mon, 09 Aug 2010 11:12:39 GMT
Fred Oliver wrote:
> Peter,
>
> I'm not clear on the scope of the proposal. Do you depend on
> enumerating all of the classes for which delegates would be needed?
> How would you interpose the delegate?
>   

Revokeability is intended for downloaded code.  I have some different 
thoughts about possible implementations.  The aim is to force re 
checking of a Permission if a reduction of trust has occurred. To never 
allow references to objects with privileged functionality to escape into 
unprivileged code.  The best place is to contain the privileged 
functionality within the platform, the second best place, the client 
implementation or remotely in the Server's service provider implementation.

Many Java classes are subject to Permission checks only in their 
constructors, or obtained from checked methods or GuardedObjects, these 
Permission's are not safe to grant if they are to be later revoked, 
object references may still exist, enabling privileged functionality in 
untrusted client code.  What is needed are new Permission's that protect 
the methods and creation of these classes by using a delegate to wrap 
the class, depriving access via existing unchecked methods.   I think a 
builder class that returns OutputStreams (InputStreams, or any other 
etc), could build many different types of OutputStreams but utilise the 
same delegate.  This could be provided as part of the Apache River platform.

What I want to do, is enable a client to provide Permission's 
temporarily for a period of time to a ProtectionDomain, then revoke that 
Permission later.  I would want to do this if I utilise services from 
different servers that utilise the same proxy code, so I can re-use the 
ClassLoader and ProtectionDomain, to avoid having to use a new 
ClassLoader with re verification of  the same bytecode.  This is based 
around provisioning of proxy codebases, using Entry's to advertise the 
required codebase, version and Permission's required.

I had thought about requiring all delegates register with the revokeable 
policy, however now I'm having a change of heart, and think instead a 
class or delegate could use a MethodAccessController, with two methods 
checkPermission() and getPermission().  The RevokeableDynamicPolicy 
implementer can provide the implementation for the 
MethodAccessController interface.  Each delegate gets it's own 
MethodAccessController object (during construction) which has been 
designated a Permission to check (at construction time), from the 
policy.  The MethodAccessController implementation will have to keep a 
static set internally of all objects, the policy will require a static 
method to Enumerate over these and set them to check when the Permission 
Class matches that of a revoked Permission, probably by passing a Set of 
Classes.

This Permission check would be optimised, to call 
AccessController.checkPermission(Permission) only under the following 
conditions.

   1. If this is the first time the current thread has called a method
      (or constructor) on the delegate object.
   2. If revocation has occurred for a Permission with the same Class in
      any ProtectionDomain, since the last permission check performed on
      that thread.  The MethodAccessController keeps track of the
      threads with an object weak hash map.

The $1,000,000.00 question: Is the optimisation of only checking a 
thread once, on the assumption that if the ProtectionDomain's on that 
thread's stack are trustworthy to access the method, the code involved 
in this thread can still be trusted until a Permission that implies it 
has become revoked?  Remembering that the code was originally trusted, 
the object constructed with the Permission check performed, utilised by 
that code for a period of time, but now now that Permission has been 
revoked any method called on the delegate throws an 
AccessControlException. 

The only way the code could still have the Permission is if the 
ProtectionDomain doesn't exist on the thread's stack, at the time of the 
permission check, the check field is cleared for that thread and later, 
the thread invokes the method with the ProtectionDomain in question on 
it's stack, however to do so, the code in question must already hold a 
reference, but not be involved in the current operations, it seems the 
probability would be very low, the reference would have to be passed 
from another thread, if an attacker could place this in the code, they'd 
be better off attacking during the privileged period.  The Permission 
revoked code would stop privileged operations during re verification of 
trust for another proxy object and server.

Static fields within the code could be used to store information between 
service proxy's, this has a parallel to applets, where this was fixed 
with separate ClassLoader, the client has that option however.

Publicly shared proxy and service implementations can have their source 
audited.

> As an example, I think you propose that if code in a domain has a
> socket open on a port for which access is later revoked, the code
> should be denied further read/write access to the socket.
>
> -Should the socket be left open or closed?
>   
Closed, to free the port.  If somehow it is shared between threads, the 
other thread will receive an IOException.
> -Was a delegate introduced and where?
>   
The best place is in a builder or factory method, since constructors 
create a dependency link.  I'm thinking of a implementing new Platform 
class or builder for the various Stream classes, along with new Permission's
> -Can the code use reflection to bypass the delegate?
>   
Yes, if it has Permission.
> -Is reflection denied generally?
>   
Yes, it should not be granted to code that will have Permission's revoked.
> Thanks,
>   
Your welcome, & thanks for asking too ;)

Cheers,

Peter.
> Fred
>
> On Sat, Aug 7, 2010 at 2:10 AM, Peter Firmstone <jini@zeus.net.au> wrote:
>   
>> Please help identify any fallacies or oversights in the following arguments.
>>
>> A Permission may be revoked, at any point in time after a revocation,
>> untrusted code may hold a reference to a privileged object.
>>
>> Some Permission's protect methods, such as Thread.interrupt(), these are
>> effectively revoked with the existing Java security model, however other
>> objects are only protected in their constructor, the responsibility being on
>> the trusted code, not to let their references escape, such as
>> FileOutputStream.
>>
>> The moment code holding a reference becomes untrusted, the reference has
>> escaped.
>>
>> Instead of using a GuardedObject, or checking permission in constructors, to
>> deal with Permission's that can be revoked, we need to encapsulate the
>> object that needs protection with a SecurityDelegate.
>>
>> During a checkPermission call, the current Thread's AccessControlContext is
>> obtained, and (gross simplification) is asked to checkPermission.  The
>> AccessControlContext contains all the ProtectionDomain's on the stack, all
>> ProtectionDomains on the stack must have the Permission for it to succeed.
>>  The ProtectionDomain's contained by the AccessControlContext are related to
>> the class and object methods called and returned, the ProtectionDomain's are
>> dynamically added or removed.
>>
>> So the thinking behind the SecurityDelegate's private check method is that
>> an object must be protected in a dynamically changing environment:
>>
>>  1. Has the RevokeableDynamicPolicy advised that a check must be
>>     performed?
>>  2. Is this the same thread that the last security check was made
>>     against?  If we haven't been advised that there is a reduction of
>>     trust in our dynamic Security environment and the last
>>     checkPermission call succeeded on this thread, then we can assume
>>     that this Tread is still safe.
>>  3. If this thread is different or new, then we must checkPermission,
>>     regardless of whether trust has changed recently or not.
>>
>> The costs:
>>
>>  1. Multi-threading is penalised (although a WeakMap could be
>>     utilised, with threads as keys, and boolean check values, where
>>     all are set true by the notify() call).
>>  2. The three "if" calls on every method invocation, check, null and
>>     == Thread.
>>  3. Replicating the check method on all implementers (this will
>>     require a helper class to implement the check).
>>  4. The RevokeableDynamicPolicy will need to notify all
>>     SecurityDelegate's every time a reduction in trust occurs, it will
>>     rely on GC to clean up and remove SecurityDelegates.
>>
>> The assumption is if the current Thread was trustworthy last call and the
>> environment hasn't experienced a reduction of trust, we can still trust this
>> thread.  There is of course a risk that a Thread may have a new
>> ProtectionDomain on it's stack that isn't trusted, however this could still
>> happen in the case of the guarded object, where the environment doesn't
>> experience a reduction of trust and the trusted code must be trusted not to
>> let the reference escape it's own ProtectionDomain.  Any code that
>> experiences a reduction of trust will receive an AccessControlException.
>>
>> Cheers,
>>
>> Peter.
>>     
>
>   


Mime
View raw message