Hi David,

Thanks for the feedback and spending some time on this proposal. Some specific comments below.

On 4/5/22 9:52 AM, David Lloyd wrote:
Here at Red Hat there have been serious discussions about the impacts
of security manager removal on our users, and whether there is an
actual value impact, and if so, whether it can be mitigated or
reversed somehow. We are interested in exploring whether we can come
up with a way in which vendors and projects that wish to continue
using SecurityManager (or something like it) would be able to do so,
while still removing the majority of the ongoing maintenance burden
from the OpenJDK project.

Before we make a decision on whether or not we think there is
sufficient justification for working up a formal JEP, we have decided
that the best first step would be to socialize the idea in a more
general form so that we can know whether the upstream OpenJDK team
would even be amenable *at all* to the solution (or something like
it), particularly in light of the observation that previous threads
about retaining SecurityManager in any form have been looked upon in a
fairly negative light.

The primary idea behind this proposal is that, while all of the points
in JEP 411 relating to the lack of what most experts might refer to as
"actual security" are certainly true, the SecurityManager mechanism
itself does nevertheless have some inherent value. The challenge,
then, is to strike a balance between the value provided by retaining
some semblance of the mechanism versus the costs inherent in retaining
it; we would want as much of the former as possible, for as little of
the latter as possible.

With this proposal, as I understand it, the JDK would still be responsible for maintaining and preserving essentially all of the existing calls to the Security Manager (SM). All new code and APIs would still need to be evaluated and determined if permission checks were needed as well as making appropriate specification changes to note the behavior when an SM is enabled (throwing a SecurityException, etc). Any missing checks would need to be treated as security issues. And we would still need to test the code and APIs to ensure that it worked properly and complied with the API specification. This would likely mean implementing and maintaining an internal SM implementation in OpenJDK.

The proposal also includes retaining calls to doPrivileged (but later potentially replacing them with some other mechanism TBD). The JDK source code includes over 1000 calls to doPrivileged. Each of these need to be carefully reviewed to ensure that they do not contain security issues and any new code needs to be evaluated to see if new calls to doPrivileged are necessary.

Retaining doPrivileged (or something similar) means that there can be domains of code with different permissions running within the VM, which retains much of the complexity of the current SM model.

In this proposal, how privileges are established or propagated is implementation-specific. But how could applications or libraries depend on the APIs and still have some confidence that the code is behaving consistently and securely?

Today, the cost of buying into the SM model is high for libraries and applications. Not many third party libraries support the SM and have modified their code to perform permission checks and call doPrivileged in the right places. If there were pluggable SMs each behaving differently, there would likely be less incentive.

Although it sounds beneficial to be able to delegate the SM implementation to a 3rd-party, in reality, I think very few people would
take the time to implement it securely, and instead would mostly
leverage its power to do things that aren't at all security related. Sure, removing the default SM and Policy implementation reduces the complexity a little, but there would still be a fairly significant maintenance overhead and an additional drawback that it would make it more difficult for applications and libraries to depend on any type of consistent behavior.

--Sean


So, here's the idea. It is assumed (for the sake of common
understanding) that as things stand, all of the classes and members
marked as "deprecated for removal" as a part of JEP 411 are intended
to be completely removed without replacement at the end of the term of
deprecation.  The proposals here are based on this assumption.

The center of this proposal is that, at the end of the term of
deprecation, all of the deprecated classes, members, and behavior are
still removed (including, and especially, AccessController and Policy
and related classes) /except/ as mentioned here:

  * Rather than completely removing SecurityManager,
      * The SecurityManager class becomes abstract and non-deprecated,
with all of its methods being removed, except as follows
      * SecurityManager.getSecurityContext() becomes abstract (this is
the one that returns Object, *not* the stack walking one)
      * SecurityManager.checkPermission() (both of them) become abstract
  * Rather than removing the SecurityManager-related methods from System,
      * System.getSecurityManager() is retained and de-deprecated
      * [Optional] System.setSecurityManager() is retained and
de-deprecated (we would want to explore whether it is feasible to
replace this (and the system property lookup mechanism) using
ServiceLoader, if bootstrap allows it)
  * [Optional] Rather than /immediately/ removing all of AccessController,
      * Retain its deprecation-for-removal status
      * Retain only doPrivileged(PrivilegedAction) and
doPrivileged(PrivilegedExceptionAction) as simple pass-throughs (no
JVM semantics other than being present on the call stack like any
method) since they are pervasively used, to allow frameworks time to
transition to (for example) a third-party alternative.

The burden of permission verification would lie completely with the
security manager implementation.  The JDK would not have a
'SecurityManager' implementation of any kind, outside of the internal
test suite.

The other part of this proposal can come in one of two possible flavors.

### Option 1: Authorization interfaces

Each point in the JDK where there presently is a permission check is
classified into an authorization category of related operations. An
interface is introduced for each category which contains the methods
encapsulating the relevant check, in a package that is deemed most
appropriate for that particular grouping.  For example, there might be
a 'SocketAuthorization' interface in the 'java.net' package, with
methods like 'checkConnect(SocketAddress from, SocketAddress to)' and
'checkAccept(SocketAddress addr)'.

At the point where a permission check previously would take place, a
check like this is performed instead:

     if (System.getSecurityManager() instanceof SocketAuthorization sa) {
         sa.checkAccept(addr);
     }

Any public or protected method with such a check should include
@throws Javadoc explaining that a SecurityException may be thrown.

The Permission subclasses previously used specifically by these
operation sites *may* in this case be deprecated for removal
immediately or at some point in the future, if desired.

It is the sole responsibility of the SecurityManager implementer to
implement the various necessary interfaces, and any third-party
authorization interfaces that would also be relevant.

### Option 2: Retain permission system

Under this option, the existing authorization checks are mostly
retained, however, since the SecurityManager class only has a general
'checkPermission()' method, the logic previously found in the
'SecurityManager' class which expands specific check calls into
general 'checkPermission()' calls (for example, calls to
'checkConnect' for sockets) would necessarily become the
responsibility of the site of the permission check.  Some work would
be undertaken
to refactor this code accordingly.

With this solution, the corresponding Permission subclasses would be
retained indefinitely.

In either case it is the responsibility of the implementer of
SecurityManager to utilize these checks appropriately for
authorization decisions, based on whatever factors are deemed
appropriate, which may include contextual information such as a
currently-authenticated identity or the call stack, or (for example) a
context object utilizing the ScopeLocal mechanism.

### Other changes

It would be worth exploring whether the SecurityManager installation
could be refitted to use the ServiceLoader mechanism (for example at
first call to getSecurityManager()) based on the class loader of the
application class or module path.  This would allow the
'System.setSecurityManager' method, and support for the corresponding
system property, to be removed at the end of the term of deprecation.

Testing

Neither solution would ease the burden of testing from the JDK quite
as much as complete removal, of course. The necessary testing for the
individual checks should be limited to ensuring that the permission
check calls are happening with correct arguments and that any thrown
SecurityException is propagated.  The policy for testing
SecurityManager installation would depend on whether, and to what
extent, the more recent changes restricting the installation of the
security manager are reversed.  Other testing issues may arise as
well.

Reply via email to