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

ste*_*ehr 4 bash fork background-process

我得到了这个常见版本的一般概念

:(){ :|:& };:
Run Code Online (Sandbox Code Playgroud)

bash fork炸弹的工作原理.

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

#!/bin/bash
$0 &
$0 &
Run Code Online (Sandbox Code Playgroud)

维基百科的叉炸弹文章SO回答我上面提到的原始叉炸弹问题的封闭副本.

我正在寻找解释第二种(可能不常见的)叉式炸弹的工作方式.我已经用我目前对其作用的理解对下面的代码进行了评论,但我并没有真正了解它是如何以其他版本的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.
Run Code Online (Sandbox Code Playgroud)

编辑:我对脚本的修改理解(至少在目前我担心的抽象层次上)以评论代码的形式出现.我已经将我原来的评论代码留给了未来的观众,他们可能会遇到我最初的误解.假设脚本存在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.
Run Code Online (Sandbox Code Playgroud)

sar*_*old 6

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

#!/bin/bash
$0
Run Code Online (Sandbox Code Playgroud)

这个炸弹将一遍又一遍地生成一个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
Run Code Online (Sandbox Code Playgroud)

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

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

1
 2
  3
   4
    5
     6
Run Code Online (Sandbox Code Playgroud)

如果添加&到命令的结尾,你会看到,老的可以最终获得计划和死亡.新的形式同样快速,因此这会导致相当大的流失,并有助于减少在生成最大进程数时它刚刚结束的可能性.树看起来更像是这样的:

1
 2
  3

    5
     6

       8
Run Code Online (Sandbox Code Playgroud)

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

           1
        2     3
      4   5 6   7
Run Code Online (Sandbox Code Playgroud)

除了它可能不会这么好 - 第二个过程可能会开始第三个过程,而不是第一个过程开始第三个过程.它可能看起来很混乱.

总的来说,每个"层"都会使前一层的大小加倍,但execve(2)只能经常调用 - 诀窍是这个炸弹可能会比更简单的炸弹强制进行更多的进程上下文切换,以及所有那些TLB刷新将对系统的性能产生重大影响.由于父母将主要执行随机两个孩子后死去,init(8)会有远远多个进程重新父.所有这些都会增加发送到init(8)清理的信号数量,这将使管理员更难登录并解决问题.