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 Sat, 07 Aug 2010 06:10:39 GMT
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.

Peter Firmstone wrote:
> Tim Blackman wrote:
>> On Jul 31, 2010, at 11:53 PM, Peter Firmstone wrote:
>>
>> <snip>
>>> A RevokeableDynamicPolicy supports the addition or removal of 
>>> PermissionGrant's
>>>     
>> <snip>
>>   
>
>> Hmmm.
>>
>> I remember talking with Bob and Mike Warres about this.  The problem 
>> with removing permission grants is that  when code is granted a 
>> permission, it can very likely squirrel away something -- an object, 
>> or another capability available through the granted permission -- 
>> that will permit it to perform the same operation again without the 
>> JVM checking for the permission again.  Our conclusion was that there 
>> was probably no effective way to implement removal of permission grants.
>>
>> Perhaps there is something about the particulars of what you have 
>> done here to negate this argument -- and I have not had the time to 
>> check the details of your stuff myself to be sure -- but my guess is 
>> that it will be difficult or impossible to do this in an airtight 
>> manner.
>>   
>
> First I'd better point out that this is still an experiment and may 
> not make a release, but I'm glad you've responded, as security is a 
> difficult issue and all help is appreciated.
>
> The SecurityDelegate's I mentioned earlier, are of course a 
> compromise, many existing security guards on existing Java classes are 
> on constructors or methods that return object's, however object's such 
> as OutputStream and the likes, have unguarded methods, so once these 
> objects have been released, the reference can be stored, by what may 
> later become untrusted, and the methods called by untrusted objects.
>
> The SecurityDelegate is a wrapper class that implements the same 
> interface as the guarded object, but once notified of a Permission 
> revocation ensures the next thread to access the guarded object, 
> through the SecurityDelegate has AccessController.checkPermission 
> called again.
>
> Because of the cost of the Permission check, it's too expensive to 
> call on every method invocation.
>
> However there is still a flaw in this, consider for a moment an object 
> protected by a SecurityDelegate, permission's are revoked, the policy 
> notifies all SecurityDelegate's of a revocation, they ensure the next 
> method call rechecks permission.  The flaw is that once the 
> SecurityDelegate, containing the protected object is in untrusted 
> hands, we don't know how many references to it exist.  The next call 
> might have permission, however there is no guarantee that another 
> following will.  The mixing of untrusted and trusted code is the risk.
>
> While it cannot be eliminated entirely, every method requiring 
> protection, should execute a private method something like the 
> following (Constructors and methods excluded for clarity):
>
> class ProtectedOutputStream extends OutputStream implements 
> SecurityDelegate {
>
>    private final OutputStream protected;
>    private volatile boolean check = true;
>    private volatile Thread currentThread = null;
>
>    public void notify(){
>       check = true;
>    }
>
>    private void check(){
>       if ( check == true) {
>          AccessController.checkPermission(perm);
>          currentThread = Thread.currentThread();
>          check = false;
>          return;
>       }
>       if ( currentThread != null ) {
>          if (Thread.currentThread() == currentThread ) {
>             return;
>          }
>       }
>        AccessController.checkPermission(perm);
>        currentThread = Thread.currentThread();
>        return;
>    }
>      public void write(byte[] b) {
>        check();
>        protected.write(b);
>    }
>
> }
>
> Still, I'm not sure if this is enough to protect the object, there are 
> some Thread timing issues I've ignored here, but those aside, I don't 
> want to call the AccessController every invocation, for obvious 
> efficiency reasons.
>
> Thought's and ideas?
>
> Cheers,
>
> Peter.
>
>


Mime
View raw message