Где ветвление () на fork-бомбе :() {:|: и};:?

Столь же странный, как это, проблема просто исчезла. Я не коснулся файлов данных или чего-либо... Поля просто не появляются больше

26
10.07.2018, 11:00
2 ответа

В результате канала в x | y, подоболочка создается для содержания конвейера как части группы приоритетного процесса. Это продолжает создавать подоболочки (через fork()) неограниченно долго, таким образом создание 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

Ветвление на самом деле не происходит, пока код не выполняется, однако, который является заключительным вызовом : в Вашем коде.

Чтобы демонтировать, как fork-бомба работает:

  • :() - определите новую вызванную функцию :
  • { :|: & } - функциональное определение, которое рекурсивно передает функцию вызова по каналу в другой экземпляр функции вызова в фоновом режиме
  • : - вызовите функцию fork-бомбы

Это имеет тенденцию не быть слишком интенсивно использующим память, но это высосет PIDs и использует циклы ЦП.

31
27.01.2020, 19:39
  • 1
    В x | y, почему там созданная подоболочка? Для моего понимания, когда удар видит a pipe, это выполняется pipe() системный вызов, который возвращается два fds. Теперь, command_left execредактор и вывод питаются к command_right, как введено. Теперь, command_right execредактор Так, почему BASHPID отличающийся каждый раз? –  Abhijeet Rastogi 03.09.2013, 08:21
  • 2
    @shadyabhi Это просто - x и y 2 отдельных команды, работающие в 2 отдельных процессах, таким образом, у Вас есть 2 отдельных подоболочки. Если x выполнения в том же процессе как оболочка, которая означает x должно быть встроенное. –  jw013 03.09.2013, 23:59

Последний бит кода, ;: выполняет функцию :(){ ... }. Это - то, где ветвление происходит.

Точка с запятой завершает первую команду, и мы запускаем другой, т.е. вызываем функцию :. Определение этой функции включает вызов в себя (:) и вывод этого вызова передается по каналу к фоновой версии :. Это поддерживает процесс неограниченно долго.

Каждый раз Вы вызываете функцию :() Вы вызываете функцию C fork(). В конечном счете это исчерпает все идентификаторы процесса (PIDs) в системе.

Пример

Можно выгрузить |:& с чем-то еще так можно понять то, что продолжается.

Установите наблюдателя

В одном окне терминала делают это:

$ watch "ps -eaf|grep \"[s]leep 61\""

Установите "предохранитель, отложенный" fork-бомба

В другом окне мы выполним немного измененную версию fork-бомбы. Эта версия попытается отрегулировать себя так, мы можем изучить то, что она делает. Наша версия будет спать в течение 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

Иерархия процесса

И a 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
...
...

Очистите время

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

  1. Определите, в каком псевдотерминале fork-бомба собирается работать

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

    $ pkill -t pts/4
    

Таким образом, что продолжается?

Хорошо каждый вызов bash и sleep вызов к функции C fork() от bash оболочка от того, куда команда была выполнена.

24
27.01.2020, 19:39
  • 1
    bash мог бы работать на отдельных терминалах. Лучше должен был бы использовать pkill -t pts/2. –  Maciej Piechotka 31.08.2013, 22:25
  • 2
    @MaciejPiechotka - благодарит за подсказку. Никогда замечаемый, что один прежде, я добавил его к ответу! –  slm♦ 01.09.2013, 01:48

Теги

Похожие вопросы