警告:ほとんどのシェルでこのコマンドを実行すると、システムの破損につながり、修正するには強制シャットダウンが必要になります
再帰関数:(){ :|: & };:
とその機能を理解しています。しかし、forkシステムコールがどこにあるのかわかりません。よくわかりませんが、パイプの中で疑わしいです|
。
_x | y
_のパイプの結果として、フォアグラウンドプロセスグループの一部としてパイプラインを含むサブシェルが作成されます。これにより、無制限に(fork()
を介して)サブシェルが作成され、フォーク爆弾が作成されます。
_$ for (( i=0; i<3; i++ )); do
> echo "$BASHPID"
> done
16907
16907
16907
$ for (( i=0; i<3; i++ )); do
> echo "$BASHPID" | cat
> done
17195
17197
17199
_
ただし、コードが実行されるまでフォークは実際には発生しません。これは、コード内の_:
_の最後の呼び出しです。
フォーク爆弾のしくみを分解するには:
:()
-_:
_という新しい関数を定義します{ :|: & }
_-呼び出し元の関数をバックグラウンドで呼び出し元の関数の別のインスタンスに再帰的にパイプする関数定義:
_-フォーク爆弾関数を呼び出しますこれはメモリを集中的に使用する傾向はありませんが、PIDを消費し、CPUサイクルを消費します。
コードの最後のビット_;:
_は、関数:(){ ... }
を実行しています。ここでフォークが発生しています。
セミコロンは最初のコマンドを終了し、次のコマンドを開始します。つまり、関数_:
_を呼び出します。この関数の定義には、それ自体への呼び出し(_:
_)が含まれており、この呼び出しの出力は、バックグラウンドバージョン_:
_にパイプされます。これは無期限にプロセスを支えます。
関数:()
を呼び出すたびに、C関数fork()
を呼び出します。最終的に、これはシステム上のすべてのプロセスID(PID)を使い果たします。
_|:&
_を他の何かと交換して、何が起こっているのかを知ることができます。
1つのターミナルウィンドウで次のようにします。
_$ watch "ps -eaf|grep \"[s]leep 61\""
_
別のウィンドウで、フォーク爆弾のわずかに変更されたバージョンを実行します。このバージョンはそれ自体がスロットルすることを試みるので、それが何をしているのか研究することができます。このバージョンは、関数:()
を呼び出す前に61秒間スリープします。
また、呼び出された後の最初の呼び出しもバックグラウンドで処理します。 Ctrl + z、次にbg
と入力します。
_$ :(){ sleep 61; : | : & };:
# control + z
[1]+ Stopped sleep 61
[2] 5845
$ bg
[1]+ sleep 61 &
_
最初のウィンドウでjobs
コマンドを実行すると、次のようになります。
_$ jobs
[1]- Running sleep 61 &
[2]+ Running : | : &
_
数分後:
_$ jobs
[1]- Done sleep 61
[2]+ Done : | :
_
一方、watch
を実行している別のウィンドウで:
_Every 2.0s: ps -eaf|grep "[s]leep 61" Sat Aug 31 12:48:14 2013
saml 6112 6108 0 12:47 pts/2 00:00:00 sleep 61
saml 6115 6110 0 12:47 pts/2 00:00:00 sleep 61
saml 6116 6111 0 12:47 pts/2 00:00:00 sleep 61
saml 6117 6109 0 12:47 pts/2 00:00:00 sleep 61
saml 6119 6114 0 12:47 pts/2 00:00:00 sleep 61
saml 6120 6113 0 12:47 pts/2 00:00:00 sleep 61
saml 6122 6118 0 12:47 pts/2 00:00:00 sleep 61
saml 6123 6121 0 12:47 pts/2 00:00:00 sleep 61
_
また、_ps -auxf
_はこのプロセス階層を示しています。
_$ ps -auxf
saml 6245 0.0 0.0 115184 5316 pts/2 S 12:48 0:00 bash
saml 6247 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
....
....
saml 6250 0.0 0.0 115184 5328 pts/2 S 12:48 0:00 bash
saml 6268 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
saml 6251 0.0 0.0 115184 5320 pts/2 S 12:48 0:00 bash
saml 6272 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
saml 6252 0.0 0.0 115184 5324 pts/2 S 12:48 0:00 bash
saml 6269 0.0 0.0 100988 464 pts/2 S 12:48 0:00 \_ sleep 61
...
...
_
_killall bash
_は、手に負えなくなる前に停止します。この方法でクリーンアップを行うと、多少の手間がかかる可能性があり、bash
シェルをすべて破壊しない可能性のある、より穏やかな方法は、次のようにすることです。
フォーク爆弾が実行される予定の疑似端末を特定する
_$ tty
/dev/pts/4
_
疑似端末を強制終了します
_$ pkill -t pts/4
_
bash
とsleep
を呼び出すたびに、コマンドが実行されたbash
シェルからC関数fork()
が呼び出されます。