Preventing System.Exit() from API

Preventing System.exit() from API

You can install a security manager which disables System.exit():

  private static class ExitTrappedException extends SecurityException { }

private static void forbidSystemExitCall() {
final SecurityManager securityManager = new SecurityManager() {
public void checkPermission( Permission permission ) {
if( "exitVM".equals( permission.getName() ) ) {
throw new ExitTrappedException() ;
}
}
} ;
System.setSecurityManager( securityManager ) ;
}

private static void enableSystemExitCall() {
System.setSecurityManager( null ) ;
}

Edit: Max points out in comments below that

as of Java 6, the permission name is actually "exitVM."+status, e.g. "exitVM.0".

However, the permission exitVM.* refers to all exit statuses, and exitVM is retained as a shorthand for exitVM.*, so the above code still works (see the documentation for RuntimePermission).

How to prevent calls to System.exit() from terminating the JVM?

Yes, this is possible using a SecurityManager. Try the following

class MySecurityManager extends SecurityManager {
@Override public void checkExit(int status) {
throw new SecurityException();
}

@Override public void checkPermission(Permission perm) {
// Allow other activities by default
}
}

In your class use the following calls:

myMethod() {
//Before running the external Command
MySecurityManager secManager = new MySecurityManager();
System.setSecurityManager(secManager);

try {
invokeExternal();
} catch (SecurityException e) {
//Do something if the external code used System.exit()
}
}

System.exit(0) does not prevent finally being called when have a SecurityManager.checkExit throw an exception

Because exit was prevented by the ThreadDeath exception (which is not one you should be throwing yourself btw):

SecurityException - if a security manager exists and its checkExit method doesn't allow exit with the specified status.

https://docs.oracle.com/javase/7/docs/api/java/lang/System.html#exit(int)

Note that you should throw a SecurityException to prevent exit e.g.:

System.setSecurityManager(new SecurityManager() {
@Override
public void checkExit(int status) {
throw new SecurityException("Not allowed.");
}
});

try {
System.exit(0);
} catch(SecurityException e) {
System.out.println("Exit failed.");
} finally {
System.out.println("I am finally block");
}
System.out.println("Program still running");

Output:

Exit failed.
I am finally block
Program still running

Ignore System.exit() from other class

You can't ignore it per se, but you can prevent it from terminating the JVM via SecurityManager.
Take a look at this question for detailed code example.

Is it safe to use `System.exit()` to stop a java application which has an embed Jetty server?

Sure, you can use System.exit(0).

But using the stop method from server would be much more cleaner and prevent you of unexpected errors (e.g. still open request).

Prevent System.exit in a Groovy web console without security policy file

I looked at Groovy's "NoExitSecurityManager" and found it is doing exactly that: disallowing System.exit() ... which is not enough.

My solution was creating my own class "DisallowAllSecurityManager" which extends SecurityManager and disallows everything a script should not need, like write access to the file system or connecting to other hosts, by throwing an SecurityException in each check.. method.

But: You cannot throw an exception in all check.. methods. Here is a list of check.. methods you need to allow:

  • checkCreateClassLoader()
  • checkMemberAccess()
  • checkPackageAccess()
  • checkPermission()
  • checkPropertyAccess()
  • checkRead()

When you want to evaluate your Groovy script you can do it the following way, limiting only the groovy script:

SecurityManager securityManager = System.getSecurityManager();
try {
System.setSecurityManager(new DisallowAllSecurityManager());
Object result = groovyShell.evaluate(expression);
...
} catch (...) {
...
} finally {
System.setSecurityManager(securityManager);
}

Springboot 2.5.1 service doesn't stop on System.exit(0)

Thanks for the thread dump. The problem's caused by a possible bug in Spring Boot where it deadlocks when System.exit(int) is called while the application context is being refreshed. Thanks for bringing it to our attention.

Until the problem is fixed in Spring Boot you can work around it by setting spring.main.register-shutdown-hook to false.

As described in the documentation, SpringApplication.exit is intended for use in your application's main method. Your usage of it is rather unusual and you may want to explore taking a different approach.

It looks like you want your application to run in a mode when it migrates the database and then shuts down. Your current approach doesn't appear to restrict what may happen up until the point that the database is migrated. You could take a little more control over that by using a different main @Configuration class when starting your application. Something like this:

@SpringBootApplication
public class ExampleApplication {

public static void main(String[] args) {
if (args.length > 0 && args[0].equals("migrate")) {
new SpringApplicationBuilder(DatabaseMigration.class).web(WebApplicationType.NONE).run(args);
}
else {
SpringApplication.run(ExampleApplication.class, args);
}
}

@ImportAutoConfiguration(classes = { FlywayAutoConfiguration.class, DataSourceAutoConfiguration.class })
static class DatabaseMigration {

}

}

The above, when started with a --migrate command line argument, will do just enough to create a DataSource, run Flyway, and then exit.



Related Topics



Leave a reply



Submit