web-dev-qa-db-ja.com

APIからのSystem.exit()の防止

例外が発生した場合にSystem.exit()を実行するサードパーティのライブラリを使用しています。 jarからAPIを使用しています。とにかく、アプリケーションがシャットダウンするため、System.exit()呼び出しを防ぐことができますか?他の多くのライセンスの問題のため、System.exit()を削除した後、jarを逆コンパイルおよび再コンパイルできません。私はかつて、stackoverflowで[覚えていない他の質問に対する]答えに出くわしました。JavaのSecurityManagerを使用してこのようなことを行うことができます。

35
Swaranga Sarma

ここにブログ投稿があります、

http://jroller.com/ethdsy/entry/disabling_system_exit

基本的には、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 ) ;
  }

編集最大 その下のコメントで指摘

Java 6の時点では、権限名は実際には「exitVM。」+ statusです(例:「exitVM.0」)。

ただし、権限exitVM.*はすべての終了ステータスを参照し、exitVMexitVM.*の省略形として保持されるため、上記のコードは引き続き機能します( RuntimePermissionのドキュメント を参照)。

34
sbridges

JFrame EXIT_ON_CLOSE操作を回避してアプリケーション全体を終了する方法は? への返信を参照してください。

編集1:リンクされたソース。 SecurityManagerを使用してSystem.exit(n)を防ぐ方法を示します。

import Java.awt.*;
import Java.awt.event.*;
import Java.security.Permission;

/** NoExit demonstrates how to prevent 'child'
applications from ending the VM with a call
to System.exit(0).
@author Andrew Thompson */
public class NoExit extends Frame implements ActionListener {

  Button frameLaunch = new Button("Frame"),
     exitLaunch = new Button("Exit");

  /** Stores a reference to the original security manager. */
  ExitManager sm;

  public NoExit() {
     super("Launcher Application");

     sm = new ExitManager( System.getSecurityManager() );
     System.setSecurityManager(sm);

     setLayout(new GridLayout(0,1));

     frameLaunch.addActionListener(this);
     exitLaunch.addActionListener(this);

     add( frameLaunch );
     add( exitLaunch );

     pack();
     setSize( getPreferredSize() );
  }

  public void actionPerformed(ActionEvent ae) {
     if ( ae.getSource()==frameLaunch ) {
        TargetFrame tf = new TargetFrame();
     } else {
        // change back to the standard SM that allows exit.
        System.setSecurityManager(
           sm.getOriginalSecurityManager() );
        // exit the VM when *we* want
        System.exit(0);
     }
  }

  public static void main(String[] args) {
     NoExit ne = new NoExit();
     ne.setVisible(true);
  }
}

/** This example frame attempts to System.exit(0)
on closing, we must prevent it from doing so. */
class TargetFrame extends Frame {
  static int x=0, y=0;

  TargetFrame() {
     super("Close Me!");
     add(new Label("Hi!"));

     addWindowListener( new WindowAdapter() {
        public void windowClosing(WindowEvent we) {
           System.out.println("Bye!");
           System.exit(0);
        }
     });

     pack();
     setSize( getPreferredSize() );
     setLocation(++x*10,++y*10);
     setVisible(true);
  }
}

/** Our custom ExitManager does not allow the VM
to exit, but does allow itself to be replaced by
the original security manager.
@author Andrew Thompson */
class ExitManager extends SecurityManager {

  SecurityManager original;

  ExitManager(SecurityManager original) {
     this.original = original;
  }

  /** Deny permission to exit the VM. */
   public void checkExit(int status) {
     throw( new SecurityException() );
  }

  /** Allow this security manager to be replaced,
  if fact, allow pretty much everything. */
  public void checkPermission(Permission perm) {
  }

  public SecurityManager getOriginalSecurityManager() {
     return original;
  }
}
6
Andrew Thompson

前のコードサンプルは部分的に正しいですが、ファイルへのコードのアクセスをブロックしてしまうことがわかりました。この問題を回避するために、SecurityManagerの記述を少し変えました。

public class MySecurityManager extends SecurityManager {

private SecurityManager baseSecurityManager;

public MySecurityManager(SecurityManager baseSecurityManager) {
    this.baseSecurityManager = baseSecurityManager;
}

@Override
public void checkPermission(Permission permission) {
    if (permission.getName().startsWith("exitVM")) {
        throw new SecurityException("System exit not allowed");
    }
    if (baseSecurityManager != null) {
        baseSecurityManager.checkPermission(permission);
    } else {
        return;
    }
}

}

私の場合、サードパーティのライブラリがVMを終了しないようにする必要がありました。しかし、System.exitを呼び出していたgrailsテストもいくつかありました。そのため、サードパーティライブラリへの呼び出しの直前にのみカスタムセキュリティマネージャーをアクティブ化し(一般的なイベントではない)、その後すぐに元のセキュリティマネージャーを復元するようにコードを記述しました。

それはすべて少し醜いです。理想的には、System.exitコードを単に削除することをお勧めしますが、サードパーティライブラリのソースコードにアクセスできません。

3

SecurityManagerを使用してSystem.exit()呼び出しを禁止することは、少なくとも2つの理由から完全ではありません。

  1. SecurityManagerを有効にした場合と有効にしない場合で実行されるJavaアプリケーションは大きく異なります。そのため、最終的にオフにする必要がありますが、System.setSecurityManager(null)ではオフにできません。この呼び出しは別のセキュリティ許可チェックにつながりますが、アプリケーションコード(SecurityManagerサブクラス)が呼び出しスタックの最上位にあるため、必然的に失敗します。

  2. すべてのJavaアプリケーションはマルチスレッドであり、他のスレッドはforbidSystemExitCall()とenableSystemExitCall()の間でさまざまなことを実行できます。これらのいくつかはセキュリティ権限チェックで保護できますが、上記とまったく同じ理由です。[はるかに一般的な] checkPermission()の代わりにcheckExit()がオーバーライドされると、ほとんどの場合がカバーされます。

これを解決する唯一の方法(私が知っている)は、SecurityManagerサブクラスにすべての特権を付与することです。おそらく、別のクラスローダーによってロードする必要があります。 bootstrap(null)クラスローダー。

3
Ixmal