Чому ці бомбовидні бомби працюють по-різному і яке значення & в ньому?


16

Я розумію, як працює звичайна вилка бомба, але я не дуже розумію, для чого потрібна & в кінці загальної бомби вилка бомба і чому ці сценарії поводяться по-різному:

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

і

:(){ : | :& }; :

Перший викликає сплеск використання процесора перед тим, як повернути мене на екран входу. Останній натомість просто змушує мою систему замерзнути, примушуючи мене до жорсткої перезавантаження. Чому так? Обидва постійно створюють нові процеси, то чому система поводиться по-різному?

Обидва сценарії також ведуть себе по-різному

:(){ : | : }; :

що взагалі не викликає проблем, хоча я б очікував, що вони будуть однакові. На сторінці керівництва bash зазначено, що команди в конвеєрі вже виконуються в нижній частині корпусу, тому мене припускають вважати, що: | : повинно вже вистачити Я вірю і повинен просто запустити конвеєр в нову підпалію, але чому це так сильно змінюється?

Редагувати: Використовуючи htop та обмежуючи кількість процесів, я зміг побачити, що перший варіант створює фактичне дерево процесів, другий варіант створює всі процеси на одному рівні, а останній варіант, здається, не створює жодних процесів зовсім. Це ще більше бентежить мене, але, можливо, це якось допомагає?


2
Я думаю, що в вашому останньому варіанті відсутня крапка з комою::(){ : | :; }; :
adonis

Відповіді:


22

ПОПЕРЕДЖЕННЯ НЕ намагайтеся запустити це на виробничій машині. ПЕРЕГО НЕ ДАЙТЕ. Попередження: Щоб спробувати будь-які "бомби", переконайтеся, що 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виконується, потім друкується "так", спляча протягом 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для виконання двох команд. Введено у три рядки:

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

Зауважте, що ми не використовували ;у визначенні b(нові рядки використовувались для розділення елементів). Однак для визначення в одному рядку зазвичай використовується ;таке:

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:~$ :(){ :|:&};:

Зазвичай пишеться як :(){ :|:& }; :

Або, написане на приємний спосіб, з якоюсь іншою назвою (сніговик):

☃(){ ☃|☃&};☃

Уліміт (який слід було встановити перед запуском цього) зробить швидке повернення досить швидко після багатьох помилок (натисніть клавішу Enter, коли список помилок припиниться, щоб отримати підказку).

Причина цього називається "вилковою бомбою" полягає в тому, що спосіб, за допомогою якого оболонка запускає під оболонку, полягає в тому, щоб розпалювати запущену оболонку, а потім викликати exec () в процес розщеплення з командою для запуску.

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


Час виконання:

  1. :(){ (:) | (:) }; time :
    Припинено
    реальні 0м45.627с

  2. :(){ : | :; }; time :
    Припинено
    реальні 0м15,283с

  3. :(){ : | :& }; time :
    реальний 0m00.002 s
    все ще працює


Ваші приклади:

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

    Там, де друге закриття )відокремлює, }є більш складною версією :(){ :|:;};:. Кожна команда в трубі так чи інакше викликається всередині підколі. Який ефект від ().

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

    Більш швидка версія, написана без пробілів: :(){(:)|:&};:(13 символів).

  3. :(){ : | : }; : ### працює в zsh, але не в bash.

    Має синтаксичну помилку (в bash), метахарактер потрібен перед закриттям },
    як це:

    :(){ : | :; }; :

[a] Створіть нового чистого користувача (я зателефоную моєму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 робіт , як це тільки один одинокий новий користувач: bize. Це спрощує виклик killall -u bizeта позбавлення системи від більшості (не всіх) бомб. Будь ласка, не питайте, які з них ще працюють, я не розповім. Але все-таки: досить низький, але з безпечного боку, адаптуйтеся до вашої системи .
Це забезпечить, що "вилка бомба" не розвалить вашу систему .

Подальше читання:

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