Recently I've been digging up information about processes in GNU/Linux and I met the infamous fork bomb :

:(){ : | :& }; :

Theoretically, it is supposed to duplicate itself infinitely until the system runs out of resources...

However, I've tried testing both on a CLI Debian and a GUI Mint distro, and it doesn't seem to impact much the system. Yes there are tons of processes that are created, and after a while I read in console messages like :

bash: fork: Resource temporarily unavailable

bash: fork: retry: No child processes

But after some time, all the processes just get killed and everything goes back to normal. I've read that the ulimit set a maximum amount of process per user, but I can't seem to be able to raise it really far.

What are the system protections against a fork-bomb? Why doesn't it replicate itself until everything freezes or at least lags a lot? Is there a way to really crash a system with a fork bomb?

  • 2
    What's your max PID currently set to? – dsstorefile1 Sep 19 at 8:20
  • 5
    Note that you won’t “crash” your system using a fork bomb... as you said, you’ll exhaust resources and be unable to spawn new processes but the system shouldn’t crash – Josh Sep 19 at 14:00
  • 2
    What happens if you run :(){ :& :; }; : instead? Do they also all end up getting killed eventually? What about :(){ while :& do :& done; }; :? – mtraceur Sep 19 at 19:22
up vote 85 down vote accepted

You probably have a Linux distro that uses systemd.

Systemd creates a cgroup for each user, and all processes of a user belong to the same cgroup.

Cgroups is a Linux mechanism to set limits on system resources like max number of processes, CPU cycles, RAM usage, etc. This is a different, more modern, layer of resource limiting than ulimit (which uses the getrlimit() syscall).

If you run systemctl status user-<uid>.slice (which represents the user's cgroup), you can see the current and maximum number of tasks (processes and threads) that is allowed within that cgroup.

$ systemctl status user-$UID.slice
● user-22001.slice - User Slice of UID 22001
   Loaded: loaded
  Drop-In: /usr/lib/systemd/system/user-.slice.d
           └─10-defaults.conf
   Active: active since Mon 2018-09-10 17:36:35 EEST; 1 weeks 3 days ago
    Tasks: 17 (limit: 10267)
   Memory: 616.7M

By default, the maximum number of tasks that systemd will allow for each user is 33% of the "system-wide maximum" (sysctl kernel.threads-max); this usually amounts to ~10,000 tasks. If you want to change this limit:

  • In systemd v239 and later, the user default is set via TasksMax= in:

    /usr/lib/systemd/system/user-.slice.d/10-defaults.conf
    

    To adjust the limit for a specific user (which will be applied immediately as well as stored in /etc/systemd/system.control), run:

    systemctl [--runtime] set-property user-<uid>.slice TasksMax=<value>
    

    The usual mechanisms of overriding a unit's settings (such as systemctl edit) can be used here as well, but they will require a reboot. For example, if you want to change the limit for every user, you could create /etc/systemd/system/user-.slice.d/15-limits.conf.

  • In systemd v238 and earlier, the user default is set via UserTasksMax= in /etc/systemd/logind.conf. Changing the value generally requires a reboot.

More info about this:

  • 5
    And 12288 processes (minus what was already spawned before the bomb) doing nothing except trying to create a new one, doesn't really impact a modern system. – Mast Sep 20 at 9:55

This won't crash modern Linux systems anymore anyway.

It creates hoards of processes but doesn't really burn all that much CPU as the processes go idle. You run out of slots in the process table before running out of RAM now.

If you're not cgroup limited as Hkoof points out, the following alteration still brings systems down:

:(){ : | :& : | :& }; :
  • 5
    This really depends on what you consider 'crashing' the system. Running out of slots in the process table will bring a system to it's knees in most cases, even if it doesn't completely cause a kernel panic. – Austin Hemmelgarn Sep 19 at 19:03
  • 4
    @AustinHemmelgarn: Which is why wise systems reserve the last 4 or so process ids for root. – Joshua Sep 19 at 19:09
  • 2
    Why would the processes go "idle"? Each forked process is in an infinite recursion of creating more processes. So it spends a lot of time in system call overhead (fork over and over), and the rest of its time doing the function call (incrementally using more memory for each call in the shell's call stack, presumably). – mtraceur Sep 19 at 19:13
  • 4
    @mtraceur: It only happens when forking starts failing. – Joshua Sep 19 at 19:14
  • 1
    Oh, I take it back. I was modeling the logic of a slightly different fork bomb implementation in my head (like this: :(){ :& :; }; :) instead of the one in the question. I haven't actually fully thought through the execution flow of the archetypical one as given. – mtraceur Sep 19 at 19:18

Back in the 90's I accidentally unleashed one of these on myself. I had inadvertently set the execute bit on a C source file that had a fork() command in it. When I double-clicked it, csh tried to run it rather than open it in an editor like I wanted.

Even then, it didn't crash the system. Unix is robust enough that your account and/or the OS will have a process limit. What happens instead is it gets super sluggish, and anything that needs to start a process is likely to fail.

What's happening behind the scenes is that the process table fills up with processes that are trying to create new processes. If one of them terminates (either due to getting an error on the fork because the process table is full, or due to a desperate operator trying to restore sanity to their system), one of the other processes will merrily fork a new one to fill the void.

The "fork bomb" is basically an unintentionally self-repairing system of processes on a mission to keep your process table full. The only way to stop it is to somehow kill them all at once.

  • 1
    Killing them all at once is easier than you think - SIGSTOP them all first. – Score_Under Sep 20 at 12:49
  • 2
    @Score_Under - I hope you'll forgive me if I don't immediately rush off to my nearest Harris Nighthawk to see if that would have fixed the problem there. I'm thinking just getting a PID an sending it the signal before it dies from the failed fork and another takes it place might be a challenge, but I'd have to try it out. – T.E.D. Sep 20 at 15:37
  • @T.E.D. kill -9 -1 may be you friend here (with the same user that runs the fork bomb; not with root). – Andreas Krey Sep 21 at 11:02
  • @AndreasKrey - That flag doesn't look familiar, so I'm doubting my 90's era Nighthawk had it. – T.E.D. Sep 21 at 11:11

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.