System.exit(...) without SecurityManager - implications for Apache Ant project

Jaikiran Pai jai.forums2013 at gmail.com
Mon Aug 23 06:46:38 UTC 2021


(resending from the correct subscribed email address)

I see that System.setSecurityManager(...) will start throwing exception 
by default starting Java 18[1]. I have been following the JEP 411, 
mostly in context of the Apache Ant project. I think we (Ant) are in a 
OK shape for Java 17 when it comes to the security manager deprecation 
messages. The initial issue related to flooding of logs in a basic Ant 
build has been addressed in recent Java 17 EA releases.

Going forward, clearly, Ant has to get rid of its usage of the 
SecurityManager. From what I have seen in the Ant code, the most 
critical usage of the security manager (even when a user doesn't 
specifically configure it) is around the prevention of JVM exit through 
user code that can call System.exit(...). Ant, by default sets up a 
custom SecurityManager and then uses the SecurityManager's 
"checkExit(...)" to prevent such calls. The JEP 411 does state that as a 
future task, the System.exit() usecase will be addressed. I thought I 
had seen a JBS issue linked that dealt with this, but now that I search 
for it, I can't find it except for this one 
https://bugs.openjdk.java.net/browse/JDK-8199704 which was raised some 
years back. Is that the one where the work related to any new APIs for 
preventing system exit, without the SecurityManager API usage, will be 
addressed?

Either way, I haven't seen any specific discussion of the use cases or 
proposals for new APIs around this. So I would like to explain how Ant 
currently uses the SecurityManager APIs when it comes to System.exit() 
calls. As many of you might already know, the core of Ant revolves 
around "tasks" which essentially are pluggable classes where the actual 
build related work happens. Ant ships with many builtin/core classes 
which perform basic build activities. These tasks are then clubbed into 
build "target(s)" in a build file for users to invoke. For the context 
of this discussion, we will focus on the builtin "java" task (which is 
one of the tasks for which Ant sets up a SecurityManager at runtime by 
default). The "java" task takes a class name and then launches the 
"main" method of that class. Users have the option to configure a fork 
mode so that this launch happens in a separate JVM than the one that the 
Ant build is currently running in. In the case where fork is disabled, 
Ant uses reflection to call the "main" method of that class within the 
current running JVM of the Ant build. Since this user provided class can 
do anything in its code, Ant sets up a custom SecurityManager at runtime 
and in addition to "granting" certain permissions, it also overrides the 
"checkExit()" API of the SecurityManager like here[2] and here[3]. What 
that effectively does is whenever the user code, that is launched using 
the "java" task, invokes `System.exit(...)` or 
`Runtime.getRuntime().exit(...)` it lets the SecurityManager API 
infrastructure do the "checkExit" checks and if not allowed then throw 
the SecurityException and prevent the JVM from exiting. Additionally, 
Ant's custom SecurityManager implementation wraps any such 
`SecurityException` from "checkExit(...)" into a internal Exception type 
which holds on to the exit code that was used to call the 
`System.exit(...)` or `Runtime.getRuntime().exit(...)`. This custom 
wrapped exception is then caught in Ant and the captured exit code is 
then logged or used to do additional decisions like whether the build 
should be stopped i.e. should further tasks/targets should be invoked or 
not. Of course there are other implications of continuing with the rest 
of the tasks/build when such a SecurityException is thrown for exit(...) 
calls (for example, if any shutdown hooks were registered by the user 
code those won't be run immediately but will get run after the Ant JVM 
exits), but those issues aren't in the scope of what we are discussing here.

So if any of the upcoming Java 18 EA builds introduce the "disallow" by 
default, then if Ant has to test against those EA builds (not just for 
SecurityManager but any other changes), then Ant project will have to 
start setting the "java.security.manager" system property to "allow". 
That's not going to be straightforward, since it would be dealing with 
this in potentially multiple launch scripts or maybe even dynamic launch 
commands issued through the code (I haven't checked where/how many). I 
don't yet know if this property value can be changed at 
runtime/dynamically. If that is allowed, it may make things a bit easier 
since that would allow us to set that property value at the same place 
where we set the custom security manager in the Ant code, but I would 
still like to avoid it if possible.

So given all this, can the new API(s) design/implementation for 
preventing System.exit(...) calls without a SecurityManager be 
prioritized and perhaps be scheduled for release in Java 18 itself, 
which is where the "disallow" will come in as default?

To summarize - Ant would need a way to intercept/prevent JVM exits via 
System.exit(...) or Runtime.getRuntime().exit(...) calls *and* a way to 
get hold of the exit code that was used to trigger such calls (Ant had 
to wrap the SecurityException into a custom exception type just to keep 
track of that exit code value).


[1] https://github.com/openjdk/jdk/pull/5204
[2] 
https://github.com/apache/ant/blob/master/src/main/org/apache/tools/ant/types/Permissions.java#L182
[3] 
https://github.com/apache/ant/blob/master/src/main/org/apache/tools/ant/util/optional/NoExitSecurityManager.java#L34

-Jaikiran




More information about the security-dev mailing list