fork爆弾のfork()はどこにありますか:(){:|:&};:?


25

警告:ほとんどのシェルでこのコマンドを実行すると、システムが破損し、修正するには強制シャットダウンが必要になります。

再帰関数:(){ :|: & };:とその機能を理解しています。しかし、フォークシステムコールがどこにあるのかわかりません。よくわかりませんが、パイプの中で疑ってい|ます。


関連(そして読む価値がある):フォークボムはどのように機能しますか?
テルドン

回答:


30

のパイプの結果として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サイクルを消費します。


ではx | y、なぜサブシェルが作成されるのですか?私の理解では、bashはaを見るとpipepipe()システムコールを実行し、2を返しますfds。これで、command_leftがexecedになり、出力がcommand_rightに入力として渡されます。これで、command_rightがexec編集されました。では、なぜBASHPID毎回違うのですか?
Abhijeet Rastogi

2
@shadyabhiそれは簡単です- xそしてy、2つの別個のプロセスで実行される2つの別個のコマンドなので、2つの別個のサブシェルがあります。xシェルと同じプロセスで実行する場合、それはx組み込みである必要があります。
jw013

24

コードの最後のビットは;:、関数を実行しています:(){ ... }。これは、分岐が発生している場所です。

セミコロンは最初のコマンドを終了し、別のコマンドを開始しています:。つまり、functionを呼び出しています。この関数の定義にはそれ自体への呼び出しが含まれて:おり、この呼び出しの出力はバックグラウンドバージョンにパイプされ:ます。これはプロセスを無期限に支えます。

関数:()を呼び出すたびに、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
...
...

クリーンアップ時間

Aはkillall bash、彼らが手に負えなくなる前に、物事を停止します。この方法でクリーンアップを行うのは少し手間がかかる場合がありますが、すべてのbashシェルを破壊する可能性のない優しい優しい方法は、次のようにすることです。

  1. フォーク爆弾が実行される擬似端末を決定する

    $ tty
    /dev/pts/4
  2. 擬似端末を殺す

    $ pkill -t pts/4

どうしたの?

まあの各呼び出しbashsleepC関数の呼び出しですfork()からbashコマンドが実行された場所からシェル。


7
bash別の端末で実行されている可能性があります。使用する方が良いでしょうpkill -t pts/2
マチェイピエチョトカ

@MaciejPiechotka-ヒントをありがとう。それを見たことがない、答えに追加しました!
slm
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.