Чому я не можу розбити свою систему з вилковою бомбою?


54

Нещодавно я розкопував інформацію про процеси в GNU / Linux і зіткнувся з сумнозвісною форк-бомбою:

:(){ : | :& }; :

Теоретично, він повинен дублювати себе нескінченно, поки у системи не вистачить ресурсів ...

Однак я спробував тестувати як на CLI Debian, так і на дистрибутив монетного двору GUI , і, схоже, це не впливає на систему. Так, створено багато процесів, і через деякий час я читаю в консольних повідомленнях на зразок:

bash: fork: ресурс тимчасово недоступний

bash: fork: retry: Ніяких дочірніх процесів

Але через деякий час всі процеси просто вбиваються і все повертається до нормального. Я читав, що ulimit встановлює максимальну кількість процесу на кожного користувача, але я, здається, не міг підняти його дійсно далеко.

Які системи захисту від вилки-бомби? Чому він не повторюється, поки все не застигне або принаймні сильно відстає? Чи є спосіб реально розбити систему з вилковою бомбою?


2
Який максимальний PID наразі встановлений?
dsstorefile1

5
Зверніть увагу , що ви не «аварії» вашої системи з допомогою вилочного бомби ... як ви сказали, ви вичерпати ресурси і не в змозі породжувати нові процеси , але система не повинна врізатися
Josh

2
Що станеться, якщо :(){ :& :; }; :замість цього ти запустиш? Чи всі вони в кінці кінців вбиваються? Про що :(){ while :& do :& done; }; :?
mtraceur

Ваше чудове запитання переконало мене переосмислити попереднє голосування "залишити закритим". Однак "Я" завжди є великими літерами англійською мовою, будь ласка, більше не пишіть його.
користувач259412

Відповіді:


86

Напевно, у вас є дистрибутив Linux, який використовує systemd.

Systemd створює групу для кожного користувача, і всі процеси користувача належать до однієї групи.

Cgroups - це механізм Linux для встановлення обмежень на системні ресурси, такі як максимальна кількість процесів, цикли процесора, використання оперативної пам’яті тощо. Це інший, більш сучасний рівень обмеження ресурсів, ніж ulimit(для якого використовується getrlimit()syscall).

Якщо ви запускаєте systemctl status user-<uid>.slice(який представляє групу користувача), ви можете побачити поточну та максимальну кількість завдань (процесів і потоків), дозволених у цій групі.

$ systemctl status user- $ UID.slice
● user-22001.slice - Користувацький фрагмент UID 22001
   Завантажений: завантажений
  Drop-In: /usr/lib/systemd/system/user-.slice.d
           └─10-defaults.conf
   Активний: активний з пн 2018-09-10 17:36:35 EEST; 1 тиждень 3 дні тому
    Завдання: 17 (ліміт: 10267)
   Пам'ять: 616,7М

За замовчуванням максимальна кількість завдань, які систематизуватиме дозволити кожному користувачеві, становить 33% від "максимуму на загальну систему" ( sysctl kernel.threads-max); зазвичай це становить ~ 10000 завдань. Якщо ви хочете змінити цей ліміт:

  • У systemd v239 та пізніших версіях за замовчуванням користувача встановлюється за допомогою TasksMax = in:

    /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.

Це створює скарбницю процесів, але насправді не записує все стільки процесора, оскільки процеси простоюють. У вас не вистачає слотів у таблиці процесів, перш ніж зараз закінчується оперативна пам'ять.

Якщо ви не обмежені у групі, як вказує Hkoof, наступна зміна все ще зводить системи:

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

5
Це дійсно залежить від того, що ви вважаєте "збоєм" системи. Вичерпання слотів у таблиці процесів призведе до того, що в більшості випадків система встане на коліна, навіть якщо це не спричинить повністю паніку ядра.
Остін Хеммельгарн

4
@AustinHemmelgarn: Ось чому мудрі системи зарезервують останні 4 або більше обробних ідентифікаторів для root.
Джошуа

2
Чому процеси йдуть «простоюючими»? Кожен роздвоєний процес знаходиться в нескінченній рекурсії, створюючи більше процесів. Таким чином, він витрачає багато часу на накладні виклики системного виклику ( forkзнову і знову), а інший час проводить функціональний виклик (припустимо, використовуючи більше пам'яті для кожного виклику в стеку виклику оболонки, імовірно).
mtraceur

4
@mtraceur: Це відбувається лише тоді, коли розгортання починає виходити з ладу.
Джошуа

1
О, я беру це назад. Я моделював логіку дещо іншої реалізації вилки бомби в моїй голові (як ось це :(){ :& :; }; ::) замість тієї, що йдеться у питанні. Я насправді не повністю продумав потік архетипічного, як дано.
mtraceur

9

Ще в 90-х я випадково розв’язав один із них на собі. Я ненароком встановив біт виконання на вихідний файл C, який мав у ньому команду fork (). Коли я двічі клацнув його, csh намагався запустити його, а не відкривати його в редакторі, як я хотів.

Вже тоді це не зірвало систему. Unix є достатньо надійним, щоб ваш обліковий запис та / або ОС мали обмеження на процес. Замість цього відбувається надзвичайно мляво, і все, що потрібно для запуску процесу, швидше за все, не вдасться.

Що відбувається за лаштунками, це те, що таблиця процесів заповнює процеси, які намагаються створити нові процеси. Якщо один із них припиняється (або через отримання помилки на вилці, оскільки таблиця процесів повна, або через відчайдушного оператора, який намагається відновити розумність в їхній системі), один з інших процесів із задоволенням викличе новий, щоб заповнити порожнеча.

"Бомба з вилкою" - це, по суті, ненавмисне саморемонтуюча система процесів під час місії з метою наповнення вашої таблиці процесів. Єдиний спосіб зупинити це - якось вбити їх усіх одразу.


1
Вбити їх одразу простіше, ніж ви думаєте - СИГСТОПУЙТЕ їх усіх спочатку.
Score_Under

2
@Score_Under - Я сподіваюся, що ви пробачте мене, якщо я негайно не спішу до мого найближчого Харріса Нічхаука, щоб побачити, чи це вирішить проблему там. Я думаю, що просто отримати PID, який надсилає йому сигнал, перш ніж він помре від невдалої вилки, а інша займає це місце, може бути проблемою, але мені доведеться спробувати це.
ТЕД

@TED ​​kill -9 -1 може бути вашим другом тут (з тим самим користувачем, який запускає вилкову бомбу; а не з root).
Андреас Крей

@AndreasKrey - Цей прапор не виглядає знайомим, тому я сумніваюся, що його було у Nighthawk 90-х років.
ТЕД

1
@TED: -1це не прапор. killбере лише один варіант, а потім зупиняє аналіз параметрів. Це вбиває ідентифікатор процесу -1, який є псевдонімом для всіх процесів.
Джошуа
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.