Differences between revisions 9 and 10
Revision 9 as of 2008-11-22 21:59:41
Size: 2282
Editor: GreyCat
Comment: first-line
Revision 10 as of 2013-01-08 13:55:02
Size: 4744
Editor: ormaaj
Comment: Explain why : is a crappy function name.
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
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. '''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 5: Line 5:
Here is that part, but written out in normal shell coding style, rather than rammed all together: A forkbomb is a simple form of DoS named after the Unix fork(2) system call. It is a program which rapidly consumes resources by repeatedly forking itself into multiple processes, whose children do the same, recursively. This quickly renders many systems without proper resource limits in an irrecoverably unresponsive state.
Line 7: Line 7:
This particular definition of a Bash forkbomb 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:
Line 8: Line 11:
:() {
 : | : &
}
:(){ :|:& };:
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:
{{{
#!/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 {{{:}}} :
}}}

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.

`:` 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 19: Line 30:
 bomb | bomb &     bomb | bomb &
Line 21: Line 32:

bomb
Line 23: Line 36:
A more verbose explanation: 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.
Line 25: Line 38:
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. 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.
Line 27: Line 40:
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. === Why '':(){ :|:& };:'' is a bad way to define a fork bomb ===
Line 29: Line 42:
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. 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 forkbomb is a simple form of DoS named after the Unix fork(2) system call. It is a program which rapidly consumes resources by repeatedly forking itself into multiple processes, whose children do the same, recursively. This quickly renders many systems without proper resource limits in an irrecoverably unresponsive state.

This particular definition of a Bash forkbomb 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:

:() { 
    : | : &
}

:

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)