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 <[email protected]> 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.


Reply via email to