System.exit() 呼出しはJava仮想マシン(JVM)を終了させる。つまり、実行中のすべてのプログラムやスレッドを終了させる。結果としてサービス運用妨害(DoS)を引き起こされる可能性がある。たとえば、Java Server Page(JSP)に組込まれたSystem.exit()を呼び出すことで、ウェブサーバを終了させ、プログラムがそれ以上サービスを提供できないようにすることが可能である。したがってプログラムは、突然の悪意ある System.exit() 呼出しを阻止しなくてはならない。さらに(Windows のタスクマネージャやPOSIXのkillコマンドの使用により)プログラムが強制的に終了させられる場合、必要なクリーンアップ処理を行わなくてはならない。
違反コード
以下の違反コード例では、System.exit()を使用してJVMを強制的にシャットダウンし、実行中のプロセスを強制終了している。このプログラムはセキュリティマネージャーを実装していないため、呼出し側がSystem.exit()を呼び出してよいかどうかをチェックすることができない。
public class InterceptExit {
public static void main(String[] args) {
// ...
System.exit(1); // 突然の exit 呼出し
System.out.println("This never executes");
}
}
適合コード
以下の適合コードでは、SecurityManager クラスで定義されている checkExit() メソッドをオーバーライドする独自のセキュリティマネージャ PasswordSecurityManager を実装している。exitを許可する前にクリーンアップコードの呼出しを行うには、このようにオーバーライドする必要がある。SecurityManagerクラスに定義されているデフォルトのcheckExit()メソッドにはこの機能が存在しない。
class PasswordSecurityManager extends SecurityManager {
private boolean isExitAllowedFlag;
public PasswordSecurityManager(){
super();
isExitAllowedFlag = false;
}
public boolean isExitAllowed(){
return isExitAllowedFlag;
}
@Override
public void checkExit(int status) {
if (!isExitAllowed()) {
throw new SecurityException();
}
super.checkExit(status);
}
public void setExitAllowed(boolean f) {
isExitAllowedFlag = f;
}
}
public class InterceptExit {
public static void main(String[] args) {
PasswordSecurityManager secManager =
new PasswordSecurityManager();
System.setSecurityManager(secManager);
try {
// ...
System.exit(1); // 突然の exit 呼出し
} catch (Throwable x) {
if (x instanceof SecurityException) {
System.out.println("Intercepted System.exit()");
// 例外をログに記録する
} else {
// 例外ハンドラに処理を渡す
}
}
// ...
secManager.setExitAllowed(true); // exit を許可する
// System.exit() が実行される
// ...
}
}
このプログラムでは、フラグを使ってexitが許可されているかどうかを確認している。setExitAllowed()メソッドはこのフラグを設定するが、フラグが設定されていない場合(つまりfalseの場合)、checkExit()メソッドはSecurityExceptionをスローする。このフラグは初期化時はfalseであるため、try 節では、最初のSystem.exit()を実行せずにSecurityException をスローする。プログラムはSecurityExceptionをキャッチし、例外をログに記録するなどのクリーンアップ処理を行う。クリーンアップ処理が完了して初めて System.exit() メソッドの実行が許可される。
例外
ERR09-EX0: コマンドラインプログラムにおいて、たとえば呼び出しに必要な引数が与えられていない場合などに System.exit() を呼び出すことは許される[Bloch 2008][ESA 2005]。
リスク評価
Sytem.exit()の不正な呼出しを許すと、サービス運用妨害(DoS)につながる恐れがある。
| ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
|---|---|---|---|---|---|
| ERR09-J | 低 | 低 | 中 | P2 | L3 |
関連ガイドライン
| MITRE CWE | CWE-382. J2EE bad practices: Use of System.exit() |
参考文献
| [API 2006] | Method checkExit(), class Runtime, method addShutdownHook |
| [Austin 2000] | Writing a Security Manager |
| [Darwin 2004] | 9.5, The Finalize Method |
| [ESA 2005] | Rule 78. Restrict the use of the System.exit method |
| [Goetz 2006] | 7.4, JVM Shutdown |
| [Kalinovsky 2004] | Chapter 16, Intercepting a Call to System.exit |
翻訳元
これは以下のページを翻訳したものです。
ERR09-J. Do not allow untrusted code to terminate the JVM (revision 70)



