Differences between revisions 7 and 11 (spanning 4 versions)
Revision 7 as of 2008-11-22 14:08:28
Size: 2280
Editor: localhost
Comment: converted to 1.6 markup
Revision 11 as of 2013-01-08 18:58:36
Size: 4786
Editor: GreyCat
Comment:
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
'''This is a potentially dangerous command. Don't run it!''' The "trigger" is omitted from the question above, leaving only the part that sets up the function.
Line 4: Line 5:
First of all -- and this is important -- please do '''not''' run this command. I've actually omitted the trigger from the question above, and left only the part that sets up the function. A fork bomb is a simple form of denial of service (DoS) named after the Unix fork(2) system call. It is a program which rapidly consumes resources by repeatedly forking copies of itself, whose children do the same, recursively. On many systems without proper resource limits, this may leave you in an irrecoverably unresponsive state.
Line 6: Line 7:
Here is that part, but written out in normal shell coding style, rather than rammed all together: This particular definition of a Bash fork bomb is for some reason so well-known that it's sometimes just known as "the forkbomb".
Line 8: Line 9:
{{{:() {
 : | : &
}
Here is the code in the most common popularized format:
{{{
:(){ :|:& };:
Line 13: Line 14:
What this does is create a function named {{{:}}} which calls itself recursively. Twice. In the background. Since the function keeps calling itself over and over (forking new processes), forever, this quickly consumes a ''lot'' of system resources. That's why it's called a "fork bomb". And again, following good conventions for readability:
{{{#!highlight text numbers=disable
#!/usr/bin/env bash
:() {
    : | : &
}
Line 15: Line 21:
If you still don't see how it works, here is an equivalent, which creates a function named {{{bomb}}} instead of {{{:}}}

{{{bomb() {
 bomb | bomb &
}
:
Line 22: Line 24:
A more verbose explanation: This defines a function named `:`. The body of the function sets up a pipeline, which in Bash consists of two [[SubShell | subshells]], the stdout of the first connected to the stdin of the second by a pipe. The function (parent shell of the pipeline) backgrounds the pipeline, the function returns, and the shell terminates, leaving behind the background job. The end result is two new processes that each call `:` to repeat the process.
Line 24: Line 26:
Inside the function, a pipeline is created which forks two more instances of the function (each of which will be a whole process) in the background. Then the function exits. However, for every instance of the function which exits in this manner, two more have already been created. The result is a vast number of processes, extremely quickly. `:` is actually an illegal function name in most contexts (described below). Here, {{{bomb}}} is used instead of {{{:}}}, which is both portable and more readable.
Line 26: Line 28:
Theoretically, anybody that has shell access to your computer can use such a technique to consume all the resources to which he/she has access. A {{{chroot(2)}}} won't help here. If the user's resources are unlimited then in a matter of seconds all the resources of your system (processes, virtual memory, open files, etc.) will be used, and it will probably deadlock itself. Any attempt made by the kernel to free more resources will just allow more instances of the function to be created. {{{
bomb() {
    bomb | bomb &
}
Line 28: Line 33:
As a result, the only way to protect yourself from such abuse is by limiting the maximum allowed use of resources for your users. Such resources are governed by the {{{setrlimit(2)}}} system call. The interface to this functionality in Bash and KornShell is the {{{ulimit}}} command. Your operating system may also have special configuration files to help manage these resources (for example, {{{/etc/security/limits.conf}}} in Debian, or {{{/etc/login.conf}}} in OpenBSD). Consult your documentation for details. bomb
}}}

Theoretically, anybody that has shell access to your computer can use such a technique to consume all the resources to which he/she has access. A `chroot(2)` won't help here. If the user's resources are unlimited then in a matter of seconds all the resources of your system (processes, virtual memory, open files, etc.) will be used, and it will probably deadlock itself. Any attempt made by the kernel to free more resources will just allow more instances of the function to be created.

As a result, the only way to protect yourself from such abuse is by limiting the maximum allowed use of resources for your users. Such resources are governed by the `setrlimit(2)` system call. The interface to this functionality in Bash and KornShell is the `ulimit` command. Your operating system may also have special configuration files to help manage these resources (for example, `/etc/security/limits.conf` in Debian, or `/etc/login.conf` in OpenBSD). Consult your documentation for details.

=== Why '':(){ :|:& };:'' is a bad way to define a fork bomb ===

This popular definition works because of an unusual combination of details that (of the shells I have to test with) only occur in Bash's non-POSIX mode, and Zsh (all emulation modes).

 1. The shell must allow defining function names beyond those required by a [[http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_230 | POSIX "Name"]]. This immediately rules out ksh93, Bash POSIX mode, Dash, Posh (segfault on definition, Posh is an old pdksh fork that's no longer maintained), and Busybox sh.

 2. The shell must either:
  * Incorrectly resolve functions that overload [[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_14 | special builtins]] ahead of the builtin itself. See [[http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_09_01_01 | Command search and execution]]. mksh fails (correctly) at this step, simply executing the `:` builtin. It is impossible to call the function even if you've successfully defined it. Bash non-POSIX mode and Zsh (even POSIX emulation) meet this criteria.
  * Provide a means of disabling the builtin. Bash and Ksh93 do. Bash fails (correctly according to its documentation). Ksh93 succeeds (incorrectly according to its documentation).
  {{{
    $ bash -c 'enable -d :; type -p :'
    bash: line 0: enable: :: not dynamically loaded
    $ ksh -c 'builtin -d :; whence -v :'
    ksh: whence: :: not found
  }}}
  Probably a bug:
  {{{
  -d Deletes each of the specified built-ins. **Special built-ins cannot be deleted**.
  }}}
  In any event, it's irrelevant because ksh93 already failed at step 1. Now you just have an inaccessible builtin.

So in a nutshell, this forkbomb isn't very interesting. It's basically the canonical definition that's been trivially obfuscated by giving it a strange name that breaks almost everywhere. Ironic given the supposed [[http://digitalcraft.org/index.php?artikel_id=292 | original author's claim]] that one may
{{{
type in :(){ :|:& };: on any UNIX terminal
}}}
 -- sure, I guess you can type it.

I saw this command somewhere: :(){ :|:& } (fork bomb). How does it work?

This is a potentially dangerous command. Don't run it! The "trigger" is omitted from the question above, leaving only the part that sets up the function.

A fork bomb is a simple form of denial of service (DoS) named after the Unix fork(2) system call. It is a program which rapidly consumes resources by repeatedly forking copies of itself, whose children do the same, recursively. On many systems without proper resource limits, this may leave you in an irrecoverably unresponsive state.

This particular definition of a Bash fork bomb is for some reason so well-known that it's sometimes just known as "the forkbomb".

Here is the code in the most common popularized format:

:(){ :|:& };:

And again, following good conventions for readability:

#!/usr/bin/env bash
:() { 
    : | : &
}

:

This defines a function named :. The body of the function sets up a pipeline, which in Bash consists of two subshells, the stdout of the first connected to the stdin of the second by a pipe. The function (parent shell of the pipeline) backgrounds the pipeline, the function returns, and the shell terminates, leaving behind the background job. The end result is two new processes that each call : to repeat the process.

: is actually an illegal function name in most contexts (described below). Here, bomb is used instead of :, which is both portable and more readable.

bomb() {
    bomb | bomb &
}

bomb

Theoretically, anybody that has shell access to your computer can use such a technique to consume all the resources to which he/she has access. A chroot(2) won't help here. If the user's resources are unlimited then in a matter of seconds all the resources of your system (processes, virtual memory, open files, etc.) will be used, and it will probably deadlock itself. Any attempt made by the kernel to free more resources will just allow more instances of the function to be created.

As a result, the only way to protect yourself from such abuse is by limiting the maximum allowed use of resources for your users. Such resources are governed by the setrlimit(2) system call. The interface to this functionality in Bash and KornShell is the ulimit command. Your operating system may also have special configuration files to help manage these resources (for example, /etc/security/limits.conf in Debian, or /etc/login.conf in OpenBSD). Consult your documentation for details.

Why '':(){ :|:& };:'' is a bad way to define a fork bomb

This popular definition works because of an unusual combination of details that (of the shells I have to test with) only occur in Bash's non-POSIX mode, and Zsh (all emulation modes).

  1. The shell must allow defining function names beyond those required by a POSIX "Name". This immediately rules out ksh93, Bash POSIX mode, Dash, Posh (segfault on definition, Posh is an old pdksh fork that's no longer maintained), and Busybox sh.

  2. The shell must either:
    • Incorrectly resolve functions that overload special builtins ahead of the builtin itself. See Command search and execution. mksh fails (correctly) at this step, simply executing the : builtin. It is impossible to call the function even if you've successfully defined it. Bash non-POSIX mode and Zsh (even POSIX emulation) meet this criteria.

    • Provide a means of disabling the builtin. Bash and Ksh93 do. Bash fails (correctly according to its documentation). Ksh93 succeeds (incorrectly according to its documentation).
          $ bash -c 'enable -d :; type -p :'
          bash: line 0: enable: :: not dynamically loaded
          $ ksh -c 'builtin -d :; whence -v :'
          ksh: whence: :: not found
      Probably a bug:
        -d    Deletes each of the specified built-ins. **Special built-ins cannot be deleted**.
      In any event, it's irrelevant because ksh93 already failed at step 1. Now you just have an inaccessible builtin.

So in a nutshell, this forkbomb isn't very interesting. It's basically the canonical definition that's been trivially obfuscated by giving it a strange name that breaks almost everywhere. Ironic given the supposed original author's claim that one may

type in :(){ :|:& };: on any UNIX terminal
  • -- sure, I guess you can type it.

BashFAQ/059 (last edited 2013-01-08 18:58:36 by GreyCat)