What's the performance penalty, if any, of using a SecurityManager
Asked Answered
E

3

10

Is there a performance penalty when using a SecurityManager?

I need the following:

public class ExitHelper {

    public ExitHelper() {

        System.setSecurityManager(new ExitMonitorSecurityManager());

    }

    private static class ExitMonitorSecurityManager extends SecurityManager {

        @Override
        public void checkPermission(Permission perm) {}

        @Override
        public void checkPermission(Permission perm, Object context) {}

        @Override
        public void checkExit( final int status ) {
            // this is the part I need and I don't care much about the performance issue of this method
        }
}

Will this have a huge impact on my program?

The program does open a lot of files, for example. And if I enable the SecurityManager and put some logging in there, I can that these methods are called a lot. Really a lot. So much that normal logging is lost amongst logging from these two methods. So it seems putting a SecurityManager into place means that lots and lots of calls are made. Would it be any slower than the default SecurityManager? (is there any by default?)

How does this work? Which part of the program will be checked for permissions and how often? I'm concerned by the two checkPermission(...) methods.

Exude answered 22/11, 2011 at 17:10 Comment(1)
Same question here: #3656828Vast
S
8

There is a performance penalty, but it is likely to be small because:

  • It only applies when you attempt some form of activity that requires a permission check.
  • Most operations that require permission checks are expensive operations (IO, network access etc.), so it is likely that the overhead of security checks is going to be a pretty low percentage of total runtime.
  • The check itself can be made very cheaply

In particular, note that the calling code for security checks is typically very lightweight in the Java library code, i.e. something like this:

 SecurityManager security = System.getSecurityManager();
 if (security != null) {
     security.checkXXX(argument,  . . . );
 }

If your security manager code itself is equally lightweight, then the runtime cost of the security check should be negligible. I would avoid putting any logging code in the SecurityManager itself however - this would be costly and probably belongs at a higher level in your application code.

If you want to absolutely minimise the overhead of the security manager for permissions that you don't care about, then you should override the specific checkXXX methods that you don't need with something like:

@Override 
public void checkRead(String file) {
  // empty method as we are happy to allow all file reads
}

Ultimately you'll have to benchmark for your particular situation, but the "gut feel" answer would be that you shouldn't really be worrying about it.

Socalled answered 22/11, 2011 at 18:0 Comment(0)
M
2

yes there is a performance penalty. if you are concerned about it, your only recourse is to measure it and see if the penalty is too high.

one potential solution for your specific use case is if you can narrow the scope of when it's needed. you clearly want to stop some code which you don't control from exiting the application. if you know when that code could be invoked, then you can just set the security manager during that call (note, you need to be aware of threading affects here since the security manager setting is global), e.g.:

System.setSecurityManager(new ExitMonitorSecurityManager());
try {
  // ... do protected op here ...
} finally {
  System.setSecurityManager(null);
}

UPDATE:

to clarify to those who may be coming to this answer later, this answer is not designed for dealing with potentially malicious code. In that situation, an appropriately configured SecurityManager should be in place at all times. This answer assumes that the OP is trying to deal with a poorly written third-party library which makes an unfortunate call to System.exit() at some, well defined point in time.

Midtown answered 22/11, 2011 at 17:36 Comment(3)
Nooooooooooo!!!!!!! You don't know when code could be invoked. Other than you might have more than one thread you might be trying to run untrusted code on at once, malicous code could, say, run a finaliser.Smash
@TomHawtin-tackline - huh? if you know that a specific library call you are about to invoke does the action you don't want, then you could use something like this (agreed that it's not ideal for various reasons). this is assuming you are not running malicious code, just poorly behaved code. if you are running potentially malicious code, then you should have a full time SecurityManager, end of story. Pretty sure the OP is referring the former situation, not the latter.Midtown
@TomHawtin-tackline - i've updated the answer to clarify the context.Midtown
H
2

I have some empirical evidence to contribute here, after implementing the security manager question:

A java SecurityManager that is identical to NO security manager except for a single check adjustment for System.exit

The performance impact with this anonymous inner class was HUGE:

        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);
            }
        });

My experience after launching my application in Eclipse was that it was visibly slower and I confirmed the same in a colleague's PC.

So I feel that 'negligible' may be an understatement (and my use case does not even actually perform any checks!). Consider this as an anecdote that this is not the case.

As another side note: I created a final class with do-nothing checks for ALL methods to avoid instantiating permission objects and such (end encourage the jit compiler to hot-wire it). Using this approach, the performance impact was indeed minimal. So, for people that simply want to add a couple of specific checks (and not rely on java policies) this actually does have negligible impact:

public final class SystemExitTraceSecurityManager extends SecurityManager {

    @Override
    public final void checkAccept(String host, int port) {
    }

    @Override
    public final void checkAccess(Thread t) {
    }

    @Override
    public final void checkAccess(ThreadGroup g) {
    }

    @Override
    public final void checkAwtEventQueueAccess() {
    }

    @Override
    public final void checkConnect(String host, int port) {
    }

    @Override
    public final void checkConnect(String host, int port, Object context) {
    }

    @Override
    public final void checkCreateClassLoader() {
    }

    public final void checkDelete(String file) {
    };

    @Override
    public final void checkExec(String cmd) {
    }

    public final void checkExit(int status) {
        Thread.dumpStack();
    };

    @Override
    public final void checkLink(String lib) {
    }

    @Override
    public final void checkListen(int port) {
    }

    @Override
    public final void checkMemberAccess(Class<?> clazz, int which) {
    }

    @Override
    public final void checkMulticast(InetAddress maddr) {
    }

    @Override
    public final void checkMulticast(InetAddress maddr, byte ttl) {
    }

    @Override
    public final void checkPackageAccess(String pkg) {
    }

    @Override
    public final void checkPackageDefinition(String pkg) {
    }

    @Override
    public final void checkPermission(Permission perm) {
    }

    @Override
    public final void checkPermission(Permission perm, Object context) {
    }

    @Override
    public final void checkPrintJobAccess() {
    }

    @Override
    public final void checkPropertiesAccess() {
    }

    public final void checkPropertyAccess(String key) {
    };

    @Override
    public final void checkRead(FileDescriptor fd) {
    }

    @Override
    public final void checkRead(String file) {
    }

    @Override
    public final void checkRead(String file, Object context) {
    }

    @Override
    public final void checkSecurityAccess(String target) {
    }

    @Override
    public final void checkSetFactory() {
    }

    @Override
    public final void checkSystemClipboardAccess() {
    }

    @Override
    public final boolean checkTopLevelWindow(Object window) {
        return true;
    }

    @Override
    public final void checkWrite(FileDescriptor fd) {
    }

    @Override
    public final void checkWrite(String file) {
    }
}
Husband answered 31/8, 2017 at 9:7 Comment(1)
Note: Performance impact shouldn't be as severe from JDK 9 onwards, thanks to JEP 232 .Snapshot

© 2022 - 2024 — McMap. All rights reserved.