这个其他版本的bash fork炸弹是如何工作的?

时间:2011-12-06 01:57:21

标签: bash fork background-process

我对this common version

的概念有了全面的了解
:(){ :|:& };:
bash fork炸弹的工作原理。

但是,我见过另一个版本(特别是针对bash)

#!/bin/bash
$0 &
$0 &

Wikipedia fork bomb article以及我上面提到的原始叉炸弹问题的SO answerclosed duplicate

我正在寻找解释第二种(可能不常见的)叉式炸弹的工作方式。我已经用我目前对其作用的理解来评论下面的代码,但是我并没有真正了解它如何以其他版本的bash fork炸弹的方式实现无限递归(可能是由于我对bash的理解不足)流程和背景)。

#!/bin/bash    # Specifies the location of the executable
               # to use in executing this script.
$0 &           # Duplicates (executes a new instance
               # of) the current running process ('$0')
               # (which would be the invocation of bash used
               # to start running the script, right?)
               # and background it ('&').
$0 &           # Do the same as above, where $0 would be
               # equivalent to the initial call to bash
               # used to start the script, right? Or, would
               # it be the backgrounded call to bash from the
               # second line? I'm leaning towards the former.
编辑:我对脚本的修改理解(至少在目前我担心的抽象层次上)以评论代码的形式出现。我已经将我原来的评论代码留给了未来的观众,他们可能会遇到我最初的误解。假设脚本位于bomb.sh

#!/bin/bash    # Script will execute using /bin/bash executable.
$0 &           # The current process (P) will spawn a child process (C1)
               # by invoking the command that spawned P
               # (/bin/bash ./bomb.sh). This makes the script recursive.
               # & allows processes to run in the background
               # (allowing process death and avoiding a potential
               # process limit).
$0 &           # Process P spawns a second child process (C2), also 
               # in the background, which gives us the exponential growth
               # (in base 2) that we want per level of recursion.

3 个答案:

答案 0 :(得分:6)

如果你把这个炸弹打破一点,它可能更有意义。将其更改为:

#!/bin/bash
$0

这个炸弹将一遍又一遍地生成一个shell脚本的新副本:

$ ps auxw | grep pts/2
sarnold   2410  0.0  0.1  24840  6340 pts/2    Ss   Nov17   0:01 bash
sarnold  17280  0.0  0.0  12296  1600 pts/2    S+   18:01   0:00 /bin/bash ./bomb.sh
sarnold  17281  0.0  0.0  12296  1600 pts/2    S+   18:01   0:00 /bin/bash ./bomb.sh
sarnold  17282  0.0  0.0  12296  1600 pts/2    S+   18:01   0:00 /bin/bash ./bomb.sh
sarnold  17283  0.0  0.0  12296  1596 pts/2    S+   18:01   0:00 /bin/bash ./bomb.sh
sarnold  17284  0.0  0.0  12296  1600 pts/2    S+   18:01   0:00 /bin/bash ./bomb.sh
...
$ ps auxw | grep pts/2 | wc -l
2077

每个旧的都基本上“死了” - 等待从已执行的孩子那里获得退出状态。当然,直到其中一个被执行的孩子由于进程限制而无法执行时才会发生这种情况。 (顺便提醒我,在进行更多游戏之前,设置一个nproc rlimit可能是一个好主意。)

所以这个进程树看起来像这样:

1
 2
  3
   4
    5
     6

如果您将&添加到命令的末尾,您会看到较旧的 最终会被安排并死亡。新的形式同样快速,因此这会导致相当大的流失,并有助于减少在生成最大进程数时它只是结束的机会。树看起来更像是这样:

1
 2
  3

    5
     6

       8

添加第二个 $0 &行将导致树看起来有点不同:

           1
        2     3
      4   5 6   7

除了它可能不会这个很好 - 第二个进程可能会从第三个进程开始,而不是从第三个进程开始。它可能看起来很混乱。

每个“图层”总体上会使前一图层的尺寸加倍,但execve(2)只能经常调用 - 诀窍就是这个炸弹可能可能强制比更简单的炸弹更多的进程上下文切换,所有这些TLB刷新将显着影响系统的性能。因为父母在执行这两个孩子后基本上会随机死亡,init(8)会让更多的进程重新成为父母。所有这些都会增加发送到init(8)进行清理的信号数量,这会使管理员更难登录并解决问题。

答案 1 :(得分:2)

当您运行$0 &时,Bash会在后台运行一个运行此脚本的新进程。你开始做两次。然后每个脚本执行两次,因此第二轮实例启动四个实例。下一轮开始8,然后是16,然后是32,依此类推。

答案 2 :(得分:1)

$0是一个变量,包含用于调用此脚本的命令的第一部分:脚本的名称和位置。例如,如果您用于调用脚本的命令是/home/user/bin/bomb foo bar,则$0将包含/home/user/bin/bomb。所以$0 &表示在后台运行同一个脚本。由于它在脚本中两次,它将产生2个孩子。每个孩子都会产生2个孩子,依此类推。