How to remove the SecurityManager

forax at univ-mlv.fr forax at univ-mlv.fr
Wed Jul 28 09:41:08 UTC 2021


> From: "Peter Firmstone" <peter.firmstone at zeus.net.au>
> To: "Remi Forax" <forax at univ-mlv.fr>, "Alan Bateman" <Alan.Bateman at oracle.com>
> Cc: "jdk-dev" <jdk-dev at openjdk.java.net>, "security-dev"
> <security-dev at openjdk.java.net>
> Sent: Wednesday, July 28, 2021 1:12:32 AM
> Subject: Re: How to remove the SecurityManager

> Thanks Remi,

> Sand-boxing is a bad idea, we are in agreement, it's not something we do,
> personally I'm taking an interest in safer languages, eg Haskell on secure
> platforms, eg OpenBSD on Sparc64 *.

> Perhaps JEP 411 is simply a reflection on the evolution of languages. Java was
> safer than C and C++ so replaced these, something safer again will replace
> Java.
All mainstream languages have a way to access to raw pointers to be able to call C functions, 
here is the one in Haskell 
https://hackage.haskell.org/package/base-4.5.0.0/docs/Foreign-Storable.html 

> I think people are getting our primary use case, authorization, confused with
> sandboxing (not on our use case list). OpenJDK developers provided a Sandbox
> example, I just wanted to communicate that I didn't think it was a practical
> defense against exploits, nor applicable to our use case:

> [ https://inside.java/2021/04/23/security-and-sandboxing-post-securitymanager/ |
> https://inside.java/2021/04/23/security-and-sandboxing-post-securitymanager/ ]

> Our process for establishing whether third party libraries are trusted before we
> use them:

>    1. Build dependency check using Owasp [
>    https://owasp.org/www-project-dependency-check/ |
>    https://owasp.org/www-project-dependency-check/ ] Reject any dependencies that
>    fail, see [ https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/pom.xml |
>    https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/pom.xml ] line 87 for an
>    example of a disabled module due to a vulnerability in a dependency, the module
>     will only be re-enabled if the vulnerability is fixed.
>    2. Static analysis using SpotBugs, then review identified bugs, review source
>     code if available. Reject if security bugs are present, or fix / patch.
>    3. Profiling of permission access checks using: [
>    https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/tools/security-policy-debug/src/main/java/org/apache/river/tool/SecurityPolicyWriter.java
>    |
>    https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/tools/security-policy-debug/src/main/java/org/apache/river/tool/SecurityPolicyWriter.java
>     ]
>    4. Reviewing generated policy files, using grep, this example was generated from
>    over 2000 tests: [
>    https://github.com/pfirmstone/JGDMS/blob/trunk/qa/harness/policy/defaultsecuresharedvm.policy.new
>    |
>    https://github.com/pfirmstone/JGDMS/blob/trunk/qa/harness/policy/defaultsecuresharedvm.policy.new
>     ]
>    5. Remove any permission from the policy file you don't want to grant to third
>     party code, if safe to do so, eg usage statistics reporting.

> One of my use cases for SM is for auditing to establish trust, and then using SM
> with POLP policy files generated following the audit, to turn off JVM features
> we're not using. Our policy provider is performant and high scaling even with
> policy files containing 1000's of lines: [
> https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/jgdms-platform/src/main/java/org/apache/river/api/security/ConcurrentPolicyFile.java
> |
> https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/jgdms-platform/src/main/java/org/apache/river/api/security/ConcurrentPolicyFile.java
> ]

> Our use of SM for access decisions occurs during and after authentication, but
> also defines access roles for trusted parties, it's not possible to replace SM
> authorization layer functionality (not to be confused with sandboxes). Our use
> case is distributed systems, with trusted services and trusted clients, which
> have POJO proxy's, different service proxies are given different
> ProtectionDomain identity and these identities are used for authorization
> decisions.

> In a simple Client - Server application, you only have one user, from the client
> and the thread runs with this permission, but our systems might be performing a
> transaction, with 5 different services, and the transaction service is the
> client of these 5 services, which are represented by their proxy
> ProtectionDomain's. If one of the authenticated services is not authorized to
> participate in the transaction (eg a third party that's not on the contract, or
> maybe the contract expired), then it's not authorized and the transaction will
> fail. This all occurs over secure authenticated connections, where both servers
> and clients are authenticated, who's the server and who's the client, well that
> gets a little blurred sometimes.

> [
> https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/jgdms-platform/src/main/java/net/jini/core/transaction/Transaction.java
> |
> https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/jgdms-platform/src/main/java/net/jini/core/transaction/Transaction.java
> ]

> Back in the Jini days, Sun Microsystems, allowed different service proxy's to be
> loaded by the same ClassLoader, if they had the same CodeSource, they had the
> same identity if they had the same parent ClassLoader, we don't do that,
> ClassLoader's are assigned to a service proxy, based on it's authenticated
> identity.

> [
> https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/jgdms-pref-class-loader/src/main/java/net/jini/loader/pref/PreferredProxyCodebaseProvider.java
> |
> https://github.com/pfirmstone/JGDMS/blob/trunk/JGDMS/jgdms-pref-class-loader/src/main/java/net/jini/loader/pref/PreferredProxyCodebaseProvider.java
> ]

> This system, at its foundations is based on Jini Extensible Remote Invocation
> (JERI), we've replaced the serialization layer, to use what we term atomic
> serialization and apply constraints during connection establishment over secure
> connections. [
> https://github.com/pfirmstone/JGDMS/tree/trunk/JGDMS/jgdms-platform/src/main/java/net/jini/core/constraint
> |
> https://github.com/pfirmstone/JGDMS/tree/trunk/JGDMS/jgdms-platform/src/main/java/net/jini/core/constraint
> ]

> We limit access based on both the service and user identity. We generate our
> policy files by profiling (the tool creates a policy file with correct syntax,
> ready for immediate use), we recently added replacement of local file paths
> with properties for policy property expansion with cross platform
> trans-portability. While its possible to use a dynamic proxy without
> downloading code, via an atomic serialization connection, it's not generally
> advised to do so with unauthenticated users, decisions around dynamic
> discovery, whether class loading or downloads are allowed, it's all based on
> policy decisions.

> The problem with our software is its designed to operate on un-trusted networks,
> and SM infrastructure is involved in authorization decisions during the
> authentication process, as well as providing user credentials for secure
> connections.

> We have no future Java migration path after JEP 411, the decision's been made,
> time to move on...

> On the bright side, according the JEP 411, we did achieve what OpenJDK dev's
> thought to be almost impossible. :) I'm pretty sure using the process I've
> documented above, you will identify 99% of accidental vulnerabilities in local
> code, and that was good enough for me lol.

