Specifically for SocketPermission, I experienced severe timeout problems with 
reverse DNS misconfigurations. For some LAN-based deployments, I relaxed this 
criterion via 'new SocketPermission("*", "accept,listen,connect,resolve")'. 
This was difficult to apply to a general Sun/Oracle JVM, however, because the 
default security policy *prepends* a ("localhost:1024-","listen") permission 
that triggers the reverse DNS lookup. To avoid this inconvenient setting, I 
install a new java.security.Policy subclass that delegates to the default 
Policy except when the incoming permission is a SocketPermission. That way I 
don't need to modify the policy file in the JVM. The Policy.implies() override 
method is trivial because it just needs to do " if (permission instanceof 
SocketPermission) { ... }". The PermissionCollection methods were trickier to 
override (skip over any SocketPermission elements in the default Policy's 
PermissionCollection), but still only about 50 LOC.

Chris

-----Original Message-----
From: Peter Firmstone [mailto:j...@zeus.net.au] 
Sent: Friday, December 09, 2011 9:28 PM
To: dev@river.apache.org
Subject: Implications for Security Checks - SocketPermission, URL and DNS 
lookups

DNS lookups and reverse lookups caused by URL and SocketPermission, 
equals, hashCode and implies methods create some serious performance 
problems for distributed programs.

The concurrent policy implementation I've been working on reduces lock 
contention between threads performing security checks.

When the SecurityManager is used to check a guard, it calls the 
AccessController, which retrieves the AccessControlContext from the call 
stack, this contains all the ProtectionDomain's on the call stack (I 
won't go into privileged calls here), if a ProtectionDomain is dynamic 
it will consult the Policy, prior to checking the static permissions it 
contains.

The problem with the old policy implementation is lock contention caused 
by multiple threads all using multiple ProtectionDomains, when the time 
taken to perform a check is considerable, especially where identical 
security checks might be performed by multiple threads executing the 
same code.

Although concurrent policy reduces contention between ProtectionDomain's 
calls to Policy.implies, there remain some fundamental problems with the 
implementations of SocketPermission and URL, that cause unnecessary DNS 
lookups during equals(), hashCode() and implies() methods.

The following bugs concern SocketPermission (please read before 
continuing) :

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6592285
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4975882 - contains a 
lot of valuable comments.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4671007 - fixed, 
perhaps incorrectly.
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6501746

Anyway to cut a long story short, DNS lookups and DNS reverse lookups 
are performed for the equals and hashCode implementations in 
SocketPermission and URL, with disastrous performance implications for 
policy implementations using collections and caching security permission 
check results. 

For example, once a SocketPermission guard has been checked for a 
specific AccessContolContext the result is cached by my SecurityManager, 
avoiding repeat security checks, however if that cache contains 
SocketPermission, DNS lookups will be required, the cache will perform 
slower than some other directly performed security checks!  The cache is 
intended to return quickly to avoid reconsulting every ProtectionDomain 
on the stack.

To make matters worse, when checking a SocketPermission guard, the DNS 
may be consulted for every non wild card SocketPermission contained 
within a SocketPermissionCollection, up until it is implied.  DNS checks 
are being made unnecessarily, since the wild card that matches may not 
require a DNS lookup at all, but because the non matching 
SocketPermission's are being checked first, the DNS lookups and reverse 
lookups are still performed.  This could be fixed completely, by moving 
the responsibility of DNS lookups from SocketPermission to 
SocketPermissionCollection.

The identity of two SocketPermission's are equal if they resolve to the 
same IP address, but their hashCode's are different! See bug 6592623.

The identity of a SocketPermission with an IP address and a DNS name, 
resolving to identical IP address should not (in my opinion) be equal, 
but is!  One SocketPermission should only imply the other while DNS 
resolves to the same IP address, otherwise the equality of the two 
SocketPermission's will change if the IP address is assigned to a 
different domain!  Object equality / identity shouldn't depend on the 
result of a possibly unreliable network source.

SocketPermission and SocketPermissionCollection are broken, the only 
solution I can think of is to re-implement these classes (from Harmony) 
in the policy and SecurityManager, substituting the existing jvm 
classes.  This would not be visible to client developers.

SocketPermission's may also exist in a ProtectionDomain's static 
Permissions, these would have to be converted by the policy when merging 
the permissions from the ProtectionDomain with those from the policy.  
Since ProtectionDomain, attempts to check it's own internal permissions, 
after the policy permission check fails, DNS checks are currently 
performed by duplicate SocketPermission's residing in the 
ProectionDomain, this will no longer occur, since the permission being 
checked will be converted to say for argument sake 
org.apache.river.security.SocketPermission.  However because some 
ProtectionDomains are static, they never consult the policy, so the 
Permission's contained in each ProtectionDomain will require conversion 
also, to do so will require extending and implementing a 
ProtectionDomain that encapsulates existing ProtectionDomain's in the 
AccessControlContext, by utilising a DomainCombiner.

For CodeSource grant's, the policy file based grant's are defined by 
URL's, however URL's identity depend upon DNS record results, similar to 
SocketPermission equals and hashCode implementations which we have no 
control over.

I'm thinking about implementing URI based grant's instead, to avoid DNS 
lookups, then allowing a policy compatibility mode to be enabled (with 
logging) for falling back to CodeSource grant's when a URL cannot be 
converted to a URI, this is a much simpler fix than the SocketPermission 
problem.

For Dynamic Policy Grants, because ProtectionDomain doesn't override 
equals (that's a good thing), the contained CodeSource must also be 
checked, again potentially slowing down permission checks with DNS 
lookups, simply because CodeSource uses URL's.  Changing the Dynamic 
Grant's to use URI based comparison would be relatively simple, since 
the URI is obtained dynamically when the dynamic grant is created.

URI based grant's don't use DNS resolution and would have a narrower 
scope of implied CodeSources, an IP based grant won't imply a DNS domain 
URL based CodeSource and vice versa.  Rather than rely on DNS 
resolution, grant's could be made specifically for IPv4, IPv6 and DNS 
names in policy files.  URL.toURI() can be utilised to check if URI 
grant's imply a CodeSource without resorting to DNS.

Any thoughts, comments or ideas?

N.B. It's sad that security is implemented the way it is, it would be 
far better if it was Executor based, since every protection domain could 
be checked in parallel, rather than in sequence.

Regards,

Peter.


Reply via email to