How to remove the SecurityManager
Peter Firmstone
peter.firmstone at zeus.net.au
Wed Jul 28 12:10:30 UTC 2021
Thanks Remi, I'm a user of ASM also, for a long time, since 2007, it's a
very performant library.
Yes, we could replace the policy audit with another tool, but it's
academic, the remaining code cannot be upgraded.
For now the policy tools informs me of reflection access, I don't need
to blacklist it if I read the code and it's doing something harmless,
eg. it might be calling public methods, to support multiple versions of
java.
I looked at Agents to replace permission checks, it requires
modification of private methods, it's bad practice, we've removed all
code that accessed private implementation or state, we only use public API.
It's not just a simple case of instrumenting public API's, many
permissions defend constructors, and constructors contain private static
methods to defend against finalizer attacks. While I could defend
public methods, methods are called far more often than constructors, it
would have an unacceptable impact on performance. Years will pass
before finalizers are removed and constructors are simplified so they
can be instrumented.
It's not viable to re-implement an authorization layer as an external
library for Java.
Right now SM only has a less than 3% impact on performance and doesn't
affect scalability, how can I justify replacing it, for what new
feature? I don't run untrusted code, it works reliably for the
authorization based access controls that I require and provides access
to subject credentials for authentication of secure connections.
Performance profiling of SM running with stateless TLS sockets
<https://imgur.com/VcSwffC>
https://imgur.com/VcSwffC
https://imgur.com/VcSwffC
https://imgur.com/VcSwffC
I think Haskell has better type safety than Java, it handles Null with
Maybe, it's good for parsing data, it appears to have made few
compromises in its design, but I'm not saying that from experience. I
think if I was looking for something to run untrusted code, it would be
as source code that I parsed, then compiled, perhaps a subset of Haskell
parsed as source code, if I used it for that, then it's audited by
parsing and the compiler. I guess something similar could be done with
ASM and bytecode, but it's not my goal to run untrusted code, I'll leave
the sandbox for the developers cat to bury applets.
Regards,
Peter.
On 28/07/2021 7:41 pm, forax at univ-mlv.fr wrote:
>
>
> ------------------------------------------------------------------------
>
> *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, forax at univ-mlv.fr
> <mailto:forax at univ-mlv.fr> wrote:
>
> ----- Original Message -----
>
> From: "Alan Bateman"<Alan.Bateman at oracle.com> <mailto:Alan.Bateman at oracle.com>
> To: "Remi Forax"<forax at univ-mlv.fr> <mailto:forax at univ-mlv.fr>, "Peter Firmstone"<peter.firmstone at zeus.net.au> <mailto: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/717299ba/attachment.htm>
More information about the security-dev
mailing list