------------------------------------------------------------------------
*From: *"Peter Firmstone" <peter.firmst...@zeus.net.au>
*To: *"Remi Forax" <fo...@univ-mlv.fr>, "Alan Bateman"
<alan.bate...@oracle.com>
*Cc: *"jdk-dev" <jdk-...@openjdk.java.net>, "security-dev"
<security-dev@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, fo...@univ-mlv.fr
<mailto:fo...@univ-mlv.fr> wrote:
----- Original Message -----
From: "Alan Bateman"<alan.bate...@oracle.com>
<mailto:alan.bate...@oracle.com>
To: "Remi Forax"<fo...@univ-mlv.fr> <mailto:fo...@univ-mlv.fr>, "Peter
Firmstone"<peter.firmst...@zeus.net.au> <mailto:peter.firmst...@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