river-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Peter Firmstone <j...@zeus.net.au>
Subject Re: Learnings from a RevokeableDynamicPolicy & A Future Roadmap
Date Thu, 05 Aug 2010 10:19:35 GMT
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.

Mime
View raw message