Де вилка () на вилковій бомбі: () {: |: &};:?


25

Попередження: Виконання цієї команди в більшості оболонок призведе до порушення роботи системи, яка потребує примусового вимикання для виправлення

Я розумію рекурсивну функцію :(){ :|: & };:і те, що вона робить. Але я не знаю, куди дзвонить система вилки. Я не впевнений, але підозрюю в трубі |.


Пов'язане (і варто прочитати): Як працює вилка бомба?
terdon

Відповіді:


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 та споживати цикли процесора.


У x | yчому, чому створюється підзагін? На моє розуміння, коли bash бачить a pipe, він виконує pipe()системний виклик, який повертає два fds. Тепер команда_ліфт відредагована, execа вихід подається на команду_право як вхід. Тепер команда_права редагується exec. Отже, чому BASHPIDкожен раз відрізняється?
Abhijeet Rastogi

2
@shadyabhi Це просто - xі yце 2 окремі команди, які виконуються в 2 окремих процесах, тому у вас є 2 окремих підрозділи. Якщо він xпрацює в тому ж процесі, що і оболонка, це означає, що він xповинен бути вбудованим.
jw013

24

Останній біт коду ;:- це функція :(){ ... }. Ось тут і виникає вилка.

Точка з комою закінчується першою командою, і ми починаємо іншу, тобто викликаємо функцію :. Визначення цієї функції включає виклик до себе ( :), а вихід цього виклику передається у фонову версію :. Це підсилює процес нескінченно.

Кожен раз , коли ви викликаєте функцію :()ви викликаєте функцію C fork(). Врешті-решт це вичерпає всі ідентифікатори процесу (PID) в системі.

Приклад

Ви можете поміняти місцями на |:&щось інше, щоб мати уявлення про те, що відбувається.

Встановіть вахту

В одному вікні терміналу зробіть це:

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

Час прибирання

А killall bashзупинить справи, перш ніж вони вийдуть з-під руки. Прибирання таким чином може бути дещо важким, більш добрий спосіб, який потенційно не зможе зірвати кожногоbash шкаралупу, - це зробити наступне:

  1. Визначте, на якому псевдотерміналі збирається вилка бомба

    $ tty
    /dev/pts/4
  2. Убити псевдотермінал

    $ pkill -t pts/4

Отже, що відбувається?

Добре кожен виклик bashі sleepє викликом функції C fork()з bashоболонки, з якої була запущена команда.


7
bashможе працювати на окремих терміналах. Краще було б користуватися pkill -t pts/2.
Maciej Piechotka

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