Man pages are usually terse reference documents. Wikipedia is a better place to turn to for conceptual explanations.
Fork duplicates a process: it creates a child process which is almost identical to the parent process (the most obvious difference is that the new process has a different process ID). In particular, fork (conceptually) must copy all the parent process's memory.
As this is rather costly, vfork was invented to handle a common special case where the copy is not necessary. Often, the first thing the child process does is to load a new program image, so this is what happens:
if (fork()) {
# parent process …
} else {
# child process (with a new copy of the process memory)
execve("/bin/sh", …); # discard the process memory
}
The execve
call loads a new executable program, and this replaces the process's code and data memory by the code of the new executable and a fresh data memory. So the whole memory copy created by fork
was all for nothing.
Thus the vfork
call was invented. It does not make a copy of the memory. Therefore vfork
is cheap, but it's hard to use since you have to make sure you don't access any of the process's stack or heap space in the child process. Note that even reading could be a problem, because the parent process keeps executing. For example, this code is broken (it may or may not work depending on whether the child or the parent gets a time slice first):
if (vfork()) {
# parent process
cmd = NULL; # modify the only copy of cmd
} else {
# child process
execve("/bin/sh", "sh", "-c", cmd, (char*)NULL); # read the only copy of cmd
}
Since the invention of vfork, better optimizations have been invented. Most modern systems, including Linux, use a form of copy-on-write, where the pages in the process memory are not copied at the time of the fork
call, but later when the parent or child first writes to the page. That is, each page starts out as shared, and remains shared until either process writes to that page; the process that writes gets a new physical page (with the same virtual address). Copy-on-write makes vfork mostly useless, since fork
won't make any copy in the cases where vfork
would be usable.
Linux does retain vfork. The fork
system call must still make a copy of the process's virtual memory table, even if it doesn't copy the actual memory; vfork
doesn't even need to do this. The performance improvement is negligible in most applications.
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 called fork()
, it looks like nothing happened. A fork-bomb process will try to call fork()
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 call fork()
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 a ps
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:
#include <stdio.h>
#include <unistd.h>
int
main(int ac, char **av)
{
while (1)
fork();
return 0;
}
I compiled and ran that program under Arch Linux in one xterm. I another xterm I tried to get a process list:
1004 % ps -fu bediger
zsh: fork failed: resource temporarily unavailable
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.
Best Answer
It is not something new. It dates way back to 1970's when it got introduced.
Quoting from here,
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,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,
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:
References
http://www.cyberciti.biz/faq/understanding-bash-fork-bomb/