>> The threat of accidental vulnerabilities in local code is almost impossible to
>> address with the Security Manager.
In your validation process, you have a static part to check the dependencies + SpotBug and a runtime part using a combination of class loader + security manager. 
For the runtime part, instead of using classloaders, you can use an agent, it will also see all the requests to load a class, it can then do a static analysis of the bytecode to determine if the bytecode only contains kosher method calls and field access, the same way SpotBug does. 
If you really want to have a mechanism that authorize some method calls or not at runtime, you can change the bytecode to introduce a method call that checks the security policy just before the authorizable method call/field access 
(you also have to blacklist java.lang.reflect and java.lang.invoke but i supppose you already do this). 

This approach is better than using a classloader + security manager because 
- Java allows you to define classes not linked to a classloader since Java 8 (the old API is Unsafe.defineAnonymousClass(), the new one is Lookup.defineHiddenClass()) 
- you can check any calls not only the ones that the SecurityManager traps. 
- you can reject calls before loading the class, so earlier than with a SecurityManager, more like the bytecode verifier does. 
- it's more lightweight in term of memory usage because it does not rely on ClassLoaders (each ClassLoader has its own metaspace, so a lot of CL fragment the memory a lot). 

To read and transform the bytecode, you can ASM [1], this is one of the library used by SpotBug to read/check the bytecode. 
(disclaimer: i'm one of the maintainer of that library). 

It's still not 100% perfect because the agent runs in the same process as the code. 
(you can go deeper by having the authorization framework in a VM puppeteering a client VM likes jshell does using JVMTI). 

> * OpenBSD on Sparc (very well supported, Oracle should sell these lol, the only
> drawback is no zfs) is a good idea, no Spectre or Meltdown vulnerabilities.

> buffy$ uname -a
> OpenBSD buffy.lan 6.7 GENERIC.MP#310 sparc64

> Although this one's a couple of versions behind, time for an upgrade.

> Regards,

> Peter.
regards, 
Rémi 

[1] https://asm.ow2.io/ 

> On 28/07/2021 5:52 am, [ mailto:forax at univ-mlv.fr | forax at univ-mlv.fr ] wrote:

>> ----- Original Message -----

>>> From: "Alan Bateman" [ mailto:Alan.Bateman at oracle.com |
>>> <Alan.Bateman at oracle.com> ] To: "Remi Forax" [ mailto:forax at univ-mlv.fr |
>>> <forax at univ-mlv.fr> ] , "Peter Firmstone" [ mailto:peter.firmstone at zeus.net.au
>>> | <peter.firmstone at zeus.net.au> ] Sent: Tuesday, July 27, 2021 6:33:25 PM
>>> Subject: Re: How to remove the SecurityManager

>>> On 27/07/2021 17:11, Remi Forax wrote:

>>>> Peter, this is how you remove the security manager using the jdk 17 (the
>>>> SystemMirror class is specific to a JDK version).

>>>> Any in-process security measures fail if the API let you to peek and poke the
>>>> memory like Unsafe does.

>>> I hope you aren't really suggesting anyone does this :-)

>> nope, it's a small example to explain why in-process sandboxing is a bad idea.

>>> It's dependent
>>> on the field layout so can break and crash the VM if it doesn't match.
>>> Also it assumes that someone gets theUnsafe before a SM is set.

>> yes, it's just an example, you have infinite variations using JNI/JNA/JNR or
>> panama and changing some field value.

>>> -Alan

>> Rémi
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/security-dev/attachments/20210728/1572f3ed/attachment.htm>


More information about the security-dev mailing list