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.

Reply via email to