A possible JEP to replace SecurityManager after JEP 411

Peter Firmstone peter.firmstone at zeus.net.au
Thu Apr 28 05:25:05 UTC 2022


Hi Martin,

Your arguments are the reasons why we use the principle of least 
privilege.   It creates a headache for attackers, similar to the 
developer who's enabled SM for the first time and must manually add 
every required permission for their software to function (who thought 
that was a good idea lol?).   The attacker requires an intimate 
knowledge of the permissions their attack vectors or gadgets require, 
including those a thread of execution has already been granted as well 
as the features that those permissions will grant the attacker access 
to.   If the thread of execution doesn't have all required permissions, 
it will cause the jvm to exit with a SecurityException.   How does the 
attacker obtain all the required information?  With great difficulty.

As soon as the software does something a generated polp policy file 
hasn't captured, a security exception is almost inevitably thrown, even 
if it wasn't designed to protect an intended target, it almost 
inevitably gets in the way.  You will find that it's almost impossible 
to do anything unintended.  Although once you can impersonate a user or 
service, say with the recent ECC exploit, you can at least do what that 
user or service is allowed to do, but it still won't allow the attacker 
to achieve their intended end goal unless the user or has all the 
required permissions.  In our case if the attacker can impersonate a 
service, then they can load code, that's a problem, as our software 
assumes ECDSA provides strong confidentiality.  We recognise that once 
you get to the stage of loading code into the jvm, it's pretty much game 
over.   A polp policy file won't defend against the recent ECC exploit.

https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/jgdms-jeri/src/main/java/net/jini/jeri/ssl/ConfidentialityStrength.java

What polp can protect against however, is an exploit in a feature that 
you don't use, it protected against the recent Log4J vulnerability.

An example of a polp policy file: 
https://github.com/pfirmstone/JGDMS/blob/trunk/qa/harness/policy/defaultsecuresharedvm.policy

One of the improvements we can make (when re-implementing access 
controls), is to reduce the size of the jdk's trusted computing base, 
instead of having many trusted protection domains with all permission 
(characterised with a null protection domain), we can give each module a 
separate protection domain identity, and limit each only to the 
permissions required for our software to function as intended.   This 
means that jvm modules we don't use will have no permissions at all.  To 
get around the large trusted jdk code base, we provided two methods 
which append a ProtectionDomain, with only the user's required 
permissions, it also prevents injection of a user Subject's permission's 
into less privileged service domains.  It's use hasn't really caught on 
though, no doubt due to complexity.

https://github.com/pfirmstone/JGDMS/blob/c1edf5892306f24f8f97f459f499dec54984b08f/JGDMS/jgdms-platform/src/main/java/net/jini/security/Security.java#L590

This is really a hack because the jdk's trusted computing base is too 
large, also user permissions should be granted only to protection 
domains that have the necessary user principals and code signers, to 
avoid injecting additional permissions into less privileged service 
protection domains.

All data parsing the jvm performs, should also be moved into separate 
modules, so that data parsing access controls and privileges could have 
been managed (this is one of the missing checks you mention), and yes it 
did provide a false sense of security for many years that Java 
serialization was secure when it wasn't.  I had many difficulties 
explaining to developers in 2010 that Java serialization wasn't secure, 
they didn't believe me and it cause problems.

Had the Java 2SE security infrastructure never been introduced, perhaps 
something else would have evolved, or at the very least, our software 
wouldn't depend on it.  Java's access controls have certainly suffered 
from a lack of investment.

Unfortunately our software is dependent on it and designed around it at 
a fundamental level, even if SM is null (which incidentally I've haven't 
yet tested, I think we have code that checks that SM is enabled), our 
software is still using AccessControlContext's to establish TLS 
connections and authenticate users.   Personally I would like to see 
parts of AccessController and AccessControlContext retained for 
retrieving the Subject for establishing secure connections in a way 
that's compatible across all Java versions.

After removing access controls, it effectively means AllPermission is 
granted to every authenticated user (and in our case service).   Any 
access controls that we create at a higher level, can be circumvented by 
the lack of lower level access controls.   So the only access control is 
authentication.

We have no desire or want to instrument the jvm, we have been advised 
that this is the new way to implement access controls by OpenJDK, it's 
simply that we want to continue to support future versions of Java and 
cannot do so without access controls.  Our software has been designed 
with and depends on access controls.

Java has had access controls for 24 years, we couldn't foresee that it 
would be removed in a breaking manner in such a short time frame.  
Remember how long Thread.stop and similar bad api's remained in 
deprecated form?

https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8204243

This isn't something we wanted or planned to do, it's a task that has 
been created for us and we have few resources to address it.

Regards,

Peter.

On 28/04/2022 3:37 am, Martin Balao wrote:
> David,
>
> I understand the reasons behind seeing authorization checks at the 
> runtime layer as something that just adds, without any harm in the 
> worst case (all of this putting the maintenance cost and other 
> arguments aside.)
>
> My concern is more about the general security principles underpinning 
> the idea. We will probably agree that half-barriers are not barriers, 
> and might cause a false sense of security. If we have authorization 
> checks at the runtime level, they must be comprehensive, coherent and 
> well-maintained. Their availability suggests that mixing high-level 
> checks with runtime-level ones can be part of a good security design 
> in modern application development. For the reasons that we've been 
> discussing, I'm not convinced of that. And even when subtle, I prefer 
> the runtime not to make the suggestion. If you still want it, you can 
> go ahead with instrumentation; but it's clear that for the runtime 
> developers that is a workaround and not a desirable security design.
>
> What I mean by splitting responsibility is that application 
> developers can use a mix of high and low level checks, at different 
> layers, with more complexity. As Sean said, letting the unauthorized 
> user to move towards the edge of the action is more risky. We can lose 
> sight of workarounds and holes with the additional attack surface and 
> complexity that comes at a lower layer. What I want to stress is the 
> value of clarity, simplicity and division of responsibilities as a 
> general security principle.
>
> Martin.-
>



More information about the security-dev mailing list