3

I am not well versed in java security managers and therefore want to confirm my understanding:

I have a java process that randomly stops (shutdown hook runs) even though there is no trace of someone killing it. As a result I decided to install a security manager and override checkExit(int status) to make sure the reason for the stop is not something calling System.exit(). Basically I wrote this:

            System.setSecurityManager(new SecurityManager() {
                @Override
                public void checkExit(int status) {
                    Thread.dumpStack();
                    super.checkExit(status);
                }
            });

I was expecting that my program would run as usual, with the only change being that a stack trace would be dumped if System.exit() was called. I found that this is NOT the case. It fails to start with this security exception:

java.security.AccessControlException: access denied ("java.util.PropertyPermission" "config" "read")
        at java.security.AccessControlContext.checkPermission(AccessControlContext.java:472) ~[na:1.8.0_74]
        at java.security.AccessController.checkPermission(AccessController.java:884) ~[na:1.8.0_74]
        at java.lang.SecurityManager.checkPermission(SecurityManager.java:549) ~[na:1.8.0_74]
        at java.lang.SecurityManager.checkPropertyAccess(SecurityManager.java:1294) ~[na:1.8.0_74]
        at java.lang.System.getProperty(System.java:717) ~[na:1.8.0_74]
        at Main.main(Main.java:161) ~[na:na]

It appears that the SecurityManager does NOT replicate the default behavior and after reading about it would seem that it applies the default policy under ${JAVA_HOME}/jre/lib/security/java.policy which is quite restrictive.

What is the real default behavior of Java when there is NO security manager? Is it to 'allow everything' or is there something else happening?

What should I install as a security manager if I wanted to replicate the default behavior, apart from that single adjustment above?

On that last point, I can see that System.setSecurityManager() actually expects an instance of java.lang.SecurityManager which means I am forced to use that implementation (that relies on policy files). What would be the most efficient way of overriding methods in that class to replicate the actual default behavior of NO security manager?

EDIT: As per the discussion below, this seems to do it

            System.setSecurityManager(new SecurityManager() {
                @Override
                public void checkPermission(Permission perm) {
                    return; // no security manager behaviour
                }

                @Override
                public void checkPermission(Permission perm, Object context) {
                    return; // no security manager behaviour
                }

                @Override
                public void checkExit(int status) {
                    Thread.dumpStack();
                    super.checkExit(status);
                }
            });
Alexandros
  • 2,097
  • 20
  • 27

1 Answers1

2

You are confused.

It appears that the SecurityManager does NOT replicate the default behavior and after reading about it would seem that it applies the default policy under ${JAVA_HOME}/jre/lib/security/java.policy which is quite restrictive.

The default behaviour of a SecurityManager is to obey the contract stated in the Javadoc, except as permitted by the default .policy file, which is indeed quite restrictive. The default behaviour in the absence of a security manager is to allow anything and everything.

What is the real default behavior of Java when there is NO security manager? Is it to 'allow everything'

Yes.

or is there something else happening?

No.

What should I install as a security manager if I wanted to replicate the default behavior, apart from that single adjustment above?

A security manager that does exactly that. If you want it to enforce nothing except the one override you have implemented, you have to provide empty overrides for all its other methods.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • From the javadoc: The special method `SecurityManager.checkPermission(java.security.Permission)` determines whether an access request indicated by a specified permission should be granted or denied. The default implementation calls `AccessController.checkPermission(perm);` Is it safe to just override `checkPermission()` so that it returns immediately? EDIT: there are two variants of the checkPermission() method and looking at the sources I should be ok if I just override these 2. – Alexandros Aug 30 '17 at 11:16
  • No, you should override it so it returns *except* in the case of the `Permission` you want to check, by calling `super.checkPermission()` and dumping the stack trace. Surely this is obvious? – user207421 Aug 30 '17 at 11:25
  • But I do NOT want to check anything (default behaviour of java when no security manager exists). So since everything delegates to checkPermission, the minimal change to have a "DoNothingSecurityManager" would be to override just the 2 methods? So with the 3rd override to dump the stack trace on checkExit() I should be good (checking this now). – Alexandros Aug 30 '17 at 11:28
  • So you want to return immediately *except in the case you want to dump the stack.* I already said that. – user207421 Aug 30 '17 at 11:29
  • Seems like we have a bit of a broken phone situation. It is what I understood, but not what I thought you meant. It also seems to be what you meant but not what you thought I understood. Either way, it is correct and works with just the checkPermission+checkExit overrides, so accepted your answer and updated the question to put the working version in it. – Alexandros Aug 30 '17 at 11:50