This fork bomb always reminds me of the something an AI programming teacher said on one of the first lessons I attended "To understand recursion, first you must understand recursion".
At it's core, this bomb is a recursive function. In essence, you create a function, which calls itself, which calls itself, which calls itself.... until system resources are consumed. In this specific instance, the recursion is amplified by the use of piping the function to itself AND backgrounding it.
I've seen this answered over on StackOverflow, and I think the example given there illustrates it best, just because it's easier to see what it does at a glance (stolen from the link above...)
☃(){ ☃|☃& };☃
Define the bug function ☃() { ... }
, the body of which calls itself (the bug function), piping the output to itself (the bug function) ☃|☃
, and background the result &
. Then, after the function is defined, actually call the bug function, ; ☃
.
I note that at least on my Arch VM, the need to background the process is not a requirement to have the same end result, to consume all available process space and render the host b0rked. Actually now I've said that it seems to sometimes terminate the run away process and after a screenful of -bash: fork: Resource temporarily unavailable
it will stop with a Terminated
(and journalctl
shows bash core dumping).
To answer your question about csh/tcsh, neither of those shells support functions, you can only alias. So for those shells you'd have to write a shell script which calls itself recursively.
zsh seems to suffer the same fate (with the same code), does not core dump and causes Arch to give Out of memory: Kill process 216 (zsh) score 0 or sacrifice child.
, but it still continues to fork. After a while it then states Killed process 162 (systemd-logind) ...
(and still continues to have a forking zsh).
Arch doesn't seem to have a pacman
version of ksh, so I had to try it on debian instead. ksh objects to :
as a function name, but using something - say b()
instead seems to have the desired result.
It is not something new. It dates way back to 1970's when it got introduced.
Quoting from here,
One of the earliest accounts of a fork bomb was at the University of
Washington on a Burroughs 5500 in 1969. It is described as a "hack"
named RABBITS that would make two copies of itself when it was run,
and these two would generate two more copies each, and the copies
would continue making more copies until memory was full, causing a
system crash. Q The Misanthrope wrote a Rabbit-like program using
BASIC in 1972 while in grade 7. Jerry Leichter of Yale University
describes hearing of programs similar to rabbits or fork bombs at his
Alma Mater of Princeton and says given his graduation date, they must
be from 1973 or earlier. An account dating to 1974 describes a program
actually named "rabbit" running on an IBM 360 system at a large firm
and a young employee who was discharged for running it.
So the :(){ :|:& };:
is just a way of implementing the fork bomb in shell. If you take some other programming language, you could implement in those languages as well. For instance, in python you could implement the fork bomb as,
import os
while True:
os.fork()
More ways of implementing the fork bomb in different languages can be found from the wikipedia link.
If you want to understand the syntax, it is pretty simple. A normal function in shell would look like,
foo(){
arg1=$1
arg2=$2
echo 'Bar..'
#do_something on $arg argument
}
fork()
bomb is defined as follows:
:(){
:|:&
};:
:|:
:|:
- Next it will call itself using programming technique called recursion and pipes the output to another call of the function :
. The worst part is function get called two times to bomb your system.
&
- Puts the function call in the background so child cannot die at all and start eating system resources.
;
- Terminate the function definition
:
- Call (run) the function aka set the fork() bomb.
Here is more human readable code:
bomb() {
bomb | bomb &
}; bomb
References
http://www.cyberciti.biz/faq/understanding-bash-fork-bomb/
Best Answer
How a fork bomb works: in C (or C-like) code, a function named
fork()
gets called. This causes linux or Unix or Unix-a-likes to create an entirely new process. This process has an address space, a process ID, a signal mask, open file descriptors, all manner of things that take up space in the OS kernel's somewhat limited memory. The newly created process also gets a spot in the kernel's data structure for processes to run. To the process that calledfork()
, it looks like nothing happened. A fork-bomb process will try to callfork()
as fast as it can, as many times as it can.The trick is that the newly created process also comes back from
fork()
in the same code. After a fork, you have two processes running the same code. Each new fork-bomb process tries to callfork()
as fast as it can, as many times as it can. The code you've given as an example is a Bash-script version of a fork bomb.Soon, all the OS kernel's process-related resources get used up. The process table is full. The waiting-to-run list of processes is full. Real memory is full, so paging starts. If this goes on long enough, the swap partition fills up.
What this looks like to a user: everything runs super slowly. You get error messages like "could not create process" when you try simple things like
ls
. Trying aps
causes an interminable pause (if it runs at all) and gives back a very long list of processes. Sometimes this situation requires a reboot via the power cord.Fork bombs used to be called "rabbits" back in the old days. Because they reproduced so rapidly.
Just for fun, I wrote a fork bomb program in C:
I compiled and ran that program under Arch Linux in one xterm. I another xterm I tried to get a process list:
The Z shell in the 2nd xterm could not call
fork()
successfully as the fork bomb processes associated with the 1st xterm had used up all kernel resources related to process created and running.