bashでフォーク爆弾が死んでいるように、なぜzshで死ぬことができないのですか?

bashでフォーク爆弾が死んでいるように、なぜzshで死ぬことができないのですか?

私は私のシステムをフォーク爆弾でより弾力的にしたいと思います。これは、systemdの引数を使用するか、cgrulesengdを介してすべての有効なシェルのコントローラをDefaultTasksMax使用して部分的に達成できます。cgrouppids

*:bash               pids                             users/shells/bash/
*:zsh                pids                             users/shells/zsh/

シェル制限を設定するための小さなスクリプトもあります。

CGDIR=/sys/fs/cgroup/
mkdir -p       $CGDIR/pids/users/shells/
echo '8192'  > $CGDIR/pids/users/shells/pids.max
mkdir -p       $CGDIR/pids/users/shells/bash/
echo '2048'  > $CGDIR/pids/users/shells/bash/pids.max
mkdir -p       $CGDIR/pids/users/shells/zsh/
echo '1024'  > $CGDIR/pids/users/shells/zsh/pids.max

bashシェルを使用して端末を起動して:(){ :|:& };:実行すると、何も起こりません。pids.current50〜60%のCPU使用率でほぼ即座に2048を取得します。ターミナルを閉じるとフォークボムが消え、すべてが正常に戻ります。

zshシェルを使用して端末で同じ操作を実行したい場合は、すぐに100%CPUを使用して端末を閉じた後でも、フォーク爆弾が原因でシステムがシャットダウンします。この問題を解決する唯一の方法は、異なるシェルを持つkillall -9 zsh端末でコマンドを複数回実行することです。

bashでフォーク爆弾が死んでいるように、なぜzshで死ぬことができないのですか?つまり、ターミナルを閉じると爆弾が爆発します。

答え1

EAGAINが失敗したbash場合fork()は、制限に達した場合(setrlimitを使用するか、対応するcgroup pid制限を使用)、スリープモードに切り替え、bash1秒後に再試行してから2秒後(再度失敗した場合)、4秒後にスリープモードに切り替えます。 8秒間さらにフォーク(!)を試みずに放棄します。

その後、bash制限に達すると(静かなシステムでは1秒未満)、ほとんどのbashがスリープモードで処理されます。これがフォーク爆弾がbash他の砲弾よりもはるかに悪い理由です。

端末を閉じても、これらのプロセスは終了しません。おそらくあなたが見ているのは、15秒が少し以上の時間(1+2+4+8)後にフォーク爆弾が消えることです。この時点で正常に開始され、スリープモードに移行したすべてのプロセスは、開始してから8秒後に同時に終了します。 4番目のフォークの試み。

ではzsh再試行モードとスリープモードがなく、すべてのプロセスが分岐して終了します。プロセスが終了すると、フォークされたプロセスの1つで使用できるようにプロセスが解放されます。

フォーク爆弾を終了したい場合、最も簡単な方法はプロセスグループ全体を終了することです。これは、プロセスのリストを収集し、各プロセスに対して個別にシャットダウンを送信する必要があるkillallため実現できません。killallすべてのプロセスがスリープモードの場合は問題ありませんが、bashプロセスが常に作成され、各シャットダウンの間に開始できる他のシェルには適していません。

を使用してpgidを取得し、ps -jを使用してプロセスグループを終了できますkill -- "-$pgid"

関連情報