24 Jul 2007

Fork bomb, or how to take down a Linux server in matter of seconds

A particular nasty local denial of service attack is a fork bomb. It's dead simple: A program just replicate itself, which again replicate itself and so on until all resources are exhausted. Fortunately, protection against fork bombs are easy - but rarely used at all.

Fork bomb? Doesn't sound familiar? To understand fork bomb, you must understand "fork()". Fork is a system call, which creates an exact copy of the running process. The new process is called "child", and the invoking process "parent". If you've taken any sort of programming class I'm sure you know all about forking. If not, you can read about it in "man 2 fork" or Wikipedias entry on fork.

To create a fork bomb, you usually make some kind of misbehaving piece of software that spawns new child processes endlessly. This can be written in any language, but a one-liner bourne shell script is perhaps the most simple one:

  #/bin/sh
  $0 &
  $0


Save this as "forkbomb.sh", execute it and see what happens. I'll bet within seconds the system is unresponsive. Here "$0" is the name of the script (forkbomb.sh) and the "&" puts the new invocation in the background. Last the script is executed a second time and this time it's in the foreground waiting for the new invocation of itself to complete (which it never does..) thus effectively holding on to resources..

You can restrict the number of processes by the built-in bash command "ulimit". Option "-u" shows/controls number of processes you're allowed to run:

  $ ulimit -u
  unlimited

Unlimited number of processes? Thats nice. Restrict it by:

  $ ulimit -u 20
  $ ulimit -u
  20

Here "20" is the maximum number of processes available to the shell and processes started by it. Try it, and you'll soon see the restriction come to play:

  $ ulimit -u 20
  $ ./forkbomb.sh
  ./forkbomb.sh: fork: Resource temporarily unavailable
  ./forkbomb.sh: fork: Resource temporarily unavailable
  ./forkbomb.sh: fork: Resource temporarily unavailable
  ....

Good. Unfortunate, we do not trust our users. So we need this setting permanent. This an be done in /etc/security/limits.conf:

  # cat /etc/security/limits.conf
  ....
  lars    hard    nproc 20

Logout and back in, to see the restriction in effect.

  $ ulimit -u
  20

And I can of course not increase the limits beyond the level set in limits.conf:

  $ ulimit -u 100
  -bash: ulimit: max user processes: cannot modify limit: Operation not permitted

But do beware - the root account (or any account with UID 0) is not bound by limits.conf.

No comments: