フォークボムでシステムをクラッシュできないのはなぜですか?


54

最近、GNU / Linuxのプロセスに関する情報を掘り下げて、悪名高いfork bombに出会いました。

:(){ : | :& }; :

理論的には、システムがリソースを使い果たすまで無限に複製することになっています...

ただし、CLI DebianGUI Mintディストリビューションの両方でテストしてみましたが、システムに大きな影響は与えないようです。はい、大量のプロセスが作成されます。しばらくすると、次のようなコンソールメッセージを読みました。

bash:fork:リソースは一時的に利用できません

bash:fork:retry:子プロセスはありません

しかし、しばらくすると、すべてのプロセスが強制終了され、すべてが正常に戻ります。ulimitがユーザーごとのプロセスの最大量を設定したことを読んだことがありますが、それを実際に上げることはできないようです。

フォークボムに対するシステム保護とは何ですか?すべてがフリーズするか、少なくとも大幅に遅れるまで、なぜ自己複製しないのですか?フォークボムでシステムを本当にクラッシュさせる方法はありますか?


2
現在設定されている最大PIDは何ですか?
dsstorefile1

5
そのあなたがなりません「クラッシュ」フォーク爆弾を使用して、システム...あなたが言ったように、あなたがリソースを使い果たして、新しいプロセスを起動することができないが、システムはいけませんよ注意クラッシュ
ジョシュ

2
:(){ :& :; }; :代わりに実行するとどうなりますか?彼らはすべて最終的に殺されることになるのですか?どう:(){ while :& do :& done; }; :
mtraceur

あなたのこの素晴らしい質問は、私が以前の「閉じたままにする」投票を再考することを確信させました。ただし、「I」は常に英語で大文字です。これ以上ひどく書かないでください。
user259412

回答:


85

おそらくsystemdを使用するLinuxディストリビューションがあります。

Systemdはユーザーごとにcgroupを作成し、ユーザーのすべてのプロセスは同じcgroupに属します。

Cgroupsは、プロセスの最大数、CPUサイクル、RAM使用量などのシステムリソースに制限を設定するLinuxメカニズムです。これは、ulimitgetrlimit()syscall を使用する)とは異なる、より現代的なリソース制限のレイヤーです。

あなたが実行した場合systemctl status user-<uid>.slice(ユーザーののcgroupを表す)、あなたは現在の数と最大数を確認できたタスクというのcgroup内で許可される(プロセスとスレッド)。

$ systemctl status user- $ UID.slice
●user-22001.slice-UID 22001のユーザースライス
   ロード済み:ロード済み
  ドロップイン:/usr/lib/systemd/system/user-.slice.d
           └─10-defaults.conf
   アクティブ:月2018-09-10 17:36:35 EEST以降アクティブ 1週間3日前
    タスク:17(制限:10267)
   メモリー:616.7M

デフォルトでは、systemdが各ユーザーに許可するタスクの最大数は、「システム全体の最大数」(sysctl kernel.threads-max)の33%です。これは通常、最大10,000タスクになります。この制限を変更する場合:

  • systemd v239以降では、ユーザーのデフォルトはTasksMax =で設定されます。

    /usr/lib/systemd/system/user-.slice.d/10-defaults.conf
    

    特定のユーザー(/etc/systemd/system.controlに保存されると同時にすぐに適用されます)の制限を調整するには、次を実行します。

    systemctl [--runtime] set-property user-<uid>.slice TasksMax=<value>
    

    ユニットの設定をオーバーライドする通常のメカニズム(などsystemctl edit)もここで使用できますが、再起動が必要になります。たとえば、すべてのユーザーの制限を変更する場合は、を作成できます/etc/systemd/system/user-.slice.d/15-limits.conf

  • systemd v238以前では、ユーザーのデフォルトはUserTasksMax = inで設定され/etc/systemd/logind.confます。通常、値を変更するには再起動が必要です。

これに関する詳細:


5
また、12288プロセス(爆弾の前に既に生成されていたものを除く)は、新しいものを作成しようとする以外に何もせず、実際のシステムには影響しません。
マスト

13

とにかく、これはもはや最新のLinuxシステムをクラッシュさせません。

大量のプロセスを作成しますが、プロセスがアイドル状態になるとそれほど多くのCPUを消費しません。RAMを使い果たす前に、プロセステーブルのスロットを使い果たします。

Hkoofが指摘しているようにcgroupに制限されていない場合でも、次の変更によりシステムがダウンします。

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

5
これは、システムを「クラッシュ」させると考えるものに本当に依存します。プロセステーブルのスロットを使い果たすと、カーネルパニックを完全に引き起こさない場合でも、ほとんどの場合、システムがひざまずきます。
オースティンヘメルガーン

4
@AustinHemmelgarn:これが、賢明なシステムがルート用に最後の4つほどのプロセスIDを予約する理由です。
ジョシュア

2
プロセスが「アイドル」になるのはなぜですか?分岐した各プロセスは、より多くのプロセスを作成する無限の再帰にあります。そのため、システムコールのオーバーヘッド(fork何度も)に多くの時間を費やし、残りの時間は関数呼び出し(シェルのコールスタック内の各呼び出しにより多くのメモリを使用すると思われます)を行います。
mtraceur

4
@mtraceur:フォークが失敗し始めたときにのみ発生します。
ジョシュア

1
ああ、私はそれを取り戻します。:(){ :& :; }; :問題の代わりに、頭の中で少し異なるフォーク爆弾実装のロジックをモデリングしていました(このように:)。与えられた典型的なものの実行フローを実際に完全に考えたことはありません。
mtraceur

9

90年代に戻って、私は誤ってこれらの1つを自分で解き放ちました。fork()コマンドが含まれているCソースファイルに誤って実行ビットを設定していました。私がそれをダブルクリックしたとき、cshは私が望むようなエディターでそれを開くのではなく、それを実行しようとしました。

それでも、システムをクラッシュさせることはありませんでした。Unixは十分に堅牢であるため、アカウントやOSにはプロセス制限があります。代わりに何が起こるかは、非常に遅くなり、プロセスを開始する必要があるものはすべて失敗する可能性があります。

背後で行われているのは、プロセステーブルが新しいプロセスを作成しようとしているプロセスでいっぱいになることです。それらの1つが終了した場合(プロセステーブルがいっぱいであるためにフォークでエラーが発生したか、システムに健全性を回復しようとする必死のオペレーターが原因で)、他のプロセスの1つが新しいプロセスを幸福にフォークして充填しますボイド。

「フォーク爆弾」は、基本的に、プロセステーブルをいっぱいに保つというミッションのプロセスの意図せずに自己修復するシステムです。それを止める唯一の方法は、彼らを一度に殺すことです。


1
一度にすべてを殺すことは、あなたが考えるよりも簡単です-最初にそれらをすべてSIGSTOPしてください。
Score_Under

2
@Score_Under-最寄りのハリスナイトホークにすぐに駆けつけて問題が解決するかどうかを確認しないでください。失敗したフォークで死ぬ前に信号を送信し、別の場所に移るだけでPIDを取得するのは難しいかもしれませんが、試してみる必要があります。
TED

@TED kill -9 -1は、あなたがここにいるかもしれません(fork爆弾を実行するのと同じユーザーで、rootではない)。
アンドレアスクレイ

@AndreasKrey-そのフラグはなじみがないので、90年代のNighthawkが持っていたのではないかと疑っています。
TED

1
@TED:-1フラグではありません。kill1つのオプションのみを取り、オプションの解析を停止します。これにより-1、すべてのプロセスのエイリアスであるプロセスIDが強制終了されます。
ジョシュア
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.