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, fo...@univ-mlv.fr wrote:


------------------------------------------------------------------------

    *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


Reply via email to