pfirmstone / jdk-with-authorization

JDK main-line development
https://openjdk.java.net/projects/jdk/
GNU General Public License v2.0
6 stars 1 forks source link

Remove static permission assignment in platform code. #21

Open pfirmstone opened 1 day ago

pfirmstone commented 1 day ago

There are multiple places in Java where Permission's are added to a ProtectionDomain during creation, these are called static permissions and only some are controlled by policy files.

Prior to Java 1.4, all permissions were static, some originated in policy files and some were assigned by the running JVM, once a ProtectionDomain was constructed, its static permissions were frozen and couldn't be changed. I'm not sure if it's still the case, but static permissions were sourced from Policy::getPermissions(CodeSource c). Since performance of static permissions could only be described as horrible, in JGDMS, ConcurrentPolicyFile only provided static permissions when a CodeSource has AllPermission, the result from Policy::getPermissions(ProtectionDomain pd) contained permissions determined by policy files.

For performance reasons, all decisions are now directed to Policy, however the static permissions are merged by the policy and as they are already granted by code, cannot be removed by an administrator auditing a policy, nor will the administrator see these permissions in the policy file audit, resulting in an incomplete audit.

One example of this is URLClassLoader, if the caller has the RuntimePermission "createClassLoader", then it's assumed the caller has done due diligence checking input data and all permissions necessary to connect to the URL, download and load it are granted, but as JNDI has shown, input data wasn't properly scrutinised. I think this shows an over-reliance on "trusted platform code" and developers not writing code with mistakes.

Allowing static permissions to be assigned to CodeSource, also denies the possibility of assigned them to the intersection of authenticated Subject Principal's and CodeSource (URL's and Signer certificates), meaning that Permissions are only attainable when the user has been authenticated for some operations.

With JNDI, I was considering adding URLPermission, but it doesn't feel right, as it's complex to reason about and it may give the auditor a false sense of security, leaving in place the possibility of other code not performing due diligence, for example in transitive dependencies.

I think it would be simpler if we just remove static permission assignment altogether, this would expose the permission checks normally granted by URLClassLoader to policy scrutiny, handing over more control to administrators and security auditors. Allowing policy to control URLPermission grants for JNDI or similar, eliminates any connections that aren't explicitly granted. This would also likely improve performance as ConcurrentPolicyFile is non blocking, except for the permission implementation code, but as these are typically exact matches for those loaded by policy files, so their Permission::implies method may never even be called. ConcurrentPolicyFile uses a PermissionComparator, that arranges code for peak performance and identifies equality without calling Object::equals.

This has the added benefit of reducing merge conflicts with OpenJDK master.

pfirmstone commented 1 day ago

We can integrate: 8343150: Change URLClassLoader.getPermissions to return empty PermissionCollection #22179

pfirmstone commented 1 day ago

Classes that override SecureClassLoader::getPermissions

jdk.internal.loader.ClassLoaders.AppClassLoader jdk.internal.loader.BuiltinClassLoader jkd.internal.loader.Loader sun.reflect.mis.MethodUtil java.net.URLClassLoader

Note that MethodUtil grants AllPermission.

Removing these will likely cause a lot of test failures, however I can test the JDK build using JGDMS test suite as a starting point.