Fork Bomb in Linux

Shavin Anjitha
7 min readSep 29, 2023

--

As the title provides some idea about what this article going to address, first we need to understand what is fork in the Linux system.

What is Fork in Linux?

Before we delve into what the fork in Linux is, first we have to understand what is a system call in the Linux system. As you already know, Linux is the world’s most popular open-source operating system that can run on mobile devices to large server systems. As with all other operating systems, there is a system call interface to request some service or resource from the kernel while we are in the user space (invocation made from user space). In order to invoke a system call (abbreviated by syscall) easily, we must have some sort of API that will allow us to wrap the actual complex system calls with much simpler and easier function invocations. The libc C library is one of the most prominent APIs that are used to achieve such a facility, and it is at the heart of Unix applications. On modern Linux systems, this libc library is provided as GNU libc, abbreviated glibc, which will come with the GNU compiler collection (gcc).

You can install the gcc compiler toolchain on Ubuntu using following steps.

First update the Ubuntu package repository using the following command.

sudo apt update

Next install the build-essential package which will include all the tools that needs to building C/C++ applications in Linux, using the following command.

sudo apt install build-essential

To gain a better understanding of the fork in Linux systems, it’s important to delve into processes. Processes are the most basic form of virtualization, representing object code in active execution as a running program. However, processes encompass more than just code, including data, resources, state, and a virtualized computer. The kernel arbitrates and manages various system resources for each process, including timers, pending signals, open files, network connections, hardware, and IPC mechanisms. Additionally, the Linux kernel provides every process with a virtualized processor and memory view, allowing the process to perceive itself as the sole controller of the system.

A process tree in the Linux system
A process tree in the Linux system

In Linux, every process is assigned a unique positive integer known as the process ID (pid). The first process is assigned pid 1, and succeeding processes are given new and unique pids. These processes are organized in a strict hierarchy called the process tree, which is rooted in the initial process known as the init process. The init process is responsible for executing system initialization routines after booting. To create new processes in Linux, the fork system call is used. When fork() is called, a copy of the calling process is generated. The original process is referred to as the parent process, while the new process is known as the child process. Once the child process is created, both processes run concurrently and execute instructions following the fork() call.

The child process almost identical to the parent process in nearly every facet, except few necessary differences:

  1. The pid of the newly allocated child process is different from that of the parent.
  2. The child’s parent pid is set to the pid of its parent process.
  3. Resources statistics are reset to zero in the child.
  4. Any pending signals are cleared and not inherited by the child.
  5. Any acquired file locks are not inherited by the child.

Let’s take a look at how we can fork a process using the libc C API library.

#include <sys/typed.h>
#include <unistd.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
pid_t pid;
// clone the current process using the fork()
pid = fork();

if (pid > 0) // returned to the parent process
{
printf("In the parent process\n");
}
else if (pid == 0) // returned to the child process
{
printf("In the child process\n");
}
else // failed to duplicate the current process
{
perror("error in fork");
}
}

After you compile and run above code snippet on of the following output will be print in the shell.

1.

In the parent process
In the child process

2.

In the child process
In the parent process

3.

error in fork

Let’s understand what going on under the hood briefly.

Initially, there is only one process running in our context. However, when we use the fork() system call, the kernel may either create a copy of the current process, or fail to clone it, resulting in a negative pid value.

In case the kernel returns a negative value, output 3 will indicate that the process duplication has failed. When the duplication is successful, two return values will be generated, one for the parent process and one for the child process. Following the fork process, two processes will run concurrently and independently in the background, with execution proceeding to the next instruction after the fork system call. If the parent process is returned first by the system, a positive value will be displayed indicating the child process’s pid. Then, the child process will be returned with a pid value of zero.

If the child process executes before the parent process, the output will be 1 according to the if-else logic; vice versa for the opposite order.

Parent and child process flow in the background after fork()

Let’s look at the following code.

#include <unistd.h>
#include <stdio.h>

int main(int argc, char* argv[])
{
fork();
fork();
fork();

printf("Hello\n");
}

Output

Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello

As you can see, ‘Hello’ is printed 8 times in the terminal. The number of times ‘Hello’ is printed is equal to the number of processes created.

After invoking fork() for the first time, two identical processes are created, both of which will execute the next instruction after the fork system call. These two processes then each create two more processes via fork(), resulting in a total of four identical processes. This same procedure results in a total of eight identical processes. Ultimately, all of these processes will print “Hello” to the terminal.

We can calculate the number of processes created using this expression.

Number of processes = 2 ^ n, where n is number of fork system calls.

process tree created by above c code snippet

What is Fork Bomb Then?

A Fork Bomb, also known as the Rabbit Virus, is a type of program that can cause a system to crash due to a lack of memory. This program continuously forks processes until the memory is filled, resulting in a denial-of-service (DoS) attack against Linux-based systems. Once activated, the Fork Bomb cannot be stopped without rebooting the entire system, which destroys all instances of the program. During an attack, self-replicating child processes consume system resources, preventing legitimate programs from running and creating new processes. User inputs are ignored, effectively locking the system. Eventually, the kernel will run into a “kernel panic” situation.

Here the simple C code snippet for Fork bomb.

#include <unistd.h>

int main(int argc, char* argv[])
{
while (1)
{
fork();
}
}

There is also a bash script for the same task.

:(){ :|: & };:

Note: Please don’t run this command unless you are prepared for a system crash and force rebooting.

If a fork bomb is triggered on a system, it will use up the CPU time for the forking process and overload the operating system’s process table. Since the forked processes are identical copies of the original program, they will endlessly duplicate themselves within their own version of the infinite loop, causing the number of processes to grow exponentially. This can be particularly problematic for modern Unix systems, which typically use a copy-on-write resource management strategy when forking processes. Ultimately, a fork bomb can overwhelm a system’s memory.

How to avoid Fork Bomb?

A straightforward method to prevent a fork bomb is to refrain from using the fork statement in any code that could result in an infinite loop. Additionally, to mitigate the impact of a fork bomb, it is advisable to restrict the maximum number of processes that a single user can possess. On a Linux system, this can be accomplished by utilizing the ulimit tool. To limit the number of processes that a single user can own, the following command can be implemented:

ulimit -u 500

If you want to limit number of processes for a specific user, you have to update the user configuration file using following command:

sudo nano /etc/security/limits.conf

Add the following line at very end of the file:

<user_name> hard nproc 1000

Next save the file and reboot the system to apply changes.

Conclusion

In the Linux operating system, the fork system call is crucial for managing and creating processes. When a process uses the fork() function, it makes a copy of itself and creates a parent-child connection between them. However, incorrect usage of fork() can lead to a dangerous program called a Fork Bomb. This program generates an excessive number of new processes, leading to resource depletion and instability in the system. To prevent this risk, it is essential to handle fork() with care and limit the number of processes a user can have.

--

--

Shavin Anjitha

Undergraduate at UoM | Computer Science and Engineering