Ваше понимание довольно точное. Оболочка использует системный вызов clone ()
для создания нового процесса. На странице руководства описывается его отличие от fork ()
:
В отличие от fork (2), clone () позволяет дочернему процессу делиться частями своего контекста выполнения с вызывающим процессом, например как пространство памяти, таблица дескрипторов файлов и таблица обработчиков сигналов. (Обратите внимание, что на этой странице руководства «вызывающий процесс» обычно соответствует «родительскому процессу».
Затем он использует системный вызов execve ()
для замены текущий образ дочернего процесса с новым образом процесса. Этот системный вызов заставляет процесс запускать код вашей программы.
Когда процесс разветвляет файлы, дескрипторы родительского процесса копируются. Из разветвления (2 )
справочная страница:
Дочерний элемент наследует копии родительского набора дескрипторов открытых файлов.
Каждый дескриптор файла в дочернем элементе ссылается на одно и то же описание открытого файла ( см. open (2)) как соответствующий дескриптор файла в родительском элементе. Это означает, что два дескриптора совместно используют флаги состояния открытого файла , текущее смещение файла и управляемые сигналами атрибуты ввода-вывода { {1}} (см. Описание F_SETOWN и F_SETSIG в fcntl (2)).
Вот почему текст отображается в вашем терминале, когда программа записывает в stdout. Вы можете увидеть этот процесс, используя str Программа ace
в Linux. Вот основные отрывки из выполнения strace
в процессе bash в Linux и выполнения / bin / echo foo
внутри оболочки.
21:32:20 clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f3f419f19d0) = 32036
Process 32036 attached
[pid 32017] 21:32:20 wait4(-1, <unfinished ...>
[pid 32036] 21:32:20 execve("/bin/echo", ["/bin/echo", "foo"], ["XDG_VTNR=8", "KDE_MULTIHEAD=false", "XDG_SESSION_ID=5512", "SSH_AGENT_PID=30259", "DM_CONTROL=/var/run/xdmctl", "TERM=xterm", "SHELL=/bin/bash", "XDM_MANAGED=method=classic", "XDG_SESSION_COOKIE=5c78dafb330601d94d7556bb52a6a2a6-1450467466.154128-547622992", "HISTSIZE=50000", "KONSOLE_DBUS_SERVICE=:1.160", "GTK2_RC_FILES=/etc/gtk-2.0/gtkrc:/home/jordan/.gtkrc-2.0:/home/jordan/.kde/share/config/gtkrc-2.0", "KONSOLE_PROFILE_NAME=Shell", "GTK_RC_FILES=/etc/gtk/gtkrc:/home/jordan/.gtkrc:/home/jordan/.kde/share/config/gtkrc", "GS_LIB=/home/jordan/.fonts", "WINDOWID=92274714", "SHELL_SESSION_ID=5b72a0038b0c4000a9299cae82f340a2", "KDE_FULL_SESSION=true", "USER=jordan", "SSH_AUTH_SOCK=/tmp/ssh-JEjo6RVmNhvR/agent.30205", "SESSION_MANAGER=local/tesla:@/tmp/.ICE-unix/30329,unix/tesla:/tmp/.ICE-unix/30329", "PATH=/home/jordan/.gem/ruby/1.9.1/bin:/home/jordan/.gem/ruby/1.9.1/bin:/home/jordan/bin:/home/jordan/local/packer:/home/jordan/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/sbin:/usr/local/sbin:/usr/sbin:/home/jordan/.rvm/bin:/home/jordan/prog/go/bin:/home/jordan/.rvm/bin:/home/jordan/prog/go/bin", "DESKTOP_SESSION=kde-plasma", "PWD=/home/jordan/games", "WORKING=/home/jordan/prog/greenspan", "KONSOLE_DBUS_WINDOW=/Windows/1", "EDITOR=emacs -nw", "LANG=en_US.UTF-8", "KDE_SESSION_UID=1000", "PS1=\\[\\033[01;32m\\]\\u@\\h\\[\\033[01;34m\\] \\w\\[\\033[1;31m\\]$(__git_ps1)\\[\\033[01;34m\\] \\$\\[\\033[00m\\] ", "KONSOLE_DBUS_SESSION=/Sessions/1", "SHLVL=2", "XDG_SEAT=seat0", "COLORFGBG=15;0", "HOME=/home/jordan", "LANGUAGE=", "KDE_SESSION_VERSION=4", "GOROOT=/home/jordan/local/go", "XCURSOR_THEME=oxy-zion", "LOGNAME=jordan", "DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-onouV6Cc66,guid=bcdceeabe7aa00a28d55899f5674608a", "XDG_DATA_DIRS=/usr/share:/usr/share:/usr/local/share", "GOPATH=/home/jordan/prog/go", "PROMPT_COMMAND=history -a", "WINDOWPATH=8", "DISPLAY=:0", "XDG_RUNTIME_DIR=/run/user/1000", "PROFILEHOME=", "QT_PLUGIN_PATH=/home/jordan/.kde/lib/kde4/plugins/:/usr/lib/kde4/plugins/", "XDG_CURRENT_DESKTOP=KDE", "HISTTIMEFORMAT=%F %T: ", "_=/bin/echo"]) = 0
[pid 32036] 21:32:20 write(1, "foo\n", 4) = 4
[pid 32036] 21:32:20 exit_group(0) = ?
[pid 32036] 21:32:20 +++ exited with 0 +++
21:32:20 <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED|WCONTINUED, NULL) = 32036
Вы не можете использовать псевдоним для форк-бомбы, потому что это недействительный псевдоним:
$ alias ':(){ :|:& };:'='echo fork bomb averted'
bash: alias: `:(){ :|:& };:': invalid alias name
The characters ‘/’, ‘$’, ‘`’, ‘=’ and any of the shell metacharacters or quoting characters listed above may not appear in an alias name.
Некоторые оболочки проверяют псевдонимы не при их объявлении, а при интерпретации команд и затем пропускают недопустимое имя. Форк-бомба всегда будет включать &
, который не может быть включен в действительный псевдоним, поэтому защитить себя таким образом невозможно.
Дважды, нет.
Это не единственный способ написать вилку -бомбу.
Есть также несколько способов выполнить «команду», когда есть псевдоним:
command the-command
\the-command
Пример:
$ alias ls=not-really-ls
$ ls
-bash: not-really-ls: command not found
$ \ls
jeff.html output.png
$ command ls
jeff.html output.png
Нет. Существует слишком много способов написать форк -бомбу.
Злой форк -создатель бомб просто попытается снова с другим именем функции. Или другие переделки, пока его вилка -бомба не сработает.
Непреднамеренный создатель бомбы форка -в первую очередь не создаст каноническую бомбу форка -.
На самом деле довольно легко самому стать непреднамеренным -создателем бомбы. Например, вы можете просто использовать рекурсивный make
с внешним, непроверенным cd
, комбинируя его с опцией -j
и не -существующими подкаталогами --— реальный пример, на который я однажды наткнулся.
Вы не можете защититься от всех возможностей, и уж точно не от решительно настроенного злоумышленника. Все, чего вы добьетесь, это увеличить сложность вашей системы.