|パイプライン

|パイプライン

私は一般的なフォーク爆弾がどのように機能するのか理解していますが、公開bashフォーク爆弾の終わりに&が必要な理由と、これらのスクリプトが異なる動作をする理由をよく理解していません。

:(){ (:) | (:) }; :

そして

:(){ : | :& }; :

前者はCPU使用率を急増し、ログイン画面に戻ります。後者のためにシステムがハングし、ハード再起動が必要でした。なぜそんなことですか?どちらも常に新しいプロセスを作成していますが、なぜシステムが異なる動作をしているのでしょうか。

両方のスクリプトも異なる動作をします。

:(){ : | : }; :

似ていると思いましたが、まったく問題は発生しませんでした。 Bashのマニュアルページには、パイプラインのコマンドがすでにサブシェルで実行されていることが示されているので、次のように考えます。 |私は新しいサブシェルでパイプを実行する必要があると信じていますが、なぜそれほど大きな変更が必要なのでしょうか?

編集:htopを使用してプロセス数を制限すると、最初のバリアントは実際のプロセスツリーを作成し、2番目のバリアントは同じレベルですべてのプロセスを作成し、最後のバリアントはプロセスをまったく生成しないようです。いいえ。これは私をもっと混乱させますが、多分役に立ちますか?

ベストアンサー1

警告本番システムでこのプログラムを実行しないでください。しないでください。ulimit -u警告:「爆弾」を試す前に、それが使用されていることを確認してください。以下の[a]をお読みください。

PIDと日付(時刻)を取得する関数を定義しましょう。

bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }

bombこれは、新規ユーザーのためのシンプルで問題のない機能です(自分を保護してください:[a]を読む):

bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2

この関数が実行のために呼び出されると、次のように動作します。

bize:~$ bomb
  START 0002786 23:07:34
yes
    END 0002786 23:07:35
bize:~$

コマンドがdate実行された後、「yes」を印刷し、1秒間待機してからコマンドを閉じ、date最後に関数は新しいコマンドプロンプトの印刷を終了します。素晴らしいことはありません。

|パイプライン

次のように関数を呼び出すと:

bize:~$ bomb | bomb
  START 0003365 23:11:34
yes
  START 0003366 23:11:34
yes
    END 0003365 23:11:35
    END 0003366 23:11:35
bize:~$

両方のコマンドは同時に開始され、両方のコマンドは1秒後に終了します。それからプロンプトが返されます。

|これがパイプラインが両方のプロセスを並列に開始する理由です。

&背景

エンディングを追加するために呼び出しを変更すると、次のようになります&

bize:~$ bomb | bomb &
[1] 3380
bize:~$
  START 0003379 23:14:14
yes
  START 0003380 23:14:14
yes
    END 0003379 23:14:15
    END 0003380 23:14:15

プロンプトがすぐに返され(すべてのジョブがバックグラウンドで送信される)、両方のコマンドは以前と同じように実行されます。[1]プロセスPIDの以前に印刷された「ジョブ番号」の値を参照してください3380。後でパイプが終了したことを示すために、同じ数字が印刷されます。

[1]+  Done                    bomb | bomb

これが効果です&

これが&プロセスをより早く開始する理由です。

より簡単な名前

bこれら2つのコマンドを実行する簡単な関数を作成できます。 3行で入力してください。

bize:~$ b(){
> bomb | bomb
> }

次のように実行されます。

bize:~$ b
  START 0003563 23:21:10
yes
  START 0003564 23:21:10
yes
    END 0003564 23:21:11
    END 0003563 23:21:11

;定義でnoを使用したことに注意してくださいb(改行文字は要素を区切るために使用されます)。ただし、1行定義では、;次のように使用するのが一般的です。

bize:~$ b(){ bomb | bomb ; }

ほとんどのスペースは必須ではなく、それに対応する内容を書くことができます(しかしあまり明確ではありません)。

bize:~$ b(){ bomb|bomb;}

&aを使用して分離し、}両方のプロセスをバックグラウンドで送信することもできます。

爆弾。

関数が自分自身を呼び出して尾を噛むと、「フォーク爆弾」が発生します。

bize:~$ b(){ b|b;}       ### May look better as b(){ b | b ; } but does the same.

より多くの機能をすばやく呼び出すには、パイプを背景に送信します。

bize:~$ b(){ b|b&}       ### Usually written as b(){ b|b& }

関数の最初の呼び出しに必須を追加し、;名前を次のように変更すると、:次の結果が得られます。

bize:~$ :(){ :|:&};:

通常、次のように書かれます。:(){ :|:& }; :

または、別の名前(雪だるま)を使って楽しい方法で作成しました。

☃(){ ☃|☃&};☃

ulimit(このコマンドを実行する前に設定する必要があります)は、多数のエラーが発生した後にすぐにプロンプ​​トが返されるようにします(エラーリストが停止したらEnterを押してプロンプトを表示します)。

シェルがサブシェルを起動する方法は、実行中のシェルをフォークし、実行するコマンドとともにフォークされたプロセスで exec() を呼び出すことであるため、「フォーク爆弾」と呼ばれます。

パイプラインは2つの新しいプロセスを「フォーク」します。これを無限大にすれば爆弾が生じます。
あるいは、早く繁殖したので、元々「ウサギ」と呼ばれていました。


タイミング:

  1. :(){ (:) | (:) }; time :
    終了真
    0m45.627s

  2. :(){ : | :; }; time :
    終了真
    0m15.283s

  3. :(){ : | :& }; time :
    True 0m00.002 s は
    まだ実行中です。


あなたの例:

  1. :(){ (:) | (:) }; :

    2番目のエンディングが)分離されるのは、}より複雑なバージョンです:(){ :|:;};:。それにもかかわらず、パイプラインの各コマンドはサブシェル内で呼び出されます。これが効果です()

  2. :(){ : | :& }; :

    スペースなしで書かれたより速いバージョンです:(){(:)|:&};:(13文字)。

  3. :(){ : | : }; : ### zshでは動作しますが、bashでは動作しません。

    (bashに)構文エラーがあります。次のように、endの前にメタ文字が必要です}

     :(){ : | :; }; :
    

[ㅏ] 新しいクリーンユーザーを作成します(これを鉱山と呼びますbize)。コンソールで新しいユーザーとしてログインsudo -i -u bizeするか、次の操作を行います。

$ su - bize
Password: 
bize:~$

max user processes制限を確認して変更してください。

bize:~$ ulimit -a           ### List all limits (I show only `-u`)
max user processes              (-u) 63931
bize:~$ ulimit -u 10        ### Low
bize:~$ ulimit -a
max user processes              (-u) 1000

10個だけを使用するのは、新しいユーザーが1人だけのようですbize。これによりkillall -u bize、システムから大部分の(すべてではない)爆弾をインポートして削除するのが簡単になります。どちらがまだ有効かは問わないでください。話しません。しかし、まだ:かなり低いですが、安全のためにシステムに適応してください。
これ「フォーク爆弾」がシステムに衝突しないようにします。

追加資料:

おすすめ記事