You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@river.apache.org by Peter Firmstone <ji...@zeus.net.au> on 2010/08/01 05:53:30 UTC
Learnings from a RevokeableDynamicPolicy & A Future Roadmap
A Brief evolution of java.security.Policy providers and Jini Security,
please correct me where necessary.
Prior to Jini 2.0 security was left up to implementing developers, the
standard tools available in Java 1.2 were insufficient. You had to
implement your own SecurityManager. Or you could define Security
policy's in policy files. The AccessController still consulted the
ProtectionDomain, but the ProtectionDomain Permission's were static and
unchanging. You could implement your own policy provider for
java.security.Policy, by there was no way you could guarantee updates to
the ProtectionDomain with any changes, the ProtectionDomain used the
Policy.getPermissions(ProtectionDomain) call to obtain the
PermissionCollection from the Policy.
To enable the Jini 2.0 Security infrastructure, Sun made changes to Java
itself, in Java 1.4 ProtectionDomain's were given a new constructor
that enabled the ProtectionDomain to consult an external Policy
Provider, and the java.security.Policy gained the
implies(ProtectionDomain, Permission) method, allowing the
ProtectionDomain to consult the Policy, Jini 2.0 took advantage of this
with the DynamicPolicyProvider. This Policy system is a permissive
system, that is security was only ever relaxed, it cannot be tightened
without restarting the JVM.
Now we have taken a new evolutionary step, inspired by Sun's Neuromancer
Research Project's additional security needs, for a distributed object
registry, we now have a RevokeableDynamicPolicy interface.
RevokeableDynamicPolicy wouldn't be possible to implement without the
changes to Java 1.4 Security that were prompted by Jini 2.0.
A RevokeableDynamicPolicy relies on the following features inherent in Java:
* ProtectionDomain's new dynamic 4 parameter constructor support for
dynamic Policy's, supplied with a null PermissionCollection. Added
in Java 1.4
* Not returning any PermissionCollection's belonging to dynamic
grants via either of Policy.getPermissions(*) methods. Only those
belonging to underlying static Policy providers will be returned.
* Total reliance on Policy.implies(ProtectionDomain, Permission)
added in Java 1.4
A RevokeableDynamicPolicy supports the addition or removal of
PermissionGrant's
* PermissionGrant.implies(ProtectionDomain), is the main feature of
the RevokeableDynamicPolicy.
* PermissionGrant is an interface.
* A PermissionGrant can be implemented by anyone, but the
implementing codebase must have a RuntimePermission for
"getProtectionDomain" and GrantPermission for the Permission's it
will grant.
* A PermissionGrant can use any means it can to determine if it
implies a ProtectionDomain, if it does the RevokeableDynamicPolicy
will add Permission's to the PermissionCollection cached for that
ProtectionDomain by calling PermissionGrant.getPermissions();
* To remove a PermissionGrant, you must have RevokePermission.
What I discovered when implementing a Concurrent version of
RevokeableDynamicPolicy:
* PermissionCollection.elements() returned an
Enumeration<Permission> that would throw a
ConcurrentModificationException, when Permission's were added to
the backing PermissionCollection.
* java.security.Permissions is a heterogeneous PermissionCollection
implementation, it's a point of contention for threads. It needed
a concurrent replacement.
* The replacement,
org.apache.river.imp.security.policy.ConcurrentPermissions
implements a threadsafe alternative for Permissions that prevents
Enumeration<Permission> from throwing
ConcurrentModificationException by caching.
* Now it is possible for Policy.implies(ProtectionDomain,
Permission) calls to occur concurrently during adding or removal
of PermissionGrant's. Policy.elements() Enumeration<Permission>
can also be enumerated during adding or removal of
PermissionGrant's or implies() calls.
* UmbrellaGrantPermission's have been added to
org.apache.river.imp.security.policy.DynamicConcurrentPolicyProvider,
so you can minimise the size of Policy files for GrantPermission's.
* This implementation passes all the existing qa harness and jtreg
tests for DynamicPolicy.
* Please feel free to assist by creating new tests for Concurrency
(many threads, hammer all methods).
What's next:
* Adding new methods to net.jini.security.Security to provide
support for PermissionGrant's and RevokeableDynamicPolicy.
* Creating an Entry that provides PermissionGrantBuilder's to assist
the client to restrict the Permission's to those that are
acceptable to the client and only those needed by the Service.
* Utilising the new org.apache.river.imp.util.PolicyParser interface
(this may be added to the api at a later date), standard java
policy file syntax can be parsed by the provided
DefaultPolicyParser (courtesy Apache Harmony) and will return
PermissionGrant's, the PermissionGrant's can return
PermissionGrantBuilder's that can be used in Entry's
* We can add standard java policy files to our downloadable jar
archives, we just need a utility class that generates the
PermissionGrantBuilder Entry's for us.
* The new PolicyParser allows parsing of URL based policy files.
* A Distributed Object Registry, inspired by Project Neuromancer,
utilising distributed hash tables to track the location of objects.
The bigger picture, A Future Roadmap:
* Standardise the use of a Parent ClassLoader in the ClassLoader
hierarchy (tree) above all client and service implementation and
proxy ClassLoader's so that the implementations can all
communicate using COMMON SERVICE INTERFACES.
* Standardise jar file naming to assist ClassLoader layout, see
https://issues.apache.org/jira/browse/RIVER-341
* Create a new ServiceStarter / ClientStarter to setup the
ClassLoader tree based on the new naming scheme.
* Codebase Entry's and Client Codebase Provisioning.
* jeri Endpoint implementations to traverse firewalls.
* DNS-SD for Internet Unicast Discovery.
* StreamServiceRegistrar - for the Internet with delayed
Unmarshalling of Service Proxy's
* A new URL Handler for CodeBase's with Version information for
Provisioning.
RevokeableDynamicPolicy and StreamServiceRegistrar lookup filter
chaining makes it possible to:
* Lookup Services by common Codebase Entry's
* Process ResultStream using chained and nested ServiceItemFilters:
1. ServiceItemFilter at the client by comparison of Entry
contents < > =.
2. ServiceItemFilter to Unmarshall Proxy, Provision CodeSource
3. ServiceItemFilter to check Method Constraints
4. ServiceItemFilter to Dynamically Grant Permission's based on
Entry as deemed acceptable.
5. ServiceItemFilter to Perform operation on Proxy
6. ServiceItemFilter to Dynamically Revoke Permission's based.
7. ServiceItemFilter to Throw away Proxy reference
8. While next, Goto 2 repeat process, can utilise same
ClassLoader as previous Service Proxy for speed, no need to
downlaod, reload and re verify bytecodes for CodeSource.
* ResultStream's are like an Enumeration, but are concurrent, used
like a stream, a null result indicates end of ResultStream.
Best Regards,
Peter Firmstone.
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Peter Firmstone wrote:
>
>
> What I discovered when implementing a Concurrent version of
> RevokeableDynamicPolicy:
>
> * PermissionCollection.elements() returned an
> Enumeration<Permission> that would throw a
> ConcurrentModificationException, when Permission's were added to
> the backing PermissionCollection.
> * java.security.Permissions is a heterogeneous PermissionCollection
> implementation, it's a point of contention for threads. It needed
> a concurrent replacement.
> * The replacement,
> org.apache.river.imp.security.policy.ConcurrentPermissions
> implements a threadsafe alternative for Permissions that prevents
> Enumeration<Permission> from throwing
> ConcurrentModificationException by caching.
> * Now it is possible for Policy.implies(ProtectionDomain,
> Permission) calls to occur concurrently during adding or removal
> of PermissionGrant's. Policy.elements() Enumeration<Permission>
> can also be enumerated during adding or removal of
> PermissionGrant's or implies() calls.
Policy.elements() - correction this should be
PermissionCollection.elements() as shown earlier, this is the method
that returns the Enumeration<Permission>, Enumerating a standard
PermissionCollection causes a ConcurrentModificationException, if the
PermissionCollection is mutated (add(Permission) is called) at the same
time.
> * UmbrellaGrantPermission's have been added to
>
> org.apache.river.imp.security.policy.DynamicConcurrentPolicyProvider,
> so you can minimise the size of Policy files for GrantPermission's.
> * This implementation passes all the existing qa harness and jtreg
> tests for DynamicPolicy.
> * Please feel free to assist by creating new tests for Concurrency
> (many threads, hammer all methods).
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Hi Gregg,
I'll try having another look later, was looking in trunk but didn't find
any java source, then got an Internal Server Error.
Cheers,
Peter.
Gregg Wonderly wrote:
> For quite some time, I've been using a package that I put together
> which uses XML to create an interface and a SecurityDelegate as you
> describe below. It was embedded in one of my applications for some
> time, but a few years back, I pulled it out into a separate codebase
> so that I could use it in several other projects which had grown to
> need more granular security control.
>
> I've put it out on authlib.dev.java.net. There really is not a lot of
> documentation at this point. This is more or less a "throw it over
> the wall" move.
>
> Here's a summary of how it is used, and how it works.
>
> It provides for the definition of users and groups/roles. There is a
> whole GUI component to the code which allows editing. This data is
> access/stored using a JDBC based backing store.
>
> The class, org.wonderly.authlib.BuildAccess processes the XML file.
> There is a sample XML file which shows most of what is possible, but
> the parsing in BuildAccess is the real clue to what is possible.
>
> There are object types, which you designate the type of permission
> that applies to that object. An example from the access.xml in the
> CVS tree is:
>
> <object type="view" access="update,read"
> permission="PermissionTwo"/>
>
> This says that there are parameters in method class which are "view"
> type references. PermissionTwo is used to control access to those
> type objects. The "access" attribute represents the types of
> permissions that the permission implementation supports for its
> "access" parameter during construction.
>
> A single method definition looks like the following:
>
> <method return="String" name="getDBUnitView" qualifiers="public">
> <descr>
> This method is used to get the description of the named view.
> </descr>
> <security>
> <filter access="read" filtered="view" filteredType="String"
> params="view" filterGeneric="String"
> class="TestUpdateAuthFilter"/>
> <!-- limit access="read" type="view" arg="view"/ -->
> </security>
> <args>
> <arg name="view" type="String" descr="name of the view to
> get the definition of"/>
> </args>
> <exceptions>
> <throws name="SQLException" descr="when a database access
> error occurs"/>
> </exceptions>
> </method>
>
> The method signature and JavaDoc is generated from this definition.
>
> The security section says that a filter operation should be performed
> to return the value if it is accessible, instead of throwing an
> exception as <limit> does.
> The class, TestUpdateAuthFilter performs the filtering operation. It
> implements a standard interface to define how the filtering works.
>
> Here's the generated code:
>
> public String getDBUnitView( String view ) throws
> java.rmi.RemoteException , SQLException {
> // Check for required access rights.
> String XXXval = null;
> String XXXtype = "filter";
> String XXXaccess = "read";
>
>
> try {
> // Call the method, authorization passes
> // Get Initial data
> String XXXlist = XXXacc.getDBUnitView( view );
> UpdateAuthFilter<String> XXXfilt = null;
> try {
> XXXfilt = new TestUpdateAuthFilter<String>();
> } catch( RuntimeException ex ) {
> log.log( Level.SEVERE, ex.toString(), ex );
> throw new AuthorizationException(
> ex.toString(), ex );
> }
> String XXXret = XXXfilt.filterList( new Object[] {view},
> XXXlist, "read", XXXauth, XXXdb );
> secureLog( Level.INFO, "{0}[{1}]:
> "+"getDBUnitView("+view+") ==> "+XXXret,
> XXXauth.getUserName(), XXXaccess );
> return XXXret;
> } catch( RuntimeException ex ) {
> // Make the exception source visible
> log.log( Level.SEVERE, ex.toString(), ex );
> // Rethrow it to stop the operation
> throw ex;
> }
> }
>
> There's a quite a bit more I can talk about and document, but I just
> wanted to throw this out. It's licensed under the Apache license, but
> I did not put the license into every source file, yet.
>
> Gregg Wonderly
>
> Peter Firmstone 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.
>>
>> 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.
>>>
>>>
>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Gregg Wonderly <gr...@wonderly.org>.
For quite some time, I've been using a package that I put together which uses
XML to create an interface and a SecurityDelegate as you describe below. It was
embedded in one of my applications for some time, but a few years back, I pulled
it out into a separate codebase so that I could use it in several other projects
which had grown to need more granular security control.
I've put it out on authlib.dev.java.net. There really is not a lot of
documentation at this point. This is more or less a "throw it over the wall"
move.
Here's a summary of how it is used, and how it works.
It provides for the definition of users and groups/roles. There is a whole GUI
component to the code which allows editing. This data is access/stored using a
JDBC based backing store.
The class, org.wonderly.authlib.BuildAccess processes the XML file. There is a
sample XML file which shows most of what is possible, but the parsing in
BuildAccess is the real clue to what is possible.
There are object types, which you designate the type of permission that applies
to that object. An example from the access.xml in the CVS tree is:
<object type="view" access="update,read"
permission="PermissionTwo"/>
This says that there are parameters in method class which are "view" type
references. PermissionTwo is used to control access to those type objects. The
"access" attribute represents the types of permissions that the permission
implementation supports for its "access" parameter during construction.
A single method definition looks like the following:
<method return="String" name="getDBUnitView" qualifiers="public">
<descr>
This method is used to get the description of the named view.
</descr>
<security>
<filter access="read" filtered="view" filteredType="String"
params="view" filterGeneric="String" class="TestUpdateAuthFilter"/>
<!-- limit access="read" type="view" arg="view"/ -->
</security>
<args>
<arg name="view" type="String" descr="name of the view to get the definition
of"/>
</args>
<exceptions>
<throws name="SQLException" descr="when a database access error occurs"/>
</exceptions>
</method>
The method signature and JavaDoc is generated from this definition.
The security section says that a filter operation should be performed to return
the value if it is accessible, instead of throwing an exception as <limit> does.
The class, TestUpdateAuthFilter performs the filtering operation. It implements
a standard interface to define how the filtering works.
Here's the generated code:
public String getDBUnitView( String view ) throws
java.rmi.RemoteException , SQLException {
// Check for required access rights.
String XXXval = null;
String XXXtype = "filter";
String XXXaccess = "read";
try {
// Call the method, authorization passes
// Get Initial data
String XXXlist = XXXacc.getDBUnitView( view );
UpdateAuthFilter<String> XXXfilt = null;
try {
XXXfilt = new TestUpdateAuthFilter<String>();
} catch( RuntimeException ex ) {
log.log( Level.SEVERE, ex.toString(), ex );
throw new AuthorizationException(
ex.toString(), ex );
}
String XXXret = XXXfilt.filterList( new Object[] {view},
XXXlist, "read", XXXauth, XXXdb );
secureLog( Level.INFO, "{0}[{1}]:
"+"getDBUnitView("+view+") ==> "+XXXret,
XXXauth.getUserName(), XXXaccess );
return XXXret;
} catch( RuntimeException ex ) {
// Make the exception source visible
log.log( Level.SEVERE, ex.toString(), ex );
// Rethrow it to stop the operation
throw ex;
}
}
There's a quite a bit more I can talk about and document, but I just wanted to
throw this out. It's licensed under the Apache license, but I did not put the
license into every source file, yet.
Gregg Wonderly
Peter Firmstone 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.
>
> 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.
>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Patricia Shanahan <pa...@acm.org>.
Peter Firmstone wrote:
...
> Basically: Method call from new thread? Permission check. Permission
> revoked? Permission check again. Previously checked Thread, no relevant
> revocation's since (of same Class<Permission>)? Don't check again,
> return quickly.
>
> The assumption I've made is, it will be very difficult for an attacker
> to predict when a thread will access a method on the delegate, then
> later, be called by that very same thread, so his class can call the
> delegate unchecked. Any thoughts on this? Am I overlooking something?
...
What are the implications of all this for TaskManager? I have not yet
investigated whether it is used to run proxy code, but some proxy
actions seem like natural parallel tasks, so it should be permitted.
There is no association between each TaskManager thread and any
particular subset of its tasks. The timing is somewhat controllable
through runAfter decisions. A task can sit around on the TaskManager
queue returning false from runAfter until a task of some specified type
has just run.
Patricia
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Has anyone spotted the security flaw? The revoke method shouldn't
return the Reaper, it should perform it instead before the write lock is
released.
At first glance, there appears to be a lot going on in the ecm object,
the size of the collections are minimised by the following strategies:
1. When a Permission goes out of scope, it becomes weakly reachable,
it, along with the Set of AccessControlContext's are removed from
the cache by garbage collection. Most Permission checks create a
Permission at the time of checking, so the Permission goes out of
scope quickly. Remember the Permission checks performed by the
ECM are intended to be repeated in succession, such that an
initial check is made and provided the AccessControlContext hasn't
changed, no further checks are made.
2. The execution cache keeps track of the Threads that are within the
try finally block, these are added and removed during very short
intervals, until at the time of revocation the write lock is
obtained. The execution cache is guaranteed to be cleaned as the
end() method is always executed by finally.
3. Set's are used to avoid duplication.
4. Threads cannot be confused with each other, making it easy to
determine when a thread is in the current execution cache.
5. The revocation is not considered complete until the policy revoke
method has completed. There is a period where trust is reduced,
during revocation, but revocation is not complete.
Peter Firmstone wrote:
> Fred,
>
> Does this look more like it?
>
> Multiple policy, multiple Permission checks, and an execution cache to
> minimise re checking during revocation.
>
> it's used like this:
>
> ecm.begin(reaper);
> try{
> ecm.checkPermission(p);
> ecm.checkPermission(q);
> // Do something briefly
> return something;
> } finally {
> ecm.end();
> }
>
> /*
> * Licensed to the Apache Software Foundation (ASF) under one
> * or more contributor license agreements. See the NOTICE file
> * distributed with this work for additional information
> * regarding copyright ownership. The ASF licenses this file
> * to you under the Apache License, Version 2.0 (the
> * "License"); you may not use this file except in compliance
> * with the License. You may obtain a copy of the License at
> *
> * http://www.apache.org/licenses/LICENSE-2.0
> *
> * Unless required by applicable law or agreed to in writing, software
> * distributed under the License is distributed on an "AS IS" BASIS,
> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> * See the License for the specific language governing permissions and
> * limitations under the License.
> */
>
> package org.apache.river.imp.security.policy.se;
>
> import java.security.AccessControlContext;
> import java.security.AccessControlException;
> import java.security.AccessController;
> import java.security.Permission;
> import java.util.Collections;
> import java.util.HashMap;
> import java.util.HashSet;
> import java.util.Iterator;
> import java.util.Map;
> import java.util.Set;
> import java.util.concurrent.ConcurrentHashMap;
> import java.util.concurrent.ConcurrentMap;
> import java.util.concurrent.locks.Lock;
> import java.util.concurrent.locks.ReadWriteLock;
> import java.util.concurrent.locks.ReentrantReadWriteLock;
> import org.apache.river.api.security.ExecutionContextManager;
> import org.apache.river.api.security.Reaper;
> import org.apache.river.imp.util.ConcurrentWeakIdentityMap;
>
> /**
> * Only a Single instance of ECM is required per policy, it is threadsafe.
> * Threads will wait until revoke is complete.
> *
> * @author Peter Firmstone
> */
> public class ECM implements ExecutionContextManager{
> private final ConcurrentMap<Permission,Set<AccessControlContext>>
> checkedCache;
> private final ConcurrentMap<AccessControlContext, Set<Thread>>
> executionCache;
> private final ConcurrentMap<Thread, Set<AccessControlContext>>
> threadAssociation;
> private final ConcurrentMap<Thread, Reaper> association;
> private final ReadWriteLock blockLock;
> private final Lock rl; // This lock is held briefly by callers of
> begin and end.
> private final Lock wl; // This lock is held by revocation.
> ECM(){
> checkedCache = new ConcurrentWeakIdentityMap<Permission,
> Set<AccessControlContext>>();
> executionCache = new ConcurrentHashMap<AccessControlContext,
> Set<Thread>>();
> threadAssociation = new ConcurrentHashMap<Thread,
> Set<AccessControlContext>>();
> association = new ConcurrentHashMap<Thread, Reaper>();
> blockLock = new ReentrantReadWriteLock();
> rl = blockLock.readLock();
> wl = blockLock.writeLock();
> }
> Set<Reaper> revoke(Set<Permission> perms){
> wl.lock();
> try {
> /* This is where we determine what needs to be revoked, we first
> * get all the AccessControlContexts for the Permission class,
> * these are removed from the checkedCache, then we narrow
> * down the AccessControlContext's to only those in the
> * execution cache, each AccessControlContext in the execution
> cache
> * has checkPermission(Permission) called for each revoked
> * permission. Any that throw AccessControlException will be
> * caught and have their Reaper run, for the Threads referenced
> * from that AccessControlContext.
> *
> * The RevokeableDynamicPolicy will have updated the current
> * Permission's after revocation, so the ProtectionDomain's in
> * the AccessControlContext will now throw an
> AccessControlException
> * if the revocation applied to them.
> *
> * The wl lock will be released, any threads that were interrupted
> * will exit through the finally block and remove themselves
> * from the execution cache. Those that aren't may throw
> * an exception and bubble up the stack, due to closing sockets
> * etc.
> *
> * The execution cache is comprised of the following fields:
> * executionCache
> * threadAssociation
> */
> // Identify Permission's with matching class files to those
> revoked.
> Set<Class> permClasses = new HashSet<Class>();
> Iterator<Permission> itp = perms.iterator();
> while (itp.hasNext()){
> permClasses.add(itp.next().getClass());
> }
> // Remove Permission's and AccessControlContexts from the
> checked cache.
> Map<Permission, Set<AccessControlContext>> removed =
> new HashMap<Permission, Set<AccessControlContext>>();
> Iterator<Permission> keysIt = checkedCache.keySet().iterator();
> while (keysIt.hasNext()){
> Permission p = keysIt.next();
> if (permClasses.contains(p.getClass())){
> Set<AccessControlContext> a = checkedCache.get(p);
> keysIt.remove();
> removed.put(p, a);
> } }
> // Match the AccessControlContexts with the execution cache;
> Set<AccessControlContext> exCache = executionCache.keySet();
> // Get the AccessControlContext's in the execution cache that
> fail.
> Set<AccessControlContext> accFails = new
> HashSet<AccessControlContext>();
> Iterator<Permission> retests = removed.keySet().iterator();
> while (retests.hasNext()){
> Permission p = retests.next();
> Set<AccessControlContext> rechecks = removed.get(p);
> Iterator<AccessControlContext> recheck = rechecks.iterator();
> while (recheck.hasNext()){
> AccessControlContext a = recheck.next();
> if (accFails.contains(a)) continue;
> // This really narrows down the checks.
> if (exCache.contains(a)){
> try {
> a.checkPermission(p);
> } catch (AccessControlException e){
> accFails.add(a);
> }
> }
> }
> }
> // Identify the threads and prepare reapers.
> Set<Reaper> reapers = new HashSet<Reaper>();
> Iterator<AccessControlContext> failedAcc = accFails.iterator();
> while (failedAcc.hasNext()){
> AccessControlContext fail = failedAcc.next();
> Set<Thread> threads = executionCache.get(fail);
> Iterator<Thread> i = threads.iterator();
> while (i.hasNext()) {
> Thread t = i.next();
> Reaper r = association.get(t);
> r.put(t);
> reapers.add(r);
> } }
> return reapers;
> } finally {
> wl.unlock();
> }
> }
>
> public void begin(Reaper r) {
> Thread currentThread = Thread.currentThread();
> association.put(currentThread, r); }
>
> public void checkPermission(Permission p) throws
> AccessControlException {
> Thread currentThread = Thread.currentThread();
> AccessControlContext executionContext = AccessController.getContext();
> rl.lock();
> try {
> // execution cache.
> Set<Thread> exCacheThreadSet =
> executionCache.get(executionContext);
> if ( exCacheThreadSet == null ){
> exCacheThreadSet = Collections.synchronizedSet(new
> HashSet<Thread>());
> Set<Thread> existed =
> executionCache.putIfAbsent(executionContext, exCacheThreadSet);
> if (existed != null){
> exCacheThreadSet = existed;
> }
> }
> exCacheThreadSet.add(currentThread);// end execution cache.
> // thread association
> Set<AccessControlContext> thAssocSet =
> threadAssociation.get(currentThread);
> if ( thAssocSet == null ){
> thAssocSet = Collections.synchronizedSet(new
> HashSet<AccessControlContext>());
> Set<AccessControlContext> existed =
> threadAssociation.putIfAbsent(currentThread, thAssocSet);
> if (existed != null){
> thAssocSet = existed;
> }
> }
> thAssocSet.add(executionContext); // end thread association.
> // checkedCache - the permission check.
> Set<AccessControlContext> checked = checkedCache.get(p);
> if (checked == null ){
> checked = Collections.synchronizedSet(new
> HashSet<AccessControlContext>());
> Set<AccessControlContext> existed = checkedCache.putIfAbsent(p,
> checked);
> if (existed != null){
> checked = existed;
> }
> }
> if ( checked.contains(executionContext)) return; // it's passed
> before.
> executionContext.checkPermission(p); // Throws
> AccessControlException
> // If we get here cache the AccessControlContext.
> checked.add(executionContext); // end checkedCache. }
> finally {
> rl.unlock();
> }
> }
>
> public void end() {
> // Teardown.
> Thread t = Thread.currentThread();
> rl.lock();
> try {
> association.remove(t);
> Set<AccessControlContext> accSet = threadAssociation.remove(t);
> Iterator<AccessControlContext> it = accSet.iterator();
> while (it.hasNext()){
> AccessControlContext acc = it.next();
> executionCache.get(acc).remove(t);
> }
> }finally {
> rl.unlock();
> }
> }
>
> }
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred,
Does this look more like it?
Multiple policy, multiple Permission checks, and an execution cache to
minimise re checking during revocation.
it's used like this:
ecm.begin(reaper);
try{
ecm.checkPermission(p);
ecm.checkPermission(q);
// Do something briefly
return something;
} finally {
ecm.end();
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.river.imp.security.policy.se;
import java.security.AccessControlContext;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.Permission;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.river.api.security.ExecutionContextManager;
import org.apache.river.api.security.Reaper;
import org.apache.river.imp.util.ConcurrentWeakIdentityMap;
/**
* Only a Single instance of ECM is required per policy, it is threadsafe.
* Threads will wait until revoke is complete.
*
* @author Peter Firmstone
*/
public class ECM implements ExecutionContextManager{
private final ConcurrentMap<Permission,Set<AccessControlContext>>
checkedCache;
private final ConcurrentMap<AccessControlContext, Set<Thread>>
executionCache;
private final ConcurrentMap<Thread, Set<AccessControlContext>>
threadAssociation;
private final ConcurrentMap<Thread, Reaper> association;
private final ReadWriteLock blockLock;
private final Lock rl; // This lock is held briefly by callers of
begin and end.
private final Lock wl; // This lock is held by revocation.
ECM(){
checkedCache = new ConcurrentWeakIdentityMap<Permission,
Set<AccessControlContext>>();
executionCache = new ConcurrentHashMap<AccessControlContext,
Set<Thread>>();
threadAssociation = new ConcurrentHashMap<Thread,
Set<AccessControlContext>>();
association = new ConcurrentHashMap<Thread, Reaper>();
blockLock = new ReentrantReadWriteLock();
rl = blockLock.readLock();
wl = blockLock.writeLock();
}
Set<Reaper> revoke(Set<Permission> perms){
wl.lock();
try {
/* This is where we determine what needs to be revoked, we first
* get all the AccessControlContexts for the Permission class,
* these are removed from the checkedCache, then we narrow
* down the AccessControlContext's to only those in the
* execution cache, each AccessControlContext in the execution cache
* has checkPermission(Permission) called for each revoked
* permission. Any that throw AccessControlException will be
* caught and have their Reaper run, for the Threads referenced
* from that AccessControlContext.
*
* The RevokeableDynamicPolicy will have updated the current
* Permission's after revocation, so the ProtectionDomain's in
* the AccessControlContext will now throw an AccessControlException
* if the revocation applied to them.
*
* The wl lock will be released, any threads that were interrupted
* will exit through the finally block and remove themselves
* from the execution cache. Those that aren't may throw
* an exception and bubble up the stack, due to closing sockets
* etc.
*
* The execution cache is comprised of the following fields:
* executionCache
* threadAssociation
*/
// Identify Permission's with matching class files to those revoked.
Set<Class> permClasses = new HashSet<Class>();
Iterator<Permission> itp = perms.iterator();
while (itp.hasNext()){
permClasses.add(itp.next().getClass());
}
// Remove Permission's and AccessControlContexts from the
checked cache.
Map<Permission, Set<AccessControlContext>> removed =
new HashMap<Permission, Set<AccessControlContext>>();
Iterator<Permission> keysIt = checkedCache.keySet().iterator();
while (keysIt.hasNext()){
Permission p = keysIt.next();
if (permClasses.contains(p.getClass())){
Set<AccessControlContext> a = checkedCache.get(p);
keysIt.remove();
removed.put(p, a);
}
}
// Match the AccessControlContexts with the execution cache;
Set<AccessControlContext> exCache = executionCache.keySet();
// Get the AccessControlContext's in the execution cache that fail.
Set<AccessControlContext> accFails = new
HashSet<AccessControlContext>();
Iterator<Permission> retests = removed.keySet().iterator();
while (retests.hasNext()){
Permission p = retests.next();
Set<AccessControlContext> rechecks = removed.get(p);
Iterator<AccessControlContext> recheck = rechecks.iterator();
while (recheck.hasNext()){
AccessControlContext a = recheck.next();
if (accFails.contains(a)) continue;
// This really narrows down the checks.
if (exCache.contains(a)){
try {
a.checkPermission(p);
} catch (AccessControlException e){
accFails.add(a);
}
}
}
}
// Identify the threads and prepare reapers.
Set<Reaper> reapers = new HashSet<Reaper>();
Iterator<AccessControlContext> failedAcc = accFails.iterator();
while (failedAcc.hasNext()){
AccessControlContext fail = failedAcc.next();
Set<Thread> threads = executionCache.get(fail);
Iterator<Thread> i = threads.iterator();
while (i.hasNext()) {
Thread t = i.next();
Reaper r = association.get(t);
r.put(t);
reapers.add(r);
}
}
return reapers;
} finally {
wl.unlock();
}
}
public void begin(Reaper r) {
Thread currentThread = Thread.currentThread();
association.put(currentThread, r);
}
public void checkPermission(Permission p) throws
AccessControlException {
Thread currentThread = Thread.currentThread();
AccessControlContext executionContext = AccessController.getContext();
rl.lock();
try {
// execution cache.
Set<Thread> exCacheThreadSet = executionCache.get(executionContext);
if ( exCacheThreadSet == null ){
exCacheThreadSet = Collections.synchronizedSet(new
HashSet<Thread>());
Set<Thread> existed =
executionCache.putIfAbsent(executionContext, exCacheThreadSet);
if (existed != null){
exCacheThreadSet = existed;
}
}
exCacheThreadSet.add(currentThread);// end execution cache.
// thread association
Set<AccessControlContext> thAssocSet =
threadAssociation.get(currentThread);
if ( thAssocSet == null ){
thAssocSet = Collections.synchronizedSet(new
HashSet<AccessControlContext>());
Set<AccessControlContext> existed =
threadAssociation.putIfAbsent(currentThread, thAssocSet);
if (existed != null){
thAssocSet = existed;
}
}
thAssocSet.add(executionContext); // end thread association.
// checkedCache - the permission check.
Set<AccessControlContext> checked = checkedCache.get(p);
if (checked == null ){
checked = Collections.synchronizedSet(new
HashSet<AccessControlContext>());
Set<AccessControlContext> existed = checkedCache.putIfAbsent(p,
checked);
if (existed != null){
checked = existed;
}
}
if ( checked.contains(executionContext)) return; // it's passed
before.
executionContext.checkPermission(p); // Throws
AccessControlException
// If we get here cache the AccessControlContext.
checked.add(executionContext); // end checkedCache.
} finally {
rl.unlock();
}
}
public void end() {
// Teardown.
Thread t = Thread.currentThread();
rl.lock();
try {
association.remove(t);
Set<AccessControlContext> accSet = threadAssociation.remove(t);
Iterator<AccessControlContext> it = accSet.iterator();
while (it.hasNext()){
AccessControlContext acc = it.next();
executionCache.get(acc).remove(t);
}
}finally {
rl.unlock();
}
}
}
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.river.imp.security.policy.se;
import java.security.AccessControlContext;
import java.security.AccessControlContext;
import java.security.AccessControlContext;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.Permission;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.river.api.security.ExecutionContextManager;
import org.apache.river.api.security.Reaper;
import org.apache.river.imp.util.ConcurrentWeakIdentityMap;
/**
* Only a Single instance of ECM is required per policy, it is threadsafe.
* Threads will wait until revoke is complete.
*
* @author Peter Firmstone
*/
public class ECM implements ExecutionContextManager{
private final ConcurrentMap<Class,Set<AccessControlContext>>
checkedCache;
private final ConcurrentMap<AccessControlContext, Set<Thread>>
executionCache;
private final ConcurrentMap<Thread, Set<AccessControlContext>>
threadAssociation;
private final ConcurrentMap<Thread, Reaper> association;
private final ReadWriteLock blockLock;
private final Lock rl; // This lock is held briefly by callers of
begin and end.
private final Lock wl; // This lock is held by revocation.
ECM(){
checkedCache = new ConcurrentWeakIdentityMap<Class,
Set<AccessControlContext>>();
executionCache = new ConcurrentHashMap<AccessControlContext,
Set<Thread>>();
threadAssociation = new ConcurrentHashMap<Thread,
Set<AccessControlContext>>();
association = new ConcurrentHashMap<Thread, Reaper>();
blockLock = new ReentrantReadWriteLock();
rl = blockLock.readLock();
wl = blockLock.writeLock();
}
boolean revoke(){
wl.lock();
try {
/* This is where we determine what needs to be revoked, we first
* get all the AccessControlContexts for the Permission class,
* these are removed from the checkedCache, then we narrow
* down the AccessControlContext's to only those in the
* execution cache, each AccessControlContext in the execution cache
* has checkPermission(Permission) called for each revoked
* permission. Any that throw AccessControlException will be
* caught and have their Reaper run, for the Threads referenced
* from that AccessControlContext.
*
* The RevokeableDynamicPolicy will have updated the current
* Permission's after revocation, so the ProtectionDomain's in
* the AccessControlContext will now throw an AccessControlException
* if the revocation applied to them.
*
* The wl lock will be released, any threads that were interrupted
* will exit through the finally block and remove themselves
* from the execution cache. Those that aren't may throw
* an exception, end() and bubble up the stack, due to closing
sockets
* etc.
*
* The execution cache is comprised of the following fields:
* executionCache
* threadAssociation
*
*
*/
return false;
} finally {
wl.unlock();
}
}
public void begin(Reaper r) {
Thread currentThread = Thread.currentThread();
association.put(currentThread, r);
}
public void checkPermission(Permission p) throws
AccessControlException {
Thread currentThread = Thread.currentThread();
AccessControlContext executionContext = AccessController.getContext();
rl.lock();
try {
// execution cache.
Set<Thread> exCacheThreadSet = executionCache.get(executionContext);
if ( exCacheThreadSet == null ){
exCacheThreadSet = Collections.synchronizedSet(new
HashSet<Thread>());
Set<Thread> existed =
executionCache.putIfAbsent(executionContext, exCacheThreadSet);
if (existed != null){
exCacheThreadSet = existed;
}
}
exCacheThreadSet.add(currentThread);// end execution cache.
// thread association
Set<AccessControlContext> thAssocSet =
threadAssociation.get(currentThread);
if ( thAssocSet == null ){
thAssocSet = Collections.synchronizedSet(new
HashSet<AccessControlContext>());
Set<AccessControlContext> existed =
threadAssociation.putIfAbsent(currentThread, thAssocSet);
if (existed != null){
thAssocSet = existed;
}
}
thAssocSet.add(executionContext); // end thread association.
// checkedCache - the permission check.
Set<AccessControlContext> checked = checkedCache.get(p);
if (checked == null ){
checked = Collections.synchronizedSet(new
HashSet<AccessControlContext>());
Set<AccessControlContext> existed =
checkedCache.putIfAbsent(p.getClass(), checked);
if (existed != null){
checked = existed;
}
}
if ( checked.contains(executionContext)) return; // it's passed
before.
executionContext.checkPermission(p); // Throws
AccessControlException
// If we get here cache the AccessControlContext.
checked.add(executionContext); // end checkedCache.
} finally {
rl.unlock();
}
}
// always called from a finally block.
public void end() {
// Teardown.
Thread t = Thread.currentThread();
rl.lock();
try {
association.remove(t);
Set<AccessControlContext> accSet = threadAssociation.remove(t);
Iterator<AccessControlContext> it = accSet.iterator();
while (it.hasNext()){
AccessControlContext acc = it.next();
executionCache.get(acc).remove(t);
}
}finally {
rl.unlock();
}
}
}
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
How about this for an ExecutionContextManager?
public interface ExecutionContextManager {
void begin(Reaper r);
void checkPermission(Permission p) throws AccessControlException;
void end();
}
public interface Reaper extends Runnable {
void put(Thread t);
}
To be used like this:
ecm.begin(reaper);
try{
ecm.checkPermission(p);
ecm.checkPermission(m);
// do something, then return
return;
}finally {
ecm.end();
}
Two separate things are being managed here, the begin(reaper) method
associates the current Thread with it's AccessControlContext and Reaper,
and places it into the current execution cache, while end() removes it.
The checkPermission(p) method, checks the cache to see if the current
AccessControlContext has been tested with the given permission, if so it
returns, if not it checks the Permission, if it succeeds, it places it
into the checked cache. The Permission is then associated with the
current thread in the execution cache.
The end() method, removes the current Thread, AccessControlContext and
Reaper from the current execution cache.
When a revocation event occurs, a lock is held to prevent any
begin(reaper) method's from proceeding. The end() method in the finally
block stops any currently executing code blocks from returning during
the revocation event. Next the Permission's Class files are checked
against the Permission's currently in the execution cache. Any with the
matching Permission class files will require the
AccessContorlContext.checkPermission(Permission perm) call be made
again, any that fail will be added to a new collection pending reaping
and removed from the checked cache. The RevokeableDynamicPolicy is
capable of changing the AccessControlContext result, since it is called
by each ProtectionDomain in the AccessControlContext.
Each Reaper will be given a copy of it's Thread of execution, it doesn't
have to use it, but it's there if the Reaper wants to just interrupt the
thread to stop the block's execution. The Reapers will be placed on a
queue and run.
The locks are released once the reapers have completed.
When exit() is called by the finally block, the thread and
AccessControlContext's are removed from the current execution cache,
regardless of any revocation event.
It is also possible for the ExectionContextManager to have static class
methods like AccessController.
What are your thoughts?
Peter.
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Gregg Wonderly <gr...@wonderly.org>.
Peter Firmstone wrote:
> Fred Oliver wrote:
>> To at least partially answer my own question, I think that the answer
>> is that the socket can't be closed (at least in all cases).
>>
>> If the delegate for a resource has multiple users (codebases,
>> principals, etc.) then closing the resource because permission for one
>> of the users has been revoked denies access to the resource by the
>> remaining valid users. (This allows a denial of service attack.) And
>> then, if you can't close the resource (socket), you can't kick loose
>> the no longer trusted thread blocked reading from it. You may be able
>> to determine the special case of no user retaining access (everyone's
>> access was revoked) and can then close the resource.
>>
>> In the standard security model, there are no checks for
>> reading/writing sockets. Allowing revocation means that checks must be
>> added for each individual read or write call on the socket streams. Is
>> that level of performance satisfactory?
>>
>
> I've just spotted a possible performance improvement.
>
> We can eliminate the end() call in the finally block, put all the
> checkPermission calls there instead. This substantially reduces the
> caching operations. Perhaps we can manage the Socket some other way, we
> just block unauthorised access using the delegate?
>
> try {
> // Do some processing
> return something;
> } finally {
> ECM.checkPermission(Collection<Permission> permissions);
> }
>
> The current expense for making a Permission call via ECM (remembering
> the first is always going to be expensive), currently requires the three
> ECM calls in succession:
>
> begin();
> checkPermission(perm);
> end();
>
> begin():
>
> 1. Associate the thread with the reaper.
>
>
> checkPermission(perm):
>
> 1. Obtain the read lock;
> 2. Add the current thread to the execution cache.
> 3. Associate the current AccessControlContext with the current thread
> 4. Check if the AccessControlContext has been checked for this
> Permission previously.
> 5. If it has been checked before, return, else do
> AccessController.checkPermission(perm), cache the result if it
> succeeds.
>
> Each end():
>
> 1. Obtain the read lock;
> 2. Remove the thread and reaper from the cache.
> 3. Remove the thread association with the AccessControlContext.
> 4. Remove the thread from the execution cache.
>
> This could be simplified to (no reaper or thread caching):
>
> checkPermission(perms)
>
> 1. Obtain the read lock;
> 2. For each Permission, check if the current AccessControlContext has
> been checked for this Permission previously, if so return.
> (HashMap lookup - fast).
> 3. If the AccessControlContext hasn't been checked previously, do
> AccessController.checkPermission(perm), cache the result if it
> succeeds, then return.
>
> So for performance reasons, it looks like we need to be considering some
> other way to manage the Socket, the ECM would serve us better if we kept
> it simple?
>
> I think your earlier suggestion of an event notification might be more
> useful, if provided as a parameter in the checkPermission call, in the
> event of failure, an event would be generated, the delegate could then
> decide what action to take. If it only had one user, then it knows to
> close the Socket, if it has multiple users, it might just keep score.
>
> This stops the transmission of data from unauthorised code, but it
> doesn't close the socket.
If there is an interface such as:
public interface PermissionChangeDelegate {
public void permissionGranted( Permissions p );
public void permissionRevoked( Permissions p );
}
and the code invokes a method with a signature like:
public void checkPermission( Permissions p, PermissionChangeDelegate del );
and the provider of this method is associated with grants and revokes such that
it can know who checking for such permission uses, then there can be a callback
to all the delegates at revocation, and the socket can be closed as appropriate
based on the knowledge of the PermissionChangeDelegate.
But, in the end, I really do think that this is too low of a level for
permission checks. Open ended resources should not be visible in the API
without some sort of wrapper class. I create subclasses of OutputStream and
InputStream etc. to hold references of sockets and perform checks there by not
using the SecurityManager, but by using the JDBC backed database which is
completely cached in memory in the auth.dev.java.net project. With that
facility, I don't have to worry about what granularity of "Permission" has been
designed into the JVM resources. Instead, I can put an appropriately grained
control layer on top of my API, and that layer can do what is needed to manage
things, because every API call is checked, and if a permission is revoked, that
fact is instantly reflected into all security delegates, and the APIs will be
controlled based on the granularity I've decided on.
Gregg Wonderly
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
An input stream delegate, might use buffering, first obtaining the data,
writing to a buffered byte array, then do a permission check(), if the
check fails close the underlying input stream and throw an IOException.
If the check passes, the bytes would be copied from the buffer to the
passed in byte array and the number of bytes returned.
The delegates would have to perform at least one optimised
ecm.checkPermission call per method. Writes and reads with array's
larger than the buffered array size would do more than one permission
check, a large buffer array would be most optimal.
By using a buffer, the permission checks are called after any potential
blocking. If revocation has not been performed at the time of the
permission check, it is unlikely that a following revocation could
complete prior to copying the buffer.
Revocation itself as a process, is not instantaneous, however the caller
on the revoke method needs to know that trust has been revoked
completely, once this policy method has returned.
I've also since realised that the Output stream delegate below, would
not necessarily stop a write from completing, if revocation occurs after
the permission check, some bytes would be written to the output stream,
the reaper would still close the output stream, so it appears to hold
little benefit over the simpler implementation.
public void write( byte[] b) {
ecm.begin(reaper)
try{
ecm.checkPermission(writePermission);
out.write( byte[] b);
} finally {
end();
}
}
In any case it appears difficult to prevent a remaining write from
occurring once it has passed the security check.
It appears that ECM should be simpler and not track the current thread.
To protect method returns we can use:
Object method()
try {
// do something
return obj;
} finally {
ecm.checkPermission(perm);
}
}
To protect state:
void replace(Object o) {
ecm.checkPermission(perm);
this.o = o;
}
To protect functions
void doSomething()
ecm.checkPermission(perm);
// do something
}
To protect Object's themselves, we need security delegates.
It seems each case needs to be checked on merit.
Perhaps the best way to protect from data loss is to be proactive,
rather than reactive, by limiting the duration a privilege is granted,
rather than to revoke it when it has become a matter of urgency. So how
would we determine when a Permission is no longer needed?
Currently the Permission's code requires is found by trial and error, by
running the code, to see what security exceptions are thrown, instead I
think services should have an Entry with the Permission's they require,
a client might decide to grant these Permission's or to limit them to a
subset, or choose another service.
Since a Smart proxy may require more than one jar file, the permission's
required should specify the permission's each require. I figure the
Entry's can contain PermissionGrant builders, allowing the grantor
(client) to make the final decision.
Once a client is finished with a service, those permission's granted
should be revoked immediately.
Thoughts?
Cheers,
Peter.
Peter Firmstone wrote:
> Clarification (I overlooked something): The
> checkPermission(Collection<Permission> perms) in the finally block
> would work only for intercepting a method return, but it doesn't work
> for InputStream read() / OutputStream write(), since we wanted to stop
> method execution, if Permission is no longer granted.
>
> For example if a socket delegate returns an OutputStream delegate,
> that wraps an underlying OutputStream, then during the write(), if a
> revocation occurs, we probably want to close the OutputStream, if it
> applies.
>
> The OutputStream write() would still need a reaper, to close the
> OutputStream causing an IOException to be thrown, although as yet I
> haven't determined how to add debug information for an intervening
> revocation.
>
> public void write( byte[] b) {
> ecm.begin(reaper)
> try{
> ecm.checkPermission(writePermission);
> out.write( byte[] b);
> } finally {
> end();
> }
> }
>
> Is it as critical to stop a read() operation?
>
> Since the array passed into the read() operation is written to, we can
> close this as well, causing an IOException, however the user will
> still get some bytes written into the byte array, which it can access
> if it catches the IOException.
>
> public int read(byte[] b) {
> ecm.begin(reaper)
> try{
> ecm.checkPermission(readPermission);
> return in.read( byte[] b);
> } finally {
> end();
> }
> }
>
> But we could provide the optimised single invocation
> checkPermission(Collection<Permission> perms) method as well, for
> calls that don't need to be intercepted.
>
> Perhaps we could be less pedantic about read operations, provided all
> write operations are intercepted?
>
> public int read(byte[] b) {
> try {
> ecm.checkPermission(readPermission);
> } catch (AccessControlException e) {
> this.close();
> throw new IOException(e.toString());
> }
> return in.read( byte[] b);
> }
>
> This checkPermission would be very fast, with only a small amount of
> cpu overhead, because it caches the result for the AccessControlContext.
>
> We could do this for write() as well, if the code was trusted at the
> time of the write() call, then we might assume that the information
> contained within, wasn't borne from an operation of malicious intent,
> we trusted it, so the call can be allowed to complete. This has a
> much smaller performance penalty, any following calls will cause an
> AccessControlExeption to be thrown, if Permission is revoked.
>
> Then write might simply be:
>
> public void write(byte[] b) {
> try {
> ecm.checkPermission(writePermission);
> } catch (AccessControlException e) {
> this.close();
> throw new IOException(e.toString());
> }
> out.write(b);
> }
>
> We might consider what the uses are for Permission revocation? I'm
> starting to think interception might hamper performance too greatly.
>
> The major uses I see for Revocation:
>
> * Reusing ClassLoader's, for proxy's with common code source, by
> removing trust gained by the previous proxy.
> * Limit the time period for which trust is granted to a third
> party. A Trust lease? Trust is only granted while contact is
> maintained.
> * If a proxy has lost contact with it's Server, which was trusted
> and we want to resume (without loosing state) we can revoke
> permission, retry connecting with the Server, verify trust, then
> re grant trust (I'm thinking about the neuromancer remote
> reference problem).
>
> Obviously the feature got your interest, I'm wondering what other uses
> there might have been for permission revocation? This might help me
> better understand the use case scenarios.
>
>
> Peter Firmstone wrote:
>> Fred Oliver wrote:
>>> To at least partially answer my own question, I think that the answer
>>> is that the socket can't be closed (at least in all cases).
>>>
>>> If the delegate for a resource has multiple users (codebases,
>>> principals, etc.) then closing the resource because permission for one
>>> of the users has been revoked denies access to the resource by the
>>> remaining valid users. (This allows a denial of service attack.) And
>>> then, if you can't close the resource (socket), you can't kick loose
>>> the no longer trusted thread blocked reading from it. You may be able
>>> to determine the special case of no user retaining access (everyone's
>>> access was revoked) and can then close the resource.
>>>
>>> In the standard security model, there are no checks for
>>> reading/writing sockets. Allowing revocation means that checks must be
>>> added for each individual read or write call on the socket streams. Is
>>> that level of performance satisfactory?
>>>
>>
>> I've just spotted a possible performance improvement.
>>
>> We can eliminate the end() call in the finally block, put all the
>> checkPermission calls there instead. This substantially reduces the
>> caching operations. Perhaps we can manage the Socket some other way,
>> we just block unauthorised access using the delegate?
>>
>> try {
>> // Do some processing
>> return something;
>> } finally {
>> ECM.checkPermission(Collection<Permission> permissions);
>> }
>>
>> The current expense for making a Permission call via ECM (remembering
>> the first is always going to be expensive), currently requires the
>> three ECM calls in succession:
>>
>> begin();
>> checkPermission(perm);
>> end();
>>
>> begin():
>>
>> 1. Associate the thread with the reaper.
>>
>>
>> checkPermission(perm):
>>
>> 1. Obtain the read lock;
>> 2. Add the current thread to the execution cache.
>> 3. Associate the current AccessControlContext with the current thread
>> 4. Check if the AccessControlContext has been checked for this
>> Permission previously.
>> 5. If it has been checked before, return, else do
>> AccessController.checkPermission(perm), cache the result if it
>> succeeds.
>>
>> Each end():
>>
>> 1. Obtain the read lock;
>> 2. Remove the thread and reaper from the cache.
>> 3. Remove the thread association with the AccessControlContext.
>> 4. Remove the thread from the execution cache.
>>
>> This could be simplified to (no reaper or thread caching):
>>
>> checkPermission(perms)
>>
>> 1. Obtain the read lock;
>> 2. For each Permission, check if the current AccessControlContext has
>> been checked for this Permission previously, if so return.
>> (HashMap lookup - fast).
>> 3. If the AccessControlContext hasn't been checked previously, do
>> AccessController.checkPermission(perm), cache the result if it
>> succeeds, then return.
>>
>> So for performance reasons, it looks like we need to be considering
>> some other way to manage the Socket, the ECM would serve us better if
>> we kept it simple?
>>
>> I think your earlier suggestion of an event notification might be
>> more useful, if provided as a parameter in the checkPermission call,
>> in the event of failure, an event would be generated, the delegate
>> could then decide what action to take. If it only had one user, then
>> it knows to close the Socket, if it has multiple users, it might just
>> keep score.
>>
>> This stops the transmission of data from unauthorised code, but it
>> doesn't close the socket.
>>
>> Cheers,
>>
>> Peter.
>>>
>>>> If there is untrusted code on a thread's stack, and if the thread
>>>> called a delegate, and if the delegate is in the between ECM.begin()
>>>> and ECM.end(), then the delegate's reaper will be called, and it can
>>>> close the socket.
>>>>
>>>> If the revocation happened elsewhere (e.g. the untrusted code is not
>>>> on any stack, or is occupied with some other task), how does the
>>>> socket get closed?
>>>>
>>>> Fred
>>>>
>>
>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
A note on ProtectionDomain's,
There can be only one! ProtectionDomain's are only ever compared with
==, they don't override equals() or hashCode(). ProtectionDomain's are
immutable in respect to the ClassLoader, CodeSource and Principals which
they encapsulate. They may be made immutable in respect of Permissions
at construction time, however when dynamic, they consult the policy.
JAAS, uses Subject's to represents users, roles, etc, the
SubjectDomainCombiner replaces the ProtectionDomains on the stack, with
new ProtectionDomains, merging the Principals of the executing Subject,
with those of the existing ProtectionDomain.
The missing equals() and hashCode() methods in ProtectionDomain, means
that caching of results for AccessControlContext's, containing
ProtectionDomain's created by SubjectDomainCombiner's even with
identical Principal[]'s, will not be equal and thus, the result cannot
be optimised much, even though the originating ProtectionDomain's and
Subject's may be identical.
jini.net.security.Security
It's used for most of the existing Jini security decisions, similar to
AccessController, so it's a logical place to put an optimised
checkPermissions(Collection<Permission>) call, that obtains and calls
the ECM from the RevokeableDynamicPolicy, if in force, it also provides
the opportunity to remove the ExecutionContextManager interface from the
public API if necessary.
By batching the Permission's together we only call
AccessController.getContext() once, this is useful for PermissionGrant
processing where we have to batch check GrantPermission's
the new checkPermissions(Collection<Permission>) call will execute
faster than AccessController.checkPermission(Permission) and provide a
performance boost to any existing security check, not just those
proposed so far.
Then we can get down to business, testing, will update SVN shortly so
you can all review the code.
N.B. I decided NOT to implement an Event for Security Delegates to be
advised of permission revocation, since a delegate
cannot know the execution context without checking it, it must alway
check EVERY method invocation, the ECM has been designed to skip as much
as possible and return quickly, provided the execution context hasn't
changed or permission revoked, since last check. I've added the method
checkPermission(Collection<Permission>) to net.jini.security.Security
along with some preliminary documentation.
Cheers,
Peter.
Here's an interesting security Bug:
*Bug ID:* 4857197 *
Votes* 0 *
Synopsis* switch back from Security.doPrivileged to
AccessController.doPrivileged
*Category* jini:other *
Reported Against* 2.0beta
*Release Fixed* 2.0
*State* 10-Fix Delivered, request for enhancement
*Priority:* 3-Medium *
Related Bugs* *Submit Date* 01-MAY-2003 *
Description*
Security.doPrivileged is very expensive. Much of our code was converted to use it from a purity of
security model perspective, but the performance hit from doing that appears to be unacceptable.
For at least performance-critical components, if preserving the Subject isn't semantically significant
(most particularly, there is no call out to user code), we should switch back to using
AccessController.doPrivileged. As such, security policy files will have to live with granting
various permissions to codesources rather than codesource+principals.
*Work Around*
N/A
*Evaluation*
Yep.
Peter Firmstone wrote:
> Performance costs of ECM access checks?
>
> How much will delegates impact performance in comparison to existing
> SocketPermission guards?
>
> Some interesting links:
>
> www.rewerse.net/pulications/download/REWERSE-RP-2005-141.pdf
>
> www.ida.liu.se/~almhe
>
> There's some interesting performance tests available for the above
> paper at:
>
> http://www.ida.liu.se/~almhe/publications/sm-testdata/
>
> I suspect we'll be able to achieve respectable performance figures,
> here are some tips in the paper we can learn from:
>
> 1. Existing SocketPermission's try to perform a DNS-lookup. Bug ID's
> related to SocketPermission problems 4155463, 4320895, 4414825,
> 4975882, 5004073
> 2. AccessController.getStackAccessControlContext was identified as an
> expensive native method, can't avoid that one!
> 3. Performance worsens with increasing numbers of CodeSources.
>
> Some initial observations:
>
> In comparison to the existing path for security checks, we can cache
> the result of the AccessControlContext.checkPermission(Permission)
> calls, until a revocation occurs, removing multiple calls to
> ProtectionDomain's contained in the AccessControlContext.
>
> Each ProtectionDomain.implies(Permission) check is typically followed
> by Policy.getPolicyNoCheck, PolicyFile.implies(ProtectionDomain,
> Permission), SynchronizedMap.get(WeakHashMap.get(ProtectionDomain)),
> Permissions.implies(Permission), Permissions.getPermissionCollection,
> HashMap.get(Class<Permission>), PermissionCollection.implies(Permission).
>
> Synchronization creates significant points of contention, although
> that has recently been solved with DynamicConcurrentPolicyProvider,
> however we still need to performance test it.
>
> AccessControlContext has reasonable equals() and hashCode()
> implementations, it will perform well in concurrent cache
> collections. Typically Permission equals and hashCode implementations
> are also reasonable. The first call from an AccessControlContext will
> be the most expensive, however in between revocations, repeated calls
> will be cheap, apart from the native call getStackAccessControlContext.
>
> I don't want to be calling DNS!
>
> Cheers,
>
> Peter.
>
>
> Peter Firmstone wrote:
>> Clarification (I overlooked something): The
>> checkPermission(Collection<Permission> perms) in the finally block
>> would work only for intercepting a method return, but it doesn't work
>> for InputStream read() / OutputStream write(), since we wanted to
>> stop method execution, if Permission is no longer granted.
>>
>> For example if a socket delegate returns an OutputStream delegate,
>> that wraps an underlying OutputStream, then during the write(), if a
>> revocation occurs, we probably want to close the OutputStream, if it
>> applies.
>>
>> The OutputStream write() would still need a reaper, to close the
>> OutputStream causing an IOException to be thrown, although as yet I
>> haven't determined how to add debug information for an intervening
>> revocation.
>>
>> public void write( byte[] b) {
>> ecm.begin(reaper)
>> try{
>> ecm.checkPermission(writePermission);
>> out.write( byte[] b);
>> } finally {
>> end();
>> }
>> }
>>
>> Is it as critical to stop a read() operation?
>>
>> Since the array passed into the read() operation is written to, we
>> can close this as well, causing an IOException, however the user will
>> still get some bytes written into the byte array, which it can access
>> if it catches the IOException.
>>
>> public int read(byte[] b) {
>> ecm.begin(reaper)
>> try{
>> ecm.checkPermission(readPermission);
>> return in.read( byte[] b);
>> } finally {
>> end();
>> }
>> }
>>
>> But we could provide the optimised single invocation
>> checkPermission(Collection<Permission> perms) method as well, for
>> calls that don't need to be intercepted.
>>
>> Perhaps we could be less pedantic about read operations, provided all
>> write operations are intercepted?
>>
>> public int read(byte[] b) {
>> try {
>> ecm.checkPermission(readPermission);
>> } catch (AccessControlException e) {
>> this.close();
>> throw new IOException(e.toString());
>> }
>> return in.read( byte[] b);
>> }
>>
>> This checkPermission would be very fast, with only a small amount of
>> cpu overhead, because it caches the result for the AccessControlContext.
>>
>> We could do this for write() as well, if the code was trusted at the
>> time of the write() call, then we might assume that the information
>> contained within, wasn't borne from an operation of malicious intent,
>> we trusted it, so the call can be allowed to complete. This has a
>> much smaller performance penalty, any following calls will cause an
>> AccessControlExeption to be thrown, if Permission is revoked.
>>
>> Then write might simply be:
>>
>> public void write(byte[] b) {
>> try {
>> ecm.checkPermission(writePermission);
>> } catch (AccessControlException e) {
>> this.close();
>> throw new IOException(e.toString());
>> }
>> out.write(b);
>> }
>>
>> We might consider what the uses are for Permission revocation? I'm
>> starting to think interception might hamper performance too greatly.
>>
>> The major uses I see for Revocation:
>>
>> * Reusing ClassLoader's, for proxy's with common code source, by
>> removing trust gained by the previous proxy.
>> * Limit the time period for which trust is granted to a third
>> party. A Trust lease? Trust is only granted while contact is
>> maintained.
>> * If a proxy has lost contact with it's Server, which was trusted
>> and we want to resume (without loosing state) we can revoke
>> permission, retry connecting with the Server, verify trust, then
>> re grant trust (I'm thinking about the neuromancer remote
>> reference problem).
>>
>> Obviously the feature got your interest, I'm wondering what other
>> uses there might have been for permission revocation? This might
>> help me better understand the use case scenarios.
>>
>>
>> Peter Firmstone wrote:
>>> Fred Oliver wrote:
>>>> To at least partially answer my own question, I think that the answer
>>>> is that the socket can't be closed (at least in all cases).
>>>>
>>>> If the delegate for a resource has multiple users (codebases,
>>>> principals, etc.) then closing the resource because permission for one
>>>> of the users has been revoked denies access to the resource by the
>>>> remaining valid users. (This allows a denial of service attack.) And
>>>> then, if you can't close the resource (socket), you can't kick loose
>>>> the no longer trusted thread blocked reading from it. You may be able
>>>> to determine the special case of no user retaining access (everyone's
>>>> access was revoked) and can then close the resource.
>>>>
>>>> In the standard security model, there are no checks for
>>>> reading/writing sockets. Allowing revocation means that checks must be
>>>> added for each individual read or write call on the socket streams. Is
>>>> that level of performance satisfactory?
>>>>
>>>
>>> I've just spotted a possible performance improvement.
>>>
>>> We can eliminate the end() call in the finally block, put all the
>>> checkPermission calls there instead. This substantially reduces the
>>> caching operations. Perhaps we can manage the Socket some other
>>> way, we just block unauthorised access using the delegate?
>>>
>>> try {
>>> // Do some processing
>>> return something;
>>> } finally {
>>> ECM.checkPermission(Collection<Permission> permissions);
>>> }
>>>
>>> The current expense for making a Permission call via ECM
>>> (remembering the first is always going to be expensive), currently
>>> requires the three ECM calls in succession:
>>>
>>> begin();
>>> checkPermission(perm);
>>> end();
>>>
>>> begin():
>>>
>>> 1. Associate the thread with the reaper.
>>>
>>>
>>> checkPermission(perm):
>>>
>>> 1. Obtain the read lock;
>>> 2. Add the current thread to the execution cache.
>>> 3. Associate the current AccessControlContext with the current thread
>>> 4. Check if the AccessControlContext has been checked for this
>>> Permission previously.
>>> 5. If it has been checked before, return, else do
>>> AccessController.checkPermission(perm), cache the result if it
>>> succeeds.
>>>
>>> Each end():
>>>
>>> 1. Obtain the read lock;
>>> 2. Remove the thread and reaper from the cache.
>>> 3. Remove the thread association with the AccessControlContext.
>>> 4. Remove the thread from the execution cache.
>>>
>>> This could be simplified to (no reaper or thread caching):
>>>
>>> checkPermission(perms)
>>>
>>> 1. Obtain the read lock;
>>> 2. For each Permission, check if the current AccessControlContext has
>>> been checked for this Permission previously, if so return.
>>> (HashMap lookup - fast).
>>> 3. If the AccessControlContext hasn't been checked previously, do
>>> AccessController.checkPermission(perm), cache the result if it
>>> succeeds, then return.
>>>
>>> So for performance reasons, it looks like we need to be considering
>>> some other way to manage the Socket, the ECM would serve us better
>>> if we kept it simple?
>>>
>>> I think your earlier suggestion of an event notification might be
>>> more useful, if provided as a parameter in the checkPermission call,
>>> in the event of failure, an event would be generated, the delegate
>>> could then decide what action to take. If it only had one user,
>>> then it knows to close the Socket, if it has multiple users, it
>>> might just keep score.
>>>
>>> This stops the transmission of data from unauthorised code, but it
>>> doesn't close the socket.
>>>
>>> Cheers,
>>>
>>> Peter.
>>>>
>>>>> If there is untrusted code on a thread's stack, and if the thread
>>>>> called a delegate, and if the delegate is in the between ECM.begin()
>>>>> and ECM.end(), then the delegate's reaper will be called, and it can
>>>>> close the socket.
>>>>>
>>>>> If the revocation happened elsewhere (e.g. the untrusted code is not
>>>>> on any stack, or is occupied with some other task), how does the
>>>>> socket get closed?
>>>>>
>>>>> Fred
>>>>>
>>>
>>>
>>>
>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Patricia Shanahan wrote:
> On 8/22/2010 8:08 AM, Peter Firmstone wrote:
> ...
>> These ProxyPermission's will be usable whether people want to revoke
>> them or not, and should be much faster than SocketPermission's, anyone
>> with any ideas, please assist.
> ...
>
> I don't know enough about what you are trying to do to assist
> directly. However, there is one tool that should be in your toolbox,
> even if you decide it does not help.
>
> Are you aware of Aspect/J, and the underlying idea of organized
> bytecode modification to manage cross-cutting concerns without
> scattered source code change?
>
> Patricia
>
Yes, it is interesting, I started looking into it a couple of years ago,
but got busy. Bytecode weaving with AspectJ, a problem that we might
face, is how to understand aspects weaved from different compiled code
fragments. In a way similar to the problems with Generics from
separately compiled code fragments, that come together in a distributed
environment. Generics in Service Interfaces only work where the
generics are specific, wild cards and generic types don't work, because
that information suffers from compile time erasure, causing runtime type
cast errors. I think we'd face similar incompatibilities, but it
doesn't mean it's not a good idea or isn't possible ;) I believe there
are researchers working on distributed aspects...
Cheers,
Peter.
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Patricia Shanahan <pa...@acm.org>.
On 8/22/2010 8:08 AM, Peter Firmstone wrote:
...
> These ProxyPermission's will be usable whether people want to revoke
> them or not, and should be much faster than SocketPermission's, anyone
> with any ideas, please assist.
...
I don't know enough about what you are trying to do to assist directly.
However, there is one tool that should be in your toolbox, even if you
decide it does not help.
Are you aware of Aspect/J, and the underlying idea of organized bytecode
modification to manage cross-cutting concerns without scattered source
code change?
Patricia
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Gregg Wonderly wrote:
> Peter Firmstone wrote:
>> I don't want to be calling DNS!
>
> This is the most significant reason why I hate resource based policy
> implementation. I've spent countless hours trying to figure out why
> something was so horribly slow, only to find that the primary DNS
> server as not functioning, and the default 10 sec cache of failure was
> too short, and so every DNS action timed out to the first host, and
> then failed over and worked.
>
> By setting the failure cache to 1min, my application was suddenly much
> more responsive.
>
> Gregg Wonderly
>
I've been running some tests on my ExecutionContextManager implementation.
I think I can eliminate the need for this additional interface and
implementation, by implementing a non blocking PermissionCollection for
a new Permission class called ProxyPermission.
Current Performance tests indicate that my ECM performs around 1.2 to
2.5 times the speed of AccessController.checkPermission(Permission).
When I run 5 concurrent threads looping constantly performing
checkPermission on 4 different Permission's for 100000 loops, the
performance per thread degrades from 11 seconds to 30 seconds for the
total test duration, due to internal synchronization in
RuntimePermission's PermissionCollection. (BasicPermissionCollection),
this is performed with the mostly non blocking
DynamicConcurrentPolicyProvider.
In comparison a comparative test on the ECM is about 7.5 seconds with
the same number of AccessController.getContext calls, the ECM reduces
these calls down to 4.2 seconds by testing 4 different Permission's per
getContext call (x 100000 loops). However this last test is atypical,
since checkPermission calls will normally only be made once, rather than
several in a row.
Because the ECM also uses a Synchronized Set, containing
AccessControlContext's there is potential for blocking under different
conditions in the ECM. Instead of having one ECM per policy, I could
have multiple, I can however create a non blocking
ProxyPermissionCollection for ProxyPermission's that behave similarly to
BasicPermission's, but are instead intended to support revocation with
Security Delegates and perform almost as well as the ECM.
This makes for a much simpler outcome and keeps the policy
implementation tighter. No ExecutionContextManager.
ProxyPermission's will be created for network addresses (without DNS
resolution), although considering that we want to be able to get through
firewalls and the like, I'm going to have to be careful, about exactly
what permission names are used. Since a service may be found, not
through DNS, but via a Registrar and a listening post, as per Sim's
Meekong Jeri Endpoint's.
These ProxyPermission's will be usable whether people want to revoke
them or not, and should be much faster than SocketPermission's, anyone
with any ideas, please assist.
Cheers,
Peter.
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Gregg Wonderly <gr...@wonderly.org>.
Peter Firmstone wrote:
> I don't want to be calling DNS!
This is the most significant reason why I hate resource based policy
implementation. I've spent countless hours trying to figure out why something
was so horribly slow, only to find that the primary DNS server as not
functioning, and the default 10 sec cache of failure was too short, and so every
DNS action timed out to the first host, and then failed over and worked.
By setting the failure cache to 1min, my application was suddenly much more
responsive.
Gregg Wonderly
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Performance costs of ECM access checks?
How much will delegates impact performance in comparison to existing
SocketPermission guards?
Some interesting links:
www.rewerse.net/pulications/download/REWERSE-RP-2005-141.pdf
www.ida.liu.se/~almhe
There's some interesting performance tests available for the above paper at:
http://www.ida.liu.se/~almhe/publications/sm-testdata/
I suspect we'll be able to achieve respectable performance figures, here
are some tips in the paper we can learn from:
1. Existing SocketPermission's try to perform a DNS-lookup. Bug ID's
related to SocketPermission problems 4155463, 4320895, 4414825,
4975882, 5004073
2. AccessController.getStackAccessControlContext was identified as an
expensive native method, can't avoid that one!
3. Performance worsens with increasing numbers of CodeSources.
Some initial observations:
In comparison to the existing path for security checks, we can cache the
result of the AccessControlContext.checkPermission(Permission) calls,
until a revocation occurs, removing multiple calls to ProtectionDomain's
contained in the AccessControlContext.
Each ProtectionDomain.implies(Permission) check is typically followed by
Policy.getPolicyNoCheck, PolicyFile.implies(ProtectionDomain,
Permission), SynchronizedMap.get(WeakHashMap.get(ProtectionDomain)),
Permissions.implies(Permission), Permissions.getPermissionCollection,
HashMap.get(Class<Permission>), PermissionCollection.implies(Permission).
Synchronization creates significant points of contention, although that
has recently been solved with DynamicConcurrentPolicyProvider, however
we still need to performance test it.
AccessControlContext has reasonable equals() and hashCode()
implementations, it will perform well in concurrent cache collections.
Typically Permission equals and hashCode implementations are also
reasonable. The first call from an AccessControlContext will be the
most expensive, however in between revocations, repeated calls will be
cheap, apart from the native call getStackAccessControlContext.
I don't want to be calling DNS!
Cheers,
Peter.
Peter Firmstone wrote:
> Clarification (I overlooked something): The
> checkPermission(Collection<Permission> perms) in the finally block
> would work only for intercepting a method return, but it doesn't work
> for InputStream read() / OutputStream write(), since we wanted to stop
> method execution, if Permission is no longer granted.
>
> For example if a socket delegate returns an OutputStream delegate,
> that wraps an underlying OutputStream, then during the write(), if a
> revocation occurs, we probably want to close the OutputStream, if it
> applies.
>
> The OutputStream write() would still need a reaper, to close the
> OutputStream causing an IOException to be thrown, although as yet I
> haven't determined how to add debug information for an intervening
> revocation.
>
> public void write( byte[] b) {
> ecm.begin(reaper)
> try{
> ecm.checkPermission(writePermission);
> out.write( byte[] b);
> } finally {
> end();
> }
> }
>
> Is it as critical to stop a read() operation?
>
> Since the array passed into the read() operation is written to, we can
> close this as well, causing an IOException, however the user will
> still get some bytes written into the byte array, which it can access
> if it catches the IOException.
>
> public int read(byte[] b) {
> ecm.begin(reaper)
> try{
> ecm.checkPermission(readPermission);
> return in.read( byte[] b);
> } finally {
> end();
> }
> }
>
> But we could provide the optimised single invocation
> checkPermission(Collection<Permission> perms) method as well, for
> calls that don't need to be intercepted.
>
> Perhaps we could be less pedantic about read operations, provided all
> write operations are intercepted?
>
> public int read(byte[] b) {
> try {
> ecm.checkPermission(readPermission);
> } catch (AccessControlException e) {
> this.close();
> throw new IOException(e.toString());
> }
> return in.read( byte[] b);
> }
>
> This checkPermission would be very fast, with only a small amount of
> cpu overhead, because it caches the result for the AccessControlContext.
>
> We could do this for write() as well, if the code was trusted at the
> time of the write() call, then we might assume that the information
> contained within, wasn't borne from an operation of malicious intent,
> we trusted it, so the call can be allowed to complete. This has a
> much smaller performance penalty, any following calls will cause an
> AccessControlExeption to be thrown, if Permission is revoked.
>
> Then write might simply be:
>
> public void write(byte[] b) {
> try {
> ecm.checkPermission(writePermission);
> } catch (AccessControlException e) {
> this.close();
> throw new IOException(e.toString());
> }
> out.write(b);
> }
>
> We might consider what the uses are for Permission revocation? I'm
> starting to think interception might hamper performance too greatly.
>
> The major uses I see for Revocation:
>
> * Reusing ClassLoader's, for proxy's with common code source, by
> removing trust gained by the previous proxy.
> * Limit the time period for which trust is granted to a third
> party. A Trust lease? Trust is only granted while contact is
> maintained.
> * If a proxy has lost contact with it's Server, which was trusted
> and we want to resume (without loosing state) we can revoke
> permission, retry connecting with the Server, verify trust, then
> re grant trust (I'm thinking about the neuromancer remote
> reference problem).
>
> Obviously the feature got your interest, I'm wondering what other uses
> there might have been for permission revocation? This might help me
> better understand the use case scenarios.
>
>
> Peter Firmstone wrote:
>> Fred Oliver wrote:
>>> To at least partially answer my own question, I think that the answer
>>> is that the socket can't be closed (at least in all cases).
>>>
>>> If the delegate for a resource has multiple users (codebases,
>>> principals, etc.) then closing the resource because permission for one
>>> of the users has been revoked denies access to the resource by the
>>> remaining valid users. (This allows a denial of service attack.) And
>>> then, if you can't close the resource (socket), you can't kick loose
>>> the no longer trusted thread blocked reading from it. You may be able
>>> to determine the special case of no user retaining access (everyone's
>>> access was revoked) and can then close the resource.
>>>
>>> In the standard security model, there are no checks for
>>> reading/writing sockets. Allowing revocation means that checks must be
>>> added for each individual read or write call on the socket streams. Is
>>> that level of performance satisfactory?
>>>
>>
>> I've just spotted a possible performance improvement.
>>
>> We can eliminate the end() call in the finally block, put all the
>> checkPermission calls there instead. This substantially reduces the
>> caching operations. Perhaps we can manage the Socket some other way,
>> we just block unauthorised access using the delegate?
>>
>> try {
>> // Do some processing
>> return something;
>> } finally {
>> ECM.checkPermission(Collection<Permission> permissions);
>> }
>>
>> The current expense for making a Permission call via ECM (remembering
>> the first is always going to be expensive), currently requires the
>> three ECM calls in succession:
>>
>> begin();
>> checkPermission(perm);
>> end();
>>
>> begin():
>>
>> 1. Associate the thread with the reaper.
>>
>>
>> checkPermission(perm):
>>
>> 1. Obtain the read lock;
>> 2. Add the current thread to the execution cache.
>> 3. Associate the current AccessControlContext with the current thread
>> 4. Check if the AccessControlContext has been checked for this
>> Permission previously.
>> 5. If it has been checked before, return, else do
>> AccessController.checkPermission(perm), cache the result if it
>> succeeds.
>>
>> Each end():
>>
>> 1. Obtain the read lock;
>> 2. Remove the thread and reaper from the cache.
>> 3. Remove the thread association with the AccessControlContext.
>> 4. Remove the thread from the execution cache.
>>
>> This could be simplified to (no reaper or thread caching):
>>
>> checkPermission(perms)
>>
>> 1. Obtain the read lock;
>> 2. For each Permission, check if the current AccessControlContext has
>> been checked for this Permission previously, if so return.
>> (HashMap lookup - fast).
>> 3. If the AccessControlContext hasn't been checked previously, do
>> AccessController.checkPermission(perm), cache the result if it
>> succeeds, then return.
>>
>> So for performance reasons, it looks like we need to be considering
>> some other way to manage the Socket, the ECM would serve us better if
>> we kept it simple?
>>
>> I think your earlier suggestion of an event notification might be
>> more useful, if provided as a parameter in the checkPermission call,
>> in the event of failure, an event would be generated, the delegate
>> could then decide what action to take. If it only had one user, then
>> it knows to close the Socket, if it has multiple users, it might just
>> keep score.
>>
>> This stops the transmission of data from unauthorised code, but it
>> doesn't close the socket.
>>
>> Cheers,
>>
>> Peter.
>>>
>>>> If there is untrusted code on a thread's stack, and if the thread
>>>> called a delegate, and if the delegate is in the between ECM.begin()
>>>> and ECM.end(), then the delegate's reaper will be called, and it can
>>>> close the socket.
>>>>
>>>> If the revocation happened elsewhere (e.g. the untrusted code is not
>>>> on any stack, or is occupied with some other task), how does the
>>>> socket get closed?
>>>>
>>>> Fred
>>>>
>>
>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Clarification (I overlooked something): The
checkPermission(Collection<Permission> perms) in the finally block would
work only for intercepting a method return, but it doesn't work for
InputStream read() / OutputStream write(), since we wanted to stop
method execution, if Permission is no longer granted.
For example if a socket delegate returns an OutputStream delegate, that
wraps an underlying OutputStream, then during the write(), if a
revocation occurs, we probably want to close the OutputStream, if it
applies.
The OutputStream write() would still need a reaper, to close the
OutputStream causing an IOException to be thrown, although as yet I
haven't determined how to add debug information for an intervening
revocation.
public void write( byte[] b) {
ecm.begin(reaper)
try{
ecm.checkPermission(writePermission);
out.write( byte[] b);
} finally {
end();
}
}
Is it as critical to stop a read() operation?
Since the array passed into the read() operation is written to, we can
close this as well, causing an IOException, however the user will still
get some bytes written into the byte array, which it can access if it
catches the IOException.
public int read(byte[] b) {
ecm.begin(reaper)
try{
ecm.checkPermission(readPermission);
return in.read( byte[] b);
} finally {
end();
}
}
But we could provide the optimised single invocation
checkPermission(Collection<Permission> perms) method as well, for calls
that don't need to be intercepted.
Perhaps we could be less pedantic about read operations, provided all
write operations are intercepted?
public int read(byte[] b) {
try {
ecm.checkPermission(readPermission);
} catch (AccessControlException e) {
this.close();
throw new IOException(e.toString());
}
return in.read( byte[] b);
}
This checkPermission would be very fast, with only a small amount of cpu
overhead, because it caches the result for the AccessControlContext.
We could do this for write() as well, if the code was trusted at the
time of the write() call, then we might assume that the information
contained within, wasn't borne from an operation of malicious intent, we
trusted it, so the call can be allowed to complete. This has a much
smaller performance penalty, any following calls will cause an
AccessControlExeption to be thrown, if Permission is revoked.
Then write might simply be:
public void write(byte[] b) {
try {
ecm.checkPermission(writePermission);
} catch (AccessControlException e) {
this.close();
throw new IOException(e.toString());
}
out.write(b);
}
We might consider what the uses are for Permission revocation? I'm
starting to think interception might hamper performance too greatly.
The major uses I see for Revocation:
* Reusing ClassLoader's, for proxy's with common code source, by
removing trust gained by the previous proxy.
* Limit the time period for which trust is granted to a third
party. A Trust lease? Trust is only granted while contact is
maintained.
* If a proxy has lost contact with it's Server, which was trusted
and we want to resume (without loosing state) we can revoke
permission, retry connecting with the Server, verify trust, then
re grant trust (I'm thinking about the neuromancer remote
reference problem).
Obviously the feature got your interest, I'm wondering what other uses
there might have been for permission revocation? This might help me
better understand the use case scenarios.
Peter Firmstone wrote:
> Fred Oliver wrote:
>> To at least partially answer my own question, I think that the answer
>> is that the socket can't be closed (at least in all cases).
>>
>> If the delegate for a resource has multiple users (codebases,
>> principals, etc.) then closing the resource because permission for one
>> of the users has been revoked denies access to the resource by the
>> remaining valid users. (This allows a denial of service attack.) And
>> then, if you can't close the resource (socket), you can't kick loose
>> the no longer trusted thread blocked reading from it. You may be able
>> to determine the special case of no user retaining access (everyone's
>> access was revoked) and can then close the resource.
>>
>> In the standard security model, there are no checks for
>> reading/writing sockets. Allowing revocation means that checks must be
>> added for each individual read or write call on the socket streams. Is
>> that level of performance satisfactory?
>>
>
> I've just spotted a possible performance improvement.
>
> We can eliminate the end() call in the finally block, put all the
> checkPermission calls there instead. This substantially reduces the
> caching operations. Perhaps we can manage the Socket some other way,
> we just block unauthorised access using the delegate?
>
> try {
> // Do some processing
> return something;
> } finally {
> ECM.checkPermission(Collection<Permission> permissions);
> }
>
> The current expense for making a Permission call via ECM (remembering
> the first is always going to be expensive), currently requires the
> three ECM calls in succession:
>
> begin();
> checkPermission(perm);
> end();
>
> begin():
>
> 1. Associate the thread with the reaper.
>
>
> checkPermission(perm):
>
> 1. Obtain the read lock;
> 2. Add the current thread to the execution cache.
> 3. Associate the current AccessControlContext with the current thread
> 4. Check if the AccessControlContext has been checked for this
> Permission previously.
> 5. If it has been checked before, return, else do
> AccessController.checkPermission(perm), cache the result if it
> succeeds.
>
> Each end():
>
> 1. Obtain the read lock;
> 2. Remove the thread and reaper from the cache.
> 3. Remove the thread association with the AccessControlContext.
> 4. Remove the thread from the execution cache.
>
> This could be simplified to (no reaper or thread caching):
>
> checkPermission(perms)
>
> 1. Obtain the read lock;
> 2. For each Permission, check if the current AccessControlContext has
> been checked for this Permission previously, if so return.
> (HashMap lookup - fast).
> 3. If the AccessControlContext hasn't been checked previously, do
> AccessController.checkPermission(perm), cache the result if it
> succeeds, then return.
>
> So for performance reasons, it looks like we need to be considering
> some other way to manage the Socket, the ECM would serve us better if
> we kept it simple?
>
> I think your earlier suggestion of an event notification might be more
> useful, if provided as a parameter in the checkPermission call, in the
> event of failure, an event would be generated, the delegate could then
> decide what action to take. If it only had one user, then it knows to
> close the Socket, if it has multiple users, it might just keep score.
>
> This stops the transmission of data from unauthorised code, but it
> doesn't close the socket.
>
> Cheers,
>
> Peter.
>>
>>> If there is untrusted code on a thread's stack, and if the thread
>>> called a delegate, and if the delegate is in the between ECM.begin()
>>> and ECM.end(), then the delegate's reaper will be called, and it can
>>> close the socket.
>>>
>>> If the revocation happened elsewhere (e.g. the untrusted code is not
>>> on any stack, or is occupied with some other task), how does the
>>> socket get closed?
>>>
>>> Fred
>>>
>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred Oliver wrote:
> To at least partially answer my own question, I think that the answer
> is that the socket can't be closed (at least in all cases).
>
> If the delegate for a resource has multiple users (codebases,
> principals, etc.) then closing the resource because permission for one
> of the users has been revoked denies access to the resource by the
> remaining valid users. (This allows a denial of service attack.) And
> then, if you can't close the resource (socket), you can't kick loose
> the no longer trusted thread blocked reading from it. You may be able
> to determine the special case of no user retaining access (everyone's
> access was revoked) and can then close the resource.
>
> In the standard security model, there are no checks for
> reading/writing sockets. Allowing revocation means that checks must be
> added for each individual read or write call on the socket streams. Is
> that level of performance satisfactory?
>
I've just spotted a possible performance improvement.
We can eliminate the end() call in the finally block, put all the
checkPermission calls there instead. This substantially reduces the
caching operations. Perhaps we can manage the Socket some other way, we
just block unauthorised access using the delegate?
try {
// Do some processing
return something;
} finally {
ECM.checkPermission(Collection<Permission> permissions);
}
The current expense for making a Permission call via ECM (remembering
the first is always going to be expensive), currently requires the three
ECM calls in succession:
begin();
checkPermission(perm);
end();
begin():
1. Associate the thread with the reaper.
checkPermission(perm):
1. Obtain the read lock;
2. Add the current thread to the execution cache.
3. Associate the current AccessControlContext with the current thread
4. Check if the AccessControlContext has been checked for this
Permission previously.
5. If it has been checked before, return, else do
AccessController.checkPermission(perm), cache the result if it
succeeds.
Each end():
1. Obtain the read lock;
2. Remove the thread and reaper from the cache.
3. Remove the thread association with the AccessControlContext.
4. Remove the thread from the execution cache.
This could be simplified to (no reaper or thread caching):
checkPermission(perms)
1. Obtain the read lock;
2. For each Permission, check if the current AccessControlContext has
been checked for this Permission previously, if so return.
(HashMap lookup - fast).
3. If the AccessControlContext hasn't been checked previously, do
AccessController.checkPermission(perm), cache the result if it
succeeds, then return.
So for performance reasons, it looks like we need to be considering some
other way to manage the Socket, the ECM would serve us better if we kept
it simple?
I think your earlier suggestion of an event notification might be more
useful, if provided as a parameter in the checkPermission call, in the
event of failure, an event would be generated, the delegate could then
decide what action to take. If it only had one user, then it knows to
close the Socket, if it has multiple users, it might just keep score.
This stops the transmission of data from unauthorised code, but it
doesn't close the socket.
Cheers,
Peter.
>
>> If there is untrusted code on a thread's stack, and if the thread
>> called a delegate, and if the delegate is in the between ECM.begin()
>> and ECM.end(), then the delegate's reaper will be called, and it can
>> close the socket.
>>
>> If the revocation happened elsewhere (e.g. the untrusted code is not
>> on any stack, or is occupied with some other task), how does the
>> socket get closed?
>>
>> Fred
>>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Fred Oliver <fk...@gmail.com>.
To at least partially answer my own question, I think that the answer
is that the socket can't be closed (at least in all cases).
If the delegate for a resource has multiple users (codebases,
principals, etc.) then closing the resource because permission for one
of the users has been revoked denies access to the resource by the
remaining valid users. (This allows a denial of service attack.) And
then, if you can't close the resource (socket), you can't kick loose
the no longer trusted thread blocked reading from it. You may be able
to determine the special case of no user retaining access (everyone's
access was revoked) and can then close the resource.
In the standard security model, there are no checks for
reading/writing sockets. Allowing revocation means that checks must be
added for each individual read or write call on the socket streams. Is
that level of performance satisfactory?
> If there is untrusted code on a thread's stack, and if the thread
> called a delegate, and if the delegate is in the between ECM.begin()
> and ECM.end(), then the delegate's reaper will be called, and it can
> close the socket.
>
> If the revocation happened elsewhere (e.g. the untrusted code is not
> on any stack, or is occupied with some other task), how does the
> socket get closed?
>
> Fred
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Fred Oliver <fk...@gmail.com>.
On Sun, Aug 15, 2010 at 11:57 PM, Peter Firmstone <ji...@zeus.net.au> wrote:
>> - When the run() method is called (on which thread?)
>
> It's called from a small thread pool, within the ECM.
>
>> , how does it
>> determine which codebase or principal (etc.) to use when checking
>> permissions? How does a socket delegate know to close a socket?
>>
>
> It will be from the AccessControlContext, the Reaper will have it's
> ProtectionDomain on the stack at the time.
If there is untrusted code on a thread's stack, and if the thread
called a delegate, and if the delegate is in the between ECM.begin()
and ECM.end(), then the delegate's reaper will be called, and it can
close the socket.
If the revocation happened elsewhere (e.g. the untrusted code is not
on any stack, or is occupied with some other task), how does the
socket get closed?
Fred
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred Oliver wrote:
> Why not have
> ECM.checkPermission(Collection<Permission>)
> instead of the begin/check/end block? Would this remove the Thread
> object from those maps?
>
No the finally block is to prevent a method returning, while revocation
is underway, and allow a Reaper to clean up before it returns.
> What if a delegate requires multiple permissions of different classes
> from multiple ECMs? Should this be done at the RevokeableDynamicPolicy
> level instead? Should the ECM be hidden from the public API?
>
No there's only one ECM per policy, it is concurrent, but blocks during
revocation.
> I was looking at writing a SocketDelegate and I' m not clear on some things.
>
Excellent!
> - How do I get a reference to the system RevokableDynamicPolicy object?
>
I need to add a static method to net.jini.security.Security.
> - Once I have it, how do I check for actual permission to do
> something? Is there a utility to iterate through the list of
> PermissionGrants? Or some other method?
>
Not yet, but that is my intent, to create a utility to iterate through
the permission grants. Perhaps we could have a utility method on
RevokeableDynamicPolicy, since it caches the Permission's during the
GrantPermission checks, to avoid a PermissionGrant implementer from
using mutability to elevate privileges. It wouldn't be too difficult to
iterate through them, using implies(ProtectionDomain). I'm going to
change the array of Permission's returned from a PermissionGrant back to
an unmodifiable collection, as per your suggestion, to enforce
immutability, it also removes one copy operation and makes iteration
simpler.
> - If we have class based ECM (which seems simpler), then should
> Class<? extends Permission> appear in many places where Permission
> currently appears? e.g.
>
> RevokableDynamicPolicy.getExecutionManager(Class<? extends Permission>);
> Controller.revoke(Set<Class<? extends Permission>> classes);
> Controller.getPermission() returns Class<? extends Permission>
> Controller.getECManager(Class<? extends Permission>);
> Controller.pool uses Class<? extends Permission> as key?
>
I've removed controller, got rid of the static caches as you suggested.
I've uploaded ExecutionContextManager and ECM onto
svn for review:
org.apache.river.imp.security.policy.se.ECM
org.apache.river.api.security.policy.ExecutionContextManager
The RevokeableDynamicPolicy is an interface, there's also a
RevokeableDynamicPolicySpi, so we can utilise different features on
different java platforms, such as concurrency etc.
> In Controller, do the pool and cont fields need to be separate? If the
> weak references get cleared at different times, then these two
> structures can briefly diverge. Is this OK?
>
> Do you still have ECM.addAction()?
No, it's now ECM.begin(Reaper), where Reaper extends Runnable, it's
given the thread we want to prevent from returning security sensitive
information. I'm still not sure if this is the right way to handle it
yet. I've thought about throwing an AccessControlException from the
end() method if any Permission's are revoked, this gives someone trying
to debug more information, it still requires the delegate have a reaper
to clean up. Feel free to play with it, modify it on svn.
> The ECM.addAction() takes a
> Runnable, which gets the job done. I'm concerned that this requires
> that delegates implement Runnable,
No just a private implementation within the delegate. It can be as
simple as interrupting the thread in question if that's the desired
behaviour, that would probably cause confusion during debugging. This
is why I'm thinking about throwing an AccessControlException from the
end() method in the finally block.
> in conflict with some other use of
> Runnable. Perhaps it's worth adding an interface for this like
> RevocationListener with a permissionRevoked() method.
>
> Most of the methods in the delegates get called from the untrusted
> code, but the run() method does not.
>
> - When the run() method is called (on which thread?)
It's called from a small thread pool, within the ECM.
> , how does it
> determine which codebase or principal (etc.) to use when checking
> permissions? How does a socket delegate know to close a socket?
>
It will be from the AccessControlContext, the Reaper will have it's
ProtectionDomain on the stack at the time.
Have a look on svn, you might have a better idea, the delegate has to
associate the Reaper with the method at the moment. I'm not entirely
comfortable with the Reaper.
Cheers & Thanks,
Peter.
> Fred
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Fred Oliver <fk...@gmail.com>.
Why not have
ECM.checkPermission(Collection<Permission>)
instead of the begin/check/end block? Would this remove the Thread
object from those maps?
What if a delegate requires multiple permissions of different classes
from multiple ECMs? Should this be done at the RevokeableDynamicPolicy
level instead? Should the ECM be hidden from the public API?
I was looking at writing a SocketDelegate and I' m not clear on some things.
- How do I get a reference to the system RevokableDynamicPolicy object?
- Once I have it, how do I check for actual permission to do
something? Is there a utility to iterate through the list of
PermissionGrants? Or some other method?
- If we have class based ECM (which seems simpler), then should
Class<? extends Permission> appear in many places where Permission
currently appears? e.g.
RevokableDynamicPolicy.getExecutionManager(Class<? extends Permission>);
Controller.revoke(Set<Class<? extends Permission>> classes);
Controller.getPermission() returns Class<? extends Permission>
Controller.getECManager(Class<? extends Permission>);
Controller.pool uses Class<? extends Permission> as key?
In Controller, do the pool and cont fields need to be separate? If the
weak references get cleared at different times, then these two
structures can briefly diverge. Is this OK?
Do you still have ECM.addAction()? The ECM.addAction() takes a
Runnable, which gets the job done. I'm concerned that this requires
that delegates implement Runnable, in conflict with some other use of
Runnable. Perhaps it's worth adding an interface for this like
RevocationListener with a permissionRevoked() method.
Most of the methods in the delegates get called from the untrusted
code, but the run() method does not.
- When the run() method is called (on which thread?), how does it
determine which codebase or principal (etc.) to use when checking
permissions? How does a socket delegate know to close a socket?
Fred
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Peter Firmstone wrote:
> Fred,
>
> I've thought about it some more. When there were smart people trying
> to solve this problem what were the constraints they faced at the time?
>
> When Java 1.4 was released, a new Policy method was added,
> implies(ProtectionDomain, Permission), and the ProtectionDomain
> modified to allow dynamic ProtectionDomain's via a new 4 parameter
> constructor.
>
> Prior to Java 1.4, the method used to get the Permission's from the
> policy, for a ProtectionDomain, was indirectly via
> policy.getPermissions(ProtectionDomain), this was handed to the
> ProtectionDomain constructor,
That should read policy.getPermissions(CodeSource), and Java 1.4 onward
merged the Permissions with a ProtectionDomain.toString() call via the
call policy.getPermissions(ProtectionDomain). Anyway it would have
appeared dauntingly difficult, since there were many different
implementations at the time, things have stabilised now thankfully.
> and was static, if ProtectionDomain.toString() was called, this caused
> the ProtectionDomain to merge any new Permissions from the policy with
> those in it's private Permissions collection.
>
> So anybody at that time, had to consider the problem of supporting pre
> Java 1.4 program's, policy's and SecurityManager implementations. To
> enable dynamic revocation of a Permission, you cannot return any
> dynamic Permission's via the policy.getPermissions method, they would
> become merged within a ProtectionDomain's Permissions, checked after
> the policy in a dynamic PD returning true after the policy returned
> false ( the policy is not checked at all in a static PD).
>
> Then there is the problem of escaping references to objects with
> privileged behaviour for some existing Permission's.
>
> Now, we no longer have to contend with supporting JVM's prior to 1.4,
> so this issue has been resolved by time, the second issue, hopefully
> now the first is resolved can be resolved now too, with new
> Permission's, Security Delegates, and optimised repeated
> checkPermission() calls.
>
> Some benefit's of revocation (and I suspect you know of others); the
> reuse of ClassLoader's and the avoidance of re verification of
> bytecode, another might be the possibility of simplifying cross domain
> login's and the separation of concerns for "code trust" and "user
> trust". You can't trust code forever, at some point, even signed
> trusted code will experience a security flaw, in which case you can
> revoke some trust of that particular code, since it has been found
> untrustworthy in some respect.
>
> There's a document at https://issues.apache.org/jira/browse/RIVER-341
>
> This is intended to cover the separation of implementation from API
> and evolution of API (by extension) and evolution of implementation by
> versioning (replacement).
>
> For Services, implementation's can be versioned, by adding version
> metadata into the jar file, they can be updated, URL's can be
> annotated with version information and message digests,
> PermissionGrant's can be utilised to determine the level of trust
> dynamically based on an implementation version and signer certificates.
>
> There are many possibilities.
>
> The issue's with fine grained permission's I'd like to see solved with
> some new tools, Service Entry's and jar files containing the
> Permission's they require.
>
> Best Regards,
>
> Peter.
>
> Fred Oliver wrote:
>> It's so much easier to ask questions than provide answers. This is
>> such a difficult problem you are trying to solve that other very smart
>> people have chosen other directions.
>>
>> Fred
>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred,
I've thought about it some more. When there were smart people trying to
solve this problem what were the constraints they faced at the time?
When Java 1.4 was released, a new Policy method was added,
implies(ProtectionDomain, Permission), and the ProtectionDomain modified
to allow dynamic ProtectionDomain's via a new 4 parameter constructor.
Prior to Java 1.4, the method used to get the Permission's from the
policy, for a ProtectionDomain, was indirectly via
policy.getPermissions(ProtectionDomain), this was handed to the
ProtectionDomain constructor, and was static, if
ProtectionDomain.toString() was called, this caused the ProtectionDomain
to merge any new Permissions from the policy with those in it's private
Permissions collection.
So anybody at that time, had to consider the problem of supporting pre
Java 1.4 program's, policy's and SecurityManager implementations. To
enable dynamic revocation of a Permission, you cannot return any dynamic
Permission's via the policy.getPermissions method, they would become
merged within a ProtectionDomain's Permissions, checked after the policy
in a dynamic PD returning true after the policy returned false ( the
policy is not checked at all in a static PD).
Then there is the problem of escaping references to objects with
privileged behaviour for some existing Permission's.
Now, we no longer have to contend with supporting JVM's prior to 1.4, so
this issue has been resolved by time, the second issue, hopefully now
the first is resolved can be resolved now too, with new Permission's,
Security Delegates, and optimised repeated checkPermission() calls.
Some benefit's of revocation (and I suspect you know of others); the
reuse of ClassLoader's and the avoidance of re verification of bytecode,
another might be the possibility of simplifying cross domain login's and
the separation of concerns for "code trust" and "user trust". You can't
trust code forever, at some point, even signed trusted code will
experience a security flaw, in which case you can revoke some trust of
that particular code, since it has been found untrustworthy in some respect.
There's a document at https://issues.apache.org/jira/browse/RIVER-341
This is intended to cover the separation of implementation from API and
evolution of API (by extension) and evolution of implementation by
versioning (replacement).
For Services, implementation's can be versioned, by adding version
metadata into the jar file, they can be updated, URL's can be annotated
with version information and message digests, PermissionGrant's can be
utilised to determine the level of trust dynamically based on an
implementation version and signer certificates.
There are many possibilities.
The issue's with fine grained permission's I'd like to see solved with
some new tools, Service Entry's and jar files containing the
Permission's they require.
Best Regards,
Peter.
Fred Oliver wrote:
> It's so much easier to ask questions than provide answers. This is
> such a difficult problem you are trying to solve that other very smart
> people have chosen other directions.
>
> Fred
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred Oliver wrote:
> It's so much easier to ask questions than provide answers.
Successful Problem Solving is borne out of asking the right questions.
It takes keen senses and experience to know the right questions to ask,
asking the wrong ones just makes it take longer.
You've asked a lot of the right questions.
> This is
> such a difficult problem you are trying to solve that other very smart
> people have chosen other directions.
>
Perhaps it's not being at the top of the game, I have nothing to loose
in trying, in either case, I hope we solve it.
In my game (Mechanical & Project Engineering) there's a saying: "Your
only as good as your last stuff up". That doesn't apply here, unless of
course it makes release without enough review from people like yourself ;)
Cheers & thanks,
Peter.
> Fred
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred Oliver wrote:
> It's so much easier to ask questions than provide answers. This is
> such a difficult problem you are trying to solve that other very smart
> people have chosen other directions.
>
> Fred
>
>
Fred,
People have their reasons for deciding which problems not to solve,
sometimes very smart people choose not to solve difficult problems, not
because they can't, but because they're worn down by other difficult
problems and would prefer to go fishing or spend time with their family,
rather than solve one more problem.
But the fact they choose not to, can give the rest of us an ego boost ;)
Every dog has his day.
Please do continue participating, your assistance has been invaluable, I
hope you find time to hang out on this list more often.
Thanks,
Peter.
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Fred Oliver <fk...@gmail.com>.
It's so much easier to ask questions than provide answers. This is
such a difficult problem you are trying to solve that other very smart
people have chosen other directions.
Fred
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred Oliver wrote:
> It looks like permissions can only be managed or revoked by class.
I made this choice initially because Permission implies(Permssion) is
not like equals(Object), one doesn't necessarily mean the other and
there are many cases where !equal but implies == true. However given
some more thought, I'm sure it would be possible to have a water tight
revocation by Permission instead of class.
However that in itself is not a simple problem, we don't know the
ProtectionDomain's on the caller's stack, we don't know the combination
of Permission's that will cause implies to return true, this would
require a PermissionCollection implies check.
Since we cache the AccessControlContext's, we could create a
DomainCombiner, that amalgamates them, then call implies on the
resultant AccessControlContext, if this returns false, then we know that
one of the ProtectionDomain's has been given access.
> If
> a domain has been granted more than one SocketPermission (e.g. to
> grant permission to use two ports or communicate with two hosts,
> etc.), can I revoke one of them?
>
Yes, but with the current code, both Sockets would be closed, both
delegates would need to catch the Socket Exception and attempt to open a
new Socket, only one would succeed, the one that hadn't been revoked.
> If I have a delegate for a complex object (say Socket) to which sets
> of permissions may apply, how would the delegate handle the sets? If
> one SocketPermission were revoked, does the delegate need deep
> knowledge of the object it protects to determine if that revoked
> permission applies?
No, I figured the safest way is to know the Socket information, close
it, catch the exception, then create a new Socket from the previous
information. If an AccessControlException is then caught, the delegate
can then close the Socket. This will cause a brief interruption to
service for Sockets where Permission hasn't been revoked, but the Socket
is closed and replaced.
The delegate shouldn't need intimate knowledge of the caller, that's the
job of the ExecutionContextManager (ECM).
Perhaps a delegate could set an atomic integer (via the ECM for each
protected method to monitor execution, if greater than 0, there is a
method that has not yet returned, then action should be taken. If 0 the
permission check will be performed next call and no action to close the
socket needs to be taken.
I guess the AccessControlContext's could be stored in order in an
execution cache, then we would know which are in current execution, we
could re call implies against those. The trouble is, when do method's
exit? So a call (aptly named methodExit()?) would have to be made on
the ECM by the delegate prior to returning any protected method.
> Can a delegate always obtain the complete set of
> permissions which apply to it to reevaluate more fully?
>
Yes it is possible to obtain a current set of PermissionGrant's and
query them, provided the delegate has Permission.
> Should Controller maintain static maps of its own instances? If that
> map were contained by instances of RevokeableDynamicPolicy, then there
> could be multiple policy objects in use at one time.
>
Hmm, true, the implementation forces a single revokeable policy for the
JVM, what advantage is there to having multiple Dynamic policies?
> PrincipalGrant extends PermissionGrant and contains two Collections
> which are both used in the hash value and equals method. I would be
> inclined to enforce their immutability with
> Collections.unmodifiableCollection().
OK.
> In the equals method, you might
> return false if the stored hash values are different before comparing
> the collections.
>
Thanks, speed tip.
> PermissionGrant.getPermissions() is documented as returning an
> immutable Collection, but the method returns a mutable array instead?
>
Previously it did, however I realised that since anyone can implement
PermissionGrant, (with appropriate Permission) I could not guarantee the
immutability of the underlying collection, with regard to the way the
RevokeableDynamicPolicy see's it, so I decided that at the time the
Policy checks GrantPermission, that it clone the array and cache it, in
a Weakly referenced Map with PermissionGrant as it's key.
If the underlying collection cannot be guaranteed immutable, the policy
would not check GrantPermission again, an implementer could gain
elevated Permission's via mutability otherwise, so I figured.
Thanks, you've given me some more ideas.
Cheers,
Peter.
> Fred
>
> On Wed, Aug 11, 2010 at 2:56 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>> Fred,
>>
>> Any thoughts? The ExecutionContextManager interface and implementation
>> (Controller) are shown below, the RevokeableDynamicPolicy and
>> PermissionGrant interfaces have implementations available on svn.
>>
>> The ExecutionContextManager is based around our discussion.
>>
>> Note that no Security Delegate is provided here, just a tool, which a
>> delegate or any other object may use,
>> ExecutionContextManager.checkPermission() and another method
>> addAction(Runnable r), to accept a Runnable to perform any clean up tasks
>> for complete revocation such as closing Socket's etc. The delegate need not
>> implement any interface other than the object it encapsulates.
>>
>> Cheers,
>>
>> Peter.
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Thoughts?
Some minor changes to the ECM:
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.river.api.security;
import java.security.AccessControlException;
import java.security.Permission;
import java.util.Set;
/**
* <p>
* An ExecutionContextManager is designed to be repeatedly called, where
calling
* AccessController.checkPermission(Permission) is too great an overhead.
* </p><p>
* The ExecutionContextManager will only call
* AccessControlContext.checkPermission(Permission) once, for each
context. This
* ensures that checkPermission isn't called again until the context
changes, or
* the Permission checked by this ExecutionContextManager experiences a
* revoke for any ProtectionDomain by the RevokeableDynamicPolicy.
* </p><p>
* A Runnable may be submitted to the ExecutionContextManager to be executed
* when a Permission Revocation matching the stored Permission occurs.
* </p><p>
* Use of this class is not limited to Revokeable Permission's.
* </p>
* @author Peter Firmstone
* @see RevokeableDynamicPolicy
* @see Permission
* @see AccessControlContext
*/
public interface ExecutionContextManager {
/**
* <p>
* This is a call made by a Security Delegate, or other Object used to
* control access to privileged methods or constructors, similar to the
* AccessControll.checkPermssion(Permission) call, but with the
Permission
* pre defined and unchanging. The Permission check is optimised,
* typically a method may only be concerned with a single Permission
check,
* but in many existing cases, the AccessController check is too
expensive
* to be called on every method invocation. The
ExecutionContextManager
* should optimise this call by ensuring that
checkPermission(Permission) is only
* called once per AccessControlContext. In other words if the caller's
* AccessControlContext hasn't changed, then checkPermission(Permission)
* isn't called again as it would be assumed to succeed, unless the
* RevokeableDynamicPolicy revokes a Permission with the same class,
* in which case the Permission must be checked again.
* </p><p>
* Typically where it is not feasable to call
AccessController.checkPermission
* on every invocation, those objects are usually guarded or have the
* checkPermission method called in the constructor.
* </p><p>
* ExecutionContextManager provides a more thorough form of protection.
* </p><p>
* ExecutionContextManager should be used sparingly, the more generic
* or widely applicable the Permission, the more efficient the
* ExecutionContextManager is in memory usage terms.
* </p><p>
* This method also add's the current context to the current execution
* cache, it is not removed from that cache until after
accessControlExit()
* has been called.
* </p>
*
* @param reaper - Runnable provided to clean up if Revocation
occurs during
* the execution that follows this call, until the try block exits,
* the current thread is not interrupted, rather the reaper is expected
* to know what resources need to be closed.
*
* @throws java.security.AccessControlException
*/
public void accessControlCommence(Runnable reaper) throws
AccessControlException;
/**
* <p>
* This method is to advise the ExecutionContextManager that the
* current method or protected region has returned, it must
* always follow the accessControlCommence() call, in response,
* the ECM removes the current context from the execution context cache
* and releases the reference to the Runnable reaper.
* </p><p>
* If the execution context is still in the cache at the time of
* revocation, the reaper will be run only if affected directly by the
* revocation, the thread may be asked to wait for a short period, to
* allow the determination to be made.
* Revocation applicability is determined by
* AccessControlContext.checkPermission(Permission p) where p is the
* Permission affected.
* </p><p>
* This should be executed in the finally{} block of a try catch
statement,
* which always executes in the event of an exception or normal return.
* </p>
* <code>
* try{
* ecm.accessControlCommence(reaper);
* // do something
* return;
* } catch (AccessControlException e) {
* throw new SecurityException("Method blah caused an...", e);
* } finally {
* ecm.accessControlExit();
* }
* </code>
* <p>
* This should not be confused with AccessController.doPrivileged blocks
* </p>
*/
public void accessControlExit();
/**
* Get the Permission monitored by this ExecutionContextManager.
* @return Permission monitored by the ExecutionContextManager
*/
public Permission getPermission();
}
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred Oliver wrote:
> If I have a delegate for a complex object (say Socket) to which sets
> of permissions may apply, how would the delegate handle the sets? If
> one SocketPermission were revoked, does the delegate need deep
> knowledge of the object it protects to determine if that revoked
> permission applies? Can a delegate always obtain the complete set of
> permissions which apply to it to reevaluate more fully?
>
>
Hi Fred, I don't think I answered this one properly, the delegate could
handle the set's of Permission's by obtaining an ExecutionContextManager
for each Permission.
So for dynamically granted Socket Permission's the delegate would create
the ExecutionContextManager and hold it for the duration required for a
particular environment.
The Socket delegate may also create other delegates for other objects
that it returns, such as InputStream.
I'll upload the code to svn shortly.
Cheers,
Peter.
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Fred Oliver <fk...@gmail.com>.
It looks like permissions can only be managed or revoked by class. If
a domain has been granted more than one SocketPermission (e.g. to
grant permission to use two ports or communicate with two hosts,
etc.), can I revoke one of them?
If I have a delegate for a complex object (say Socket) to which sets
of permissions may apply, how would the delegate handle the sets? If
one SocketPermission were revoked, does the delegate need deep
knowledge of the object it protects to determine if that revoked
permission applies? Can a delegate always obtain the complete set of
permissions which apply to it to reevaluate more fully?
Should Controller maintain static maps of its own instances? If that
map were contained by instances of RevokeableDynamicPolicy, then there
could be multiple policy objects in use at one time.
PrincipalGrant extends PermissionGrant and contains two Collections
which are both used in the hash value and equals method. I would be
inclined to enforce their immutability with
Collections.unmodifiableCollection(). In the equals method, you might
return false if the stored hash values are different before comparing
the collections.
PermissionGrant.getPermissions() is documented as returning an
immutable Collection, but the method returns a mutable array instead?
Fred
On Wed, Aug 11, 2010 at 2:56 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
> Fred,
>
> Any thoughts? The ExecutionContextManager interface and implementation
> (Controller) are shown below, the RevokeableDynamicPolicy and
> PermissionGrant interfaces have implementations available on svn.
>
> The ExecutionContextManager is based around our discussion.
>
> Note that no Security Delegate is provided here, just a tool, which a
> delegate or any other object may use,
> ExecutionContextManager.checkPermission() and another method
> addAction(Runnable r), to accept a Runnable to perform any clean up tasks
> for complete revocation such as closing Socket's etc. The delegate need not
> implement any interface other than the object it encapsulates.
>
> Cheers,
>
> Peter.
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred,
Any thoughts? The ExecutionContextManager interface and implementation
(Controller) are shown below, the RevokeableDynamicPolicy and
PermissionGrant interfaces have implementations available on svn.
The ExecutionContextManager is based around our discussion.
Note that no Security Delegate is provided here, just a tool, which a
delegate or any other object may use,
ExecutionContextManager.checkPermission() and another method
addAction(Runnable r), to accept a Runnable to perform any clean up
tasks for complete revocation such as closing Socket's etc. The
delegate need not implement any interface other than the object it
encapsulates.
Cheers,
Peter.
package org.apache.river.api.security;
import java.security.Permission;
import java.util.List;
/**
* RevokeableDynamicPolicy, is a Java Security Policy Provider that supports
* Runtime Dynamically Grantable and Revokeable Permission's, in the form
* of PermissionGrant's
*
* @author Peter Firmstone
* @see java.security.Policy
* @see java.security.ProtectionDomain
* @see java.security.AccessController
* @see java.security.DomainCombiner
* @see java.security.AccessControlContext
* @see java.security.Permission
*/
public interface RevokeableDynamicPolicy {
/**
* Grant Permission's as specified in a List of PermissionGrant's
* which can be added by concurrent threads.
*
* @param grants
*/
public void grant(List<PermissionGrant> grants);
/**
* Revoke, only removes any PermissionGrant's that are identical,
typically
* a List of Grant's is obtained by getPermssionGrant's which can be
* manipulated and investigated, any that are undesirable should be
passed
* to revoke.
*
* Revokes can only be performed synchronuously with other Revokes.
*
* @param grants
*/
public void revoke(List<PermissionGrant> grants);
/**
* Get a List copy of the current PermissionGrant's in force.
* @return
*/
public List<PermissionGrant> getPermissionGrants();
/**
* The Revocation of Permission's requires a new construct for
controlling
* access. Typically many objects that provide privileged functionality
* are guarded in their constructor by a checkPermission(Permission)
call
* or by a GuardedObject, once this check has succeeded, the caller
receives
* a reference to the guarded object. These Permission's cannot be
* revoked completely, because the reference has escaped, the
permission
* check will not be called again.
*
* Instead what is needed is a permission check that is efficient enough
* to allow the methods that provide the privileged functionality to be
* called for every method invocation. What the ExecutionContextManager
* does is minimise the checkPermission calls by skipping
checkPermission for
* any execution AccessControlContext that has already passed, unless
* a Permission related to the one being managed is revoked, in
which case
* the cache of AccessControlContext's previously checked are cleared.
*
* The ExecutionContextManager is specific only to one permission, this
* is the enabler for the reduced checkPermission calls, since a
* Permission should behave in a persistent manner, once it passes, it
* should always pass, unless revoked.
*
*
* @param p Permission the ExecutionContextManager will check.
* @return a new ExecutionContextManager instance.
*/
public ExecutionContextManager getExecutionContextManager(Permission p);
/**
*
* @return true if Revoke supported.
*/
public boolean revokeSupported();
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.river.api.security;
import java.security.AccessControlException;
import java.security.Permission;
/**
* <p>
* An ExecutionContextManager is designed to be repeatedly called, where
calling
* AccessController.checkPermission(Permission) is too great an overhead.
* </p><p>
* The ExecutionContextManager will only call
* AccessControlContext.checkPermission(Permission) once, for each
context. This
* ensures that checkPermission isn't called again until the context
changes, or
* the Permission checked by this ExecutionContextManager experiences a
* revoke for any ProtectionDomain by the RevokeableDynamicPolicy.
* </p><p>
* A Runnable may be submitted to the ExecutionContextManager to be executed
* when a Permission Revocation matching the stored Permission occurs.
* </p><p>
* Use of this class is not limited to Revokeable Permission's.
* </p>
* @author Peter Firmstone
* @see RevokeableDynamicPolicy
* @see Permission
* @see AccessControlContext
*/
public interface ExecutionContextManager {
/**
* <p>
* This is a call made by a Security Delegate, or other Object used to
* control access to privileged methods or constructors, similar to the
* AccessControll.checkPermission(Permission) call, but with the
Permission
* pre defined and unchanging. The Permission check is optimised,
* typically a method may only be concerned with a single Permission
check,
* but in many existing cases, the AccessController check is too
expensive
* to be called on every method invocation. The
ExecutionContextManager
* should optimise this call by ensuring that
checkPermission(Permission) is only
* called once per AccessControlContext. In other words if the caller's
* AccessControlContext hasn't changed, then checkPermission(Permission)
* isn't called again as it would be assumed to succeed, unless the
* RevokeableDynamicPolicy revokes a Permission with the same class,
* in which case the Permission must be checked again.
* </p><p>
* Typically where it is not feasable to call
AccessController.checkPermission
* on every invocation, those objects are usually guarded or have the
* checkPermission method called in the constructor.
* </p><p>
* ExecutionContextManager provides a more thorough form of protection.
* </p><p>
* ExecutionContextManager should be used sparingly, the more generic
* or widely applicable the Permission, the more efficient the
* ExecutionContextManager is in memory usage terms.
* </p>
* @throws java.security.AccessControlException
*/
public void checkPermission() throws AccessControlException;
/**
* Get the Permission monitored by this ExecutionContextManager.
* @return Permission monitored by the ExecutionContextManager
*/
public Permission getPermission();
/**
* <p>
* Action to be taken in event that the Permission monitored by this
* ExecutionContextManager has experienced a revocation event. This
* allows Sockets to be closed, or any clean up to occur or any other
* task that must be performed to reset state.
* </p><p>
* This may not be the only action performed, since the same
* ExecutionContextManager may be used by multiple clients, the Runnable
* is only weakly referenced, garbage collection is relied upon for its
* removal.
* </p><p>
* The implementer must have the Permission's required for
* execution, no privileges are assigned.
* </p>
* @param r - Clean up task to be performed.
*/
public void addAction(Runnable r);
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.river.imp.security.policy.se;
import java.lang.ref.WeakReference;
import java.security.AccessControlContext;
import java.security.AccessControlException;
import java.security.AccessController;
import java.security.Permission;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import org.apache.river.api.security.ExecutionContextManager;
import org.apache.river.imp.util.ConcurrentWeakIdentityMap;
/**
* An implementation of ExecutionContextManager.
*
* @author Peter Firmstone.
*/
class Controller implements ExecutionContextManager {
/* The class manages revoke for all it's objects. */
private static final ConcurrentMap<Permission,
ExecutionContextManager> pool
= new ConcurrentWeakIdentityMap<Permission,
ExecutionContextManager>();
private static final List<WeakReference<Controller>> cont =
new ArrayList<WeakReference<Controller>>(80);
/**
* This method is called by the RevokeableDynamicPolicy to get a List
* of Runnable clean up jobs that must be performed to complete the
* revocation of Permissions.
*
* A Thread pool can be used to perform the work, however the policy's
* revoke call must not return until after all the jobs are complete.
*
* @param classes - A set of Permission Class object's for the
Permission's
* being revoked.
* @return A List of Runnable clean up tasks to be performed to complete
* the revocation.
*/
static List<Runnable> revoke(Set<Class> classes){
List<Runnable> cleanupJobs;
synchronized (cont){
cleanupJobs = new ArrayList<Runnable>(cont.size());
Iterator<WeakReference<Controller>> it =
cont.iterator();
while (it.hasNext()) {
WeakReference<Controller> wf = it.next();
Controller ecm = wf.get();
if ( ecm != null ){
if (classes.contains(ecm.getPermission().getClass())){
ecm.clear();
cleanupJobs.addAll(ecm.getRunnable());
}
} else {
it.remove();
}
}
}
return cleanupJobs;
}
static ExecutionContextManager getECManager(Permission p){
ExecutionContextManager exm = pool.get(p);
if ( exm != null ){
return exm;
}
exm = new Controller(p);
ExecutionContextManager existed = pool.putIfAbsent(p, exm);
if ( existed != null){
exm = existed;
}
return exm;
}
/* Object state and methods */
private final Permission perm;
private final List<WeakReference<Runnable>> cleanup;
private final Set<AccessControlContext> checkedExecutionContext;
/* A Revocation in progress will delay construction of a new
Controller */
private Controller(Permission p){
perm = p;
WeakReference<Controller> mac =
new WeakReference<Controller>(this);
cleanup = new ArrayList<WeakReference<Runnable>>();
checkedExecutionContext = new HashSet<AccessControlContext>(80);
// this must be done last.
synchronized (cont){
cont.add(mac);
}
}
public void checkPermission() throws AccessControlException {
AccessControlContext executionContext = AccessController.getContext();
synchronized (checkedExecutionContext){
if (checkedExecutionContext.contains(executionContext)) {
return;
}
}
executionContext.checkPermission(perm);
/* If we get to here without exception we can add it.
* The RevokeablyDynamicPolicy will revoke the Permission prior to
* clearing the current checked execution context as part of the revoke
* process, this means
* that while the revocation isn't yet complete, the checked context
* will still return true, but the actual permission check would return
* false, however at the completion of the revocation process, the
* Runnable provided will be executed to perform any necessary
cleanupJobs
* to fully revoke.
*
* This prevents invalid execution context's from finding their way
* into the checked Execution Context which would be a security breach.
*
* Revoke's happen synchronuously to ensure that this contract is
honored.
*/
synchronized (checkedExecutionContext){
checkedExecutionContext.add(executionContext);
}
}
public Permission getPermission() {
return perm;
}
public void addAction(Runnable r) {
synchronized (cleanup){
cleanup.add(new WeakReference<Runnable>(r));
}
}
private List<Runnable> getRunnable(){
List<Runnable> tasks;
synchronized (cleanup){
tasks = new ArrayList<Runnable>(cleanup.size());
Iterator<WeakReference<Runnable>> it = cleanup.iterator();
while (it.hasNext()){
WeakReference<Runnable> wr = it.next();
Runnable r = wr.get();
if (r != null){
tasks.add(r);
}else {
cleanup.remove(wr);
}
}
}
return tasks;
}
private void clear(){
synchronized (checkedExecutionContext){
checkedExecutionContext.clear();
}
}
}
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.river.api.security;
import java.security.CodeSource;
import java.security.Permission;
import java.security.Principal;
import java.security.ProtectionDomain;
/**
* PermissionGrant's are expected to be effectively immutable,
* threadsafe and have a good hashCode implementation to perform well in
* Collections.
*
* You shouldn't pass around PermissionGrant's to just anyone as they can
* provide an attacker with information about which Permission's may be
granted.
*
* @author Peter Firmstone
*/
public interface PermissionGrant {
/**
* A DynamicPolicy implementation can use a PermissionGrant as a
container
* for Dynamic Grant's. A PermissionGrant is first asked by the Policy
* if it applies to a Particular ProtectionDomain, if it does, the
Policy
* calls getPermissions.
*
* Dynamic grants can be denied to some ProtectionDomains based on
* CodeSource or URL's for codebases, this is to remove the
possiblity of
* executing Permissions for vulnerable codebases, once a vulnerability
* is identified after the fact.
*
* @param pd ProtectionDomain
* @return
* @see RevokeableDynamicPolicy
*/
boolean implies(ProtectionDomain pd);
/**
* Checks if this PermissionGrant applies to the passed in ClassLoader
* and Principal's.
*
* Note that if this method returns false, it doesn't necessarily mean
* that the grant will not apply to the ClassLoader, since it will
depend on
* the contents of the ClassLoader and that is indeterminate. It just
* indicates that the grant definitely does apply if it returns true.
*
* If this method returns false, follow up using the
ProtectionDomain for a
* more specific test, which may return true.
*/
boolean implies(ClassLoader cl, Principal[] pal);
/**
* Checks if this PermissionGrant applies to the passed in CodeSource
* and Principal's.
* @param cs
* @return
*/
boolean implies(CodeSource codeSource, Principal[] pal);
@Override
boolean equals(Object o);
/**
* Returns an unmodifiable collection of permissions defined by this
* PermissionGrant, may be <code>null</code>.
* @return
*/
Permission[] getPermissions();
@Override
int hashCode();
/**
* Returns true if this PermissionGrant defines no Permissions, or if
* a PermissionGrant was made to a ProtectionDomain that no longer
exists.
*/
boolean isVoid();
}
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Tom Hobbs wrote:
> Hi Peter,
>
> Something that occurs to me is where does the revoke message come from and
> who gets?
>
The policy sends the message, the delegate receives it.
> Also, if I were a malicious programmer, is it possible for me to
> legitimately get the appropriate permission for something, then intercept
> and ignore any revokes that come my way?
No, it'll be passed by direct reference.
> It seems risky if the client code
> is able to do this, and the master/server/revoker code assumes that it has
> revoked permissions.
>
> It feels like there's a certain amount of trust going on in the form of "If
> I tell you not to do something, I trust you not to do it." I've got two
> young daughters; whilst okay, this approach isn't always reliable! :-)
>
There was some of that when based on threads, however by caching the
AccessControlContext's that pass, there is no risk, since references to
the objects the delegates protect will never escape, unless reflection
permission has been granted.
So if there's a loop that calls a method many times, checkPermission
will be called once initially, the AccessControlContext cached and while
the current context doesn't change and no revocation occurs, there will
be no further checkPermission calls.
The added cost will be getting the current context and checking it
exists in the cache, this is much less work than calling implies() on
every ProtectionDomain on the stack, which all eventually calls the policy.
Cheers,
Peter.
> Cheers,
>
> Tom
>
>
> On Tue, Aug 10, 2010 at 12:05 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>
>> Fred Oliver wrote:
>>
>>
>>> Peter,
>>>
>>> Thanks again.
>>>
>>>
>>>
>>>
>>>> Further, the
>>>>
>>>>> revocation events are delivered to one or more of the delegates to
>>>>> force the socket to close.
>>>>>
>>>>>
>>>>>
>>>>>
>>>> That was the original intent, however, now I'm thinking the delegate
>>>> catch
>>>> AccessControlException, thrown by a helper class, called
>>>> MethodAccessContoller, which the delegate calls prior to entering the
>>>> privileged block, performs any clean up, then re-throws the exception.
>>>> Code
>>>> that doesn't need to do any clean up, doesn't need to catch the
>>>> exception.
>>>>
>>>>
>>>>
>>> What happens to the thread stuck in the read on the socket when the
>>> permission it had to read was revoked after the read began? Force
>>> closing the socket will free up the thread. Otherwise the thread would
>>> eventually obtain data it shouldn't have from this read (or hang
>>> indefinitely waiting for data).
>>>
>>>
>>>
>> Hmm, yes, it needs to be closed from another thread.
>>
>>
>>
>>
>>>> Basically: Method call from new thread? Permission check. Permission
>>>> revoked? Permission check again. Previously checked Thread, no relevant
>>>> revocation's since (of same Class<Permission>)? Don't check again, return
>>>> quickly.
>>>>
>>>> The assumption I've made is, it will be very difficult for an attacker to
>>>> predict when a thread will access a method on the delegate, then later,
>>>> be
>>>> called by that very same thread, so his class can call the delegate
>>>> unchecked. Any thoughts on this? Am I overlooking something?
>>>>
>>>>
>>>>
>>> What happens when a delegate is passed back and forth between trusted
>>> (having permission) and untrusted (not having permission) code (on the
>>> same thread)? If you cached based on the thread, you'll get
>>> unpredictable results?
>>>
>>>
>>>
>> Yes that is a problem, so we have take a snapshot of the
>> AccessControlContext at the time of the permission check and check that it
>> is still equal() later. I guess I could drop the thread check and just
>> check the AccessControlContext, this might be useful for thread groups etc
>> ;)
>>
>> The AccessControlContext could be cached for each Thread.
>>
>> Cheers,
>>
>> Peter.
>>
>> Fred
>>
>>>
>>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Tom Hobbs <tv...@googlemail.com>.
Hi Peter,
Something that occurs to me is where does the revoke message come from and
who gets?
Also, if I were a malicious programmer, is it possible for me to
legitimately get the appropriate permission for something, then intercept
and ignore any revokes that come my way? It seems risky if the client code
is able to do this, and the master/server/revoker code assumes that it has
revoked permissions.
It feels like there's a certain amount of trust going on in the form of "If
I tell you not to do something, I trust you not to do it." I've got two
young daughters; whilst okay, this approach isn't always reliable! :-)
Cheers,
Tom
On Tue, Aug 10, 2010 at 12:05 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
> Fred Oliver wrote:
>
>> Peter,
>>
>> Thanks again.
>>
>>
>>
>>> Further, the
>>>> revocation events are delivered to one or more of the delegates to
>>>> force the socket to close.
>>>>
>>>>
>>>>
>>> That was the original intent, however, now I'm thinking the delegate
>>> catch
>>> AccessControlException, thrown by a helper class, called
>>> MethodAccessContoller, which the delegate calls prior to entering the
>>> privileged block, performs any clean up, then re-throws the exception.
>>> Code
>>> that doesn't need to do any clean up, doesn't need to catch the
>>> exception.
>>>
>>>
>>
>> What happens to the thread stuck in the read on the socket when the
>> permission it had to read was revoked after the read began? Force
>> closing the socket will free up the thread. Otherwise the thread would
>> eventually obtain data it shouldn't have from this read (or hang
>> indefinitely waiting for data).
>>
>>
>
> Hmm, yes, it needs to be closed from another thread.
>
>
>
>>
>>> Basically: Method call from new thread? Permission check. Permission
>>> revoked? Permission check again. Previously checked Thread, no relevant
>>> revocation's since (of same Class<Permission>)? Don't check again, return
>>> quickly.
>>>
>>> The assumption I've made is, it will be very difficult for an attacker to
>>> predict when a thread will access a method on the delegate, then later,
>>> be
>>> called by that very same thread, so his class can call the delegate
>>> unchecked. Any thoughts on this? Am I overlooking something?
>>>
>>>
>>
>> What happens when a delegate is passed back and forth between trusted
>> (having permission) and untrusted (not having permission) code (on the
>> same thread)? If you cached based on the thread, you'll get
>> unpredictable results?
>>
>>
>
> Yes that is a problem, so we have take a snapshot of the
> AccessControlContext at the time of the permission check and check that it
> is still equal() later. I guess I could drop the thread check and just
> check the AccessControlContext, this might be useful for thread groups etc
> ;)
>
> The AccessControlContext could be cached for each Thread.
>
> Cheers,
>
> Peter.
>
> Fred
>>
>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Peter Firmstone wrote:
> Fred Oliver wrote:
>> Peter,
>>
>> Thanks again.
>>
>>
>>>> Further, the
>>>> revocation events are delivered to one or more of the delegates to
>>>> force the socket to close.
>>>>
>>>>
>>> That was the original intent, however, now I'm thinking the delegate
>>> catch
>>> AccessControlException, thrown by a helper class, called
>>> MethodAccessContoller, which the delegate calls prior to entering the
>>> privileged block, performs any clean up, then re-throws the
>>> exception. Code
>>> that doesn't need to do any clean up, doesn't need to catch the
>>> exception.
>>>
>>
>> What happens to the thread stuck in the read on the socket when the
>> permission it had to read was revoked after the read began? Force
>> closing the socket will free up the thread. Otherwise the thread would
>> eventually obtain data it shouldn't have from this read (or hang
>> indefinitely waiting for data).
>>
>
> Hmm, yes, it needs to be closed from another thread.
>
>>
>>> Basically: Method call from new thread? Permission check. Permission
>>> revoked? Permission check again. Previously checked Thread, no
>>> relevant
>>> revocation's since (of same Class<Permission>)? Don't check again,
>>> return
>>> quickly.
>>>
>>> The assumption I've made is, it will be very difficult for an
>>> attacker to
>>> predict when a thread will access a method on the delegate, then
>>> later, be
>>> called by that very same thread, so his class can call the delegate
>>> unchecked. Any thoughts on this? Am I overlooking something?
>>>
>>
>> What happens when a delegate is passed back and forth between trusted
>> (having permission) and untrusted (not having permission) code (on the
>> same thread)? If you cached based on the thread, you'll get
>> unpredictable results?
>>
>
> Yes that is a problem, so we have take a snapshot of the
> AccessControlContext at the time of the permission check and check
> that it is still equal() later. I guess I could drop the thread check
> and just check the AccessControlContext, this might be useful for
> thread groups etc ;)
>
> The AccessControlContext could be cached for each Thread.
Yes, I think I'll keep a HashSet containing the AccessControlContext's
that have passed with checkPermission, then if the Set contains the
current AccessControlContext, we don't need to check it again. When a
revocation occurs the Set will be cleared.
I'm going to optimise the revocation strictly to only advise the
delegates based on the Permission Classes, registered by the delegate's
themselves, when they register with the policy (not individual
Permission's since they may imply each other, just the common Class
type). Since the policy notifies the delegate, it also gets to close
any sockets etc.
This should be the most optimum solution, certainly much less work than
calling checkPermission on every method invocation, but with no security
trade off's.
N.B. Your time is much appreciated, thanks for the help.
Peter.
>
> Cheers,
>
> Peter.
>
>> Fred
>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred Oliver wrote:
> Peter,
>
> Thanks again.
>
>
>>> Further, the
>>> revocation events are delivered to one or more of the delegates to
>>> force the socket to close.
>>>
>>>
>> That was the original intent, however, now I'm thinking the delegate catch
>> AccessControlException, thrown by a helper class, called
>> MethodAccessContoller, which the delegate calls prior to entering the
>> privileged block, performs any clean up, then re-throws the exception. Code
>> that doesn't need to do any clean up, doesn't need to catch the exception.
>>
>
> What happens to the thread stuck in the read on the socket when the
> permission it had to read was revoked after the read began? Force
> closing the socket will free up the thread. Otherwise the thread would
> eventually obtain data it shouldn't have from this read (or hang
> indefinitely waiting for data).
>
Hmm, yes, it needs to be closed from another thread.
>
>> Basically: Method call from new thread? Permission check. Permission
>> revoked? Permission check again. Previously checked Thread, no relevant
>> revocation's since (of same Class<Permission>)? Don't check again, return
>> quickly.
>>
>> The assumption I've made is, it will be very difficult for an attacker to
>> predict when a thread will access a method on the delegate, then later, be
>> called by that very same thread, so his class can call the delegate
>> unchecked. Any thoughts on this? Am I overlooking something?
>>
>
> What happens when a delegate is passed back and forth between trusted
> (having permission) and untrusted (not having permission) code (on the
> same thread)? If you cached based on the thread, you'll get
> unpredictable results?
>
Yes that is a problem, so we have take a snapshot of the
AccessControlContext at the time of the permission check and check that
it is still equal() later. I guess I could drop the thread check and
just check the AccessControlContext, this might be useful for thread
groups etc ;)
The AccessControlContext could be cached for each Thread.
Cheers,
Peter.
> Fred
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Fred Oliver <fk...@gmail.com>.
Peter,
Thanks again.
>> Further, the
>> revocation events are delivered to one or more of the delegates to
>> force the socket to close.
>>
>
> That was the original intent, however, now I'm thinking the delegate catch
> AccessControlException, thrown by a helper class, called
> MethodAccessContoller, which the delegate calls prior to entering the
> privileged block, performs any clean up, then re-throws the exception. Code
> that doesn't need to do any clean up, doesn't need to catch the exception.
What happens to the thread stuck in the read on the socket when the
permission it had to read was revoked after the read began? Force
closing the socket will free up the thread. Otherwise the thread would
eventually obtain data it shouldn't have from this read (or hang
indefinitely waiting for data).
> Basically: Method call from new thread? Permission check. Permission
> revoked? Permission check again. Previously checked Thread, no relevant
> revocation's since (of same Class<Permission>)? Don't check again, return
> quickly.
>
> The assumption I've made is, it will be very difficult for an attacker to
> predict when a thread will access a method on the delegate, then later, be
> called by that very same thread, so his class can call the delegate
> unchecked. Any thoughts on this? Am I overlooking something?
What happens when a delegate is passed back and forth between trusted
(having permission) and untrusted (not having permission) code (on the
same thread)? If you cached based on the thread, you'll get
unpredictable results?
Fred
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Don't worry, it's not based on Threads now, that model never did sit
well, it's now based on AccessControlContext caching. New context, must
be checked.
Patricia Shanahan wrote:
> Peter Firmstone wrote:
> ...
>> The assumption I've made is, it will be very difficult for an
>> attacker to predict when a thread will access a method on the
>> delegate, then later, be called by that very same thread, so his
>> class can call the delegate unchecked. Any thoughts on this? Am I
>> overlooking something?
> ...
>
> To win the overall game, a security system needs to block every single
> attempt at breaking the rules.
>
> An attacker only needs have some chance of single try success and a
> way of causing repeated attempts until one succeeds. Assuming
> independence, an attacker with a probability p of single try success
> gets a probability t of at least one success in log(1-t)/log(1-p) tries.
>
> For example, it takes less than 700,000 attempts to get a 50% chance
> of at least one attempt succeeding, given a one in a million chance
> for a single attempt.
>
> If you can enforce upper bounds on both the number of attempts and the
> probability of each attempt succeeding it may be possible to show that
> the overall probability of successful attack is low enough to ignore.
>
> Patricia
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Patricia Shanahan <pa...@acm.org>.
Peter Firmstone wrote:
...
> The assumption I've made is, it will be very difficult for an attacker
> to predict when a thread will access a method on the delegate, then
> later, be called by that very same thread, so his class can call the
> delegate unchecked. Any thoughts on this? Am I overlooking something?
...
To win the overall game, a security system needs to block every single
attempt at breaking the rules.
An attacker only needs have some chance of single try success and a way
of causing repeated attempts until one succeeds. Assuming independence,
an attacker with a probability p of single try success gets a
probability t of at least one success in log(1-t)/log(1-p) tries.
For example, it takes less than 700,000 attempts to get a 50% chance of
at least one attempt succeeding, given a one in a million chance for a
single attempt.
If you can enforce upper bounds on both the number of attempts and the
probability of each attempt succeeding it may be possible to show that
the overall probability of successful attack is low enough to ignore.
Patricia
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Fred Oliver wrote:
> Peter,
>
> Thanks for the long answer. I'm still missing some implementation hints.
>
> In the case I suggested, downloaded code creates a socket on a port
> using the standard Java classes, gets the socket streams and begins
> communicating with the outside world. At this point, it is too late to
> stop the code from communicating by revoking permissions.
>
Correct.
> If I understand correctly, instead, the downloaded code would not
> receive socket permissions at all (because they cannot be revoked
> after the socket is open), and would not be allowed to use the socket
> classes directly. Instead, a River factory class would be provided,
> and the downloaded code would be required to use that factory class to
> obtain a delegate for the socket. The delegate socket could then
> connect and return delegates for the streams to the downloaded code.
> In order to obtain permission for itself (to create and connect), the
> delegates would need to use doPrivileged() blocks?
Correct.
> Further, the
> revocation events are delivered to one or more of the delegates to
> force the socket to close.
>
That was the original intent, however, now I'm thinking the delegate
catch AccessControlException, thrown by a helper class, called
MethodAccessContoller, which the delegate calls prior to entering the
privileged block, performs any clean up, then re-throws the exception.
Code that doesn't need to do any clean up, doesn't need to catch the
exception.
> Have I got the picture?
>
Yes
> The scope of the proposal is then to allow permission revocation to
> apply to a limited (but extendable) set of delegate factory classes
> which downloaded code must be written to use?
>
Yes, and to a limited subset of existing Java Permissions, which will be
advised in the javadoc following auditing, although I guess there's a
small risk that a standard JVM Permission that provides adequate
protection today, may not in a future version.
Fred, you've just managed to clarify it in simple terms, having cleared
that up, hopefully people can provide their insights into the risks
associated with not calling AccessController.checkPermission on every
method invocation on the delegate.
Basically: Method call from new thread? Permission check. Permission
revoked? Permission check again. Previously checked Thread, no relevant
revocation's since (of same Class<Permission>)? Don't check again,
return quickly.
The assumption I've made is, it will be very difficult for an attacker
to predict when a thread will access a method on the delegate, then
later, be called by that very same thread, so his class can call the
delegate unchecked. Any thoughts on this? Am I overlooking something?
I'm actually wondering about in the case of the given example, whether
it is better to catch the AccessControlException, then throw an
IOException, containing the relevant information, or to re-throw the
AccessControlException.
After all it will be a client originated Thread that calls the proxy
code, which is more likely to catch an IOException than an
AccessControlException.
Thanks,
Peter.
> Fred
>
>
> On Mon, Aug 9, 2010 at 7:12 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
>
>> 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 <ji...@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.
>>>>
>>>>
>>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Gregg Wonderly <gr...@wonderly.org>.
Quite a long time ago, on the Jini lists, I presented the issue of resource
oriented authorization vs role oriented authorization. I found a reference to
some of this at:
<http://osdir.com/ml/java.sun.jini/2005-03/msg00252.html>
I tried to stress the fact that I feel that you really never want to design your
distributed application to use permission grants based on access to resources
such as socket connections, files etc. Instead, you want something at the front
line of your application APIs that represents role based access. First,
authenticate and then use the associated entity's roles to find permissions.
Authentication is not always easy, but I think that this greatly faciltates the
ability to revoke access, dynamically through API control of what roles can do,
rather than through direct permissions on resource access. Primarily this just
falls out of the fact that you are making API calls for access, and you can plug
in smart proxy returns and do other things, over time to refine the details you
need to control.
My authlib stuff that I just threw out on java.net, represents some of what I
had done to facilitate this for my applications.
Gregg Wonderly
Fred Oliver wrote:
> Peter,
>
> Thanks for the long answer. I'm still missing some implementation hints.
>
> In the case I suggested, downloaded code creates a socket on a port
> using the standard Java classes, gets the socket streams and begins
> communicating with the outside world. At this point, it is too late to
> stop the code from communicating by revoking permissions.
>
> If I understand correctly, instead, the downloaded code would not
> receive socket permissions at all (because they cannot be revoked
> after the socket is open), and would not be allowed to use the socket
> classes directly. Instead, a River factory class would be provided,
> and the downloaded code would be required to use that factory class to
> obtain a delegate for the socket. The delegate socket could then
> connect and return delegates for the streams to the downloaded code.
> In order to obtain permission for itself (to create and connect), the
> delegates would need to use doPrivileged() blocks? Further, the
> revocation events are delivered to one or more of the delegates to
> force the socket to close.
>
> Have I got the picture?
>
> The scope of the proposal is then to allow permission revocation to
> apply to a limited (but extendable) set of delegate factory classes
> which downloaded code must be written to use?
>
> Fred
>
>
> On Mon, Aug 9, 2010 at 7:12 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
>> 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 <ji...@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.
>>>>
>>>
>>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Fred Oliver <fk...@gmail.com>.
Peter,
Thanks for the long answer. I'm still missing some implementation hints.
In the case I suggested, downloaded code creates a socket on a port
using the standard Java classes, gets the socket streams and begins
communicating with the outside world. At this point, it is too late to
stop the code from communicating by revoking permissions.
If I understand correctly, instead, the downloaded code would not
receive socket permissions at all (because they cannot be revoked
after the socket is open), and would not be allowed to use the socket
classes directly. Instead, a River factory class would be provided,
and the downloaded code would be required to use that factory class to
obtain a delegate for the socket. The delegate socket could then
connect and return delegates for the streams to the downloaded code.
In order to obtain permission for itself (to create and connect), the
delegates would need to use doPrivileged() blocks? Further, the
revocation events are delivered to one or more of the delegates to
force the socket to close.
Have I got the picture?
The scope of the proposal is then to allow permission revocation to
apply to a limited (but extendable) set of delegate factory classes
which downloaded code must be written to use?
Fred
On Mon, Aug 9, 2010 at 7:12 AM, Peter Firmstone <ji...@zeus.net.au> wrote:
> 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 <ji...@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.
>>>
>>
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
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 <ji...@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.
>>
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Fred Oliver <fk...@gmail.com>.
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?
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?
-Was a delegate introduced and where?
-Can the code use reflection to bypass the delegate?
-Is reflection denied generally?
Thanks,
Fred
On Sat, Aug 7, 2010 at 2:10 AM, Peter Firmstone <ji...@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.
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Niclas Hedhman <ni...@hedhman.org>.
On Sat, Aug 7, 2010 at 2:10 PM, Peter Firmstone <ji...@zeus.net.au> wrote:
> Please help identify any fallacies or oversights in the following arguments.
I am not a security expert by any means, but in principle I know;
* Security is hard. The more complex, the more likely it is to be flawed.
* I suspect that any scheme is impossible to prove to be guaranteed
secure. Only "know to be" secured until proven wrong, in some cases
too late.
So the general advice is; Keep it simple, or it won't work, just make
it much harder for the developers.
Cheers
--
Niclas Hedhman, Software Developer
http://www.qi4j.org - New Energy for Java
I live here; http://tinyurl.com/2qq9er
I work here; http://tinyurl.com/2ymelc
I relax here; http://tinyurl.com/2cgsug
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
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.
>
>
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
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.
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Peter Firmstone <ji...@zeus.net.au>.
Tim Blackman wrote:
> On Jul 31, 2010, at 11:53 PM, Peter Firmstone wrote:
>
>
>> A Brief evolution of java.security.Policy providers and Jini Security, please correct me where necessary.
>>
>> Prior to Jini 2.0 security was left up to implementing developers, the standard tools available in Java 1.2 were insufficient. You had to implement your own SecurityManager. Or you could define Security policy's in policy files. The AccessController still consulted the ProtectionDomain, but the ProtectionDomain Permission's were static and unchanging. You could implement your own policy provider for java.security.Policy, by there was no way you could guarantee updates to the ProtectionDomain with any changes, the ProtectionDomain used the Policy.getPermissions(ProtectionDomain) call to obtain the PermissionCollection from the Policy.
>>
>> To enable the Jini 2.0 Security infrastructure, Sun made changes to Java itself, in Java 1.4 ProtectionDomain's were given a new constructor that enabled the ProtectionDomain to consult an external Policy Provider, and the java.security.Policy gained the implies(ProtectionDomain, Permission) method, allowing the ProtectionDomain to consult the Policy, Jini 2.0 took advantage of this with the DynamicPolicyProvider.
>>
>
> Yes, I remember that Bob Scheifler did manage to shoehorn some small but important changes into the JDK, presumably these ones you mention, although I don't remember exactly.
>
>
>> This Policy system is a permissive system, that is security was only ever relaxed, it cannot be tightened without restarting the JVM.
>>
>> Now we have taken a new evolutionary step, inspired by Sun's Neuromancer Research Project's additional security needs, for a distributed object registry, we now have a RevokeableDynamicPolicy interface.
>>
>
> [...]
>
>
>> A RevokeableDynamicPolicy supports the addition or removal of PermissionGrant's
>>
>
> 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.
>
Thanks Tim, I was hoping someone would bring this up, it's something
I've been trying to find a solution for.
I've demonstrated that Permission's can be revoked from the Policy, so
that AccessController.checkPermission returns an AccessControlException,
however there are caveats, with Permission's that only guard references,
as you mention, if the client keeps a reference then the guarded object
has escaped. I need to create a list of Permission's that cannot safely
be revoked. Many shouldn't be granted to dynamically downloaded code,
even if we trust it, such as RuntimePermission "getClassLoader"
In order to be able to make effective use of a revokeable policy, one
must use a wrapper object (a Security Delegate) to encapsulate an object
and place a AccessController.checkPermission call prior to effecting the
call.
However some Permission's can be revoked, take for instance a
FileInputStream, once it reaches the end of file, a new FileInputStream
must be created to re read the file. So if at the time of creation the
client was trusted to read the stream, then at a later stage it wasn't,
there is the possibility that the client has kept a copy of the data,
but if that client has a copy of the data, we need to make sure it can
no longer communicate with the outside world, so it can't be
transmitted, until trust has been re-established.
For example, you could use a SecurityDelegate, perhaps called a
CheckedOutputStream, that encapsulates an OutputStream, for networks and
files. The CheckedOutputStream can internally contain a volatile
variable which is checked every time a method on the object is called,
if false, the method executes, if true, prior to calling the method on
the encapsulated OutputStream, it calls
AccessController.checkPermission, if it passes, it set's the volatile
variable back to false. These SecurityDelegate's, would need to be
registered with the policy, perhaps indirectly via
net.jini.security.Security, every time a permission is revoked, the
SecurityDelegate's would be notified to set their internal volatile
boolean variable, check == true.
interface SecurityDelegate {
void notify();
}
public class CheckedOutputStream extends OutputStream implements
SecurityDelegate{
...
}
In this case we wouldn't directly grant a "write" to the client, since
it could easily create it's own output stream and keep the reference,
but if we have our own wrapped by a SecurityDelegate, then this is a
different story, we grant our code the FilePermission "write" some file,
and we must requre a different Permission the client have to utilise our
CheckedOutputStream.
We could use such a SecurityDelegate for the OutputStream returned by
net.jini.jeri.OutboundRequest.getRequestOutputStream, the same could be
done for an InputStream.
This has got me thinking about why Interfaces are essential for Service
API, including methods and parameters, because interfaces allow us to
implement SecurityDelegate's for our Service API. Different code can
use SecurityDelegates to allow trust, that's revokeable. Once bitten
twice shy?
We can ensure that the Service API exists in a parent ClassLoader and
the services, proxy's and client's exist in separate Child
ClassLoader's, they only use Service API to communicate. That way
proper separation is maintained.
I've been thinking about using Entry's for declaring the Permission's a
Service requires, to enable the client to decide if the Permission's are
acceptable to grant, and if so, restrict the permission's to only those
declared (or a subset), after trust has been established.
> By the way, when working on Neuromancer, the team working on that project decided that assigning permissions to classloaders and principals was too hard. We didn't make much progress on security concerns actually, but our idea was that we would treat the entire virtual machine as a single capability zone -- no different permissions for different code, threads, principals, etc., within a single Java VM. Our hope was to keep things simple, an idea whose rightness seemed to be borne out by the complexity of developing Jini 2.0 and the difficulties that the Jini team had in plugging security holes in the model immediately afterwards (an effort I heard about but did not participate in).
>
> - Tim
>
Security isn't easy is it? I'd be interested to hear about the
Neuromancer security model, I wasn't aware of it. I've been thinking
about a code commons where developers can share their code, and sign
each other's jar files after review. Much software downloaded today
only uses sha checksum's to ensure it is safe.
Cheers,
Peter.
Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Posted by Tim Blackman <ti...@gmail.com>.
On Jul 31, 2010, at 11:53 PM, Peter Firmstone wrote:
> A Brief evolution of java.security.Policy providers and Jini Security, please correct me where necessary.
>
> Prior to Jini 2.0 security was left up to implementing developers, the standard tools available in Java 1.2 were insufficient. You had to implement your own SecurityManager. Or you could define Security policy's in policy files. The AccessController still consulted the ProtectionDomain, but the ProtectionDomain Permission's were static and unchanging. You could implement your own policy provider for java.security.Policy, by there was no way you could guarantee updates to the ProtectionDomain with any changes, the ProtectionDomain used the Policy.getPermissions(ProtectionDomain) call to obtain the PermissionCollection from the Policy.
>
> To enable the Jini 2.0 Security infrastructure, Sun made changes to Java itself, in Java 1.4 ProtectionDomain's were given a new constructor that enabled the ProtectionDomain to consult an external Policy Provider, and the java.security.Policy gained the implies(ProtectionDomain, Permission) method, allowing the ProtectionDomain to consult the Policy, Jini 2.0 took advantage of this with the DynamicPolicyProvider.
Yes, I remember that Bob Scheifler did manage to shoehorn some small but important changes into the JDK, presumably these ones you mention, although I don't remember exactly.
> This Policy system is a permissive system, that is security was only ever relaxed, it cannot be tightened without restarting the JVM.
>
> Now we have taken a new evolutionary step, inspired by Sun's Neuromancer Research Project's additional security needs, for a distributed object registry, we now have a RevokeableDynamicPolicy interface.
[...]
> A RevokeableDynamicPolicy supports the addition or removal of PermissionGrant's
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.
By the way, when working on Neuromancer, the team working on that project decided that assigning permissions to classloaders and principals was too hard. We didn't make much progress on security concerns actually, but our idea was that we would treat the entire virtual machine as a single capability zone -- no different permissions for different code, threads, principals, etc., within a single Java VM. Our hope was to keep things simple, an idea whose rightness seemed to be borne out by the complexity of developing Jini 2.0 and the difficulties that the Jini team had in plugging security holes in the model immediately afterwards (an effort I heard about but did not participate in).
- Tim