日期:2014-05-16  浏览次数:20717 次

linux bash Shell脚本经典之Fork炸dan解析:() { :|:& };:

众所周知,bash是一款极其强大的shell,提供了强大的交互与编程功能。这样的一款shell中自然不会缺少“函数”这个元素来帮助程序进行 模块化的高效开发与管理。于是产生了由于其特殊的特性,bash拥有了fork炸dan。Jaromil在2002年设计了最为精简的一个fork炸dan的实 现。

所谓fork炸dan是一种恶意程序,它的内部是一个不断在fork进程的无限循环,fork炸dan并不需要有特别的权限即可对系统造成破坏。fork炸 弹实质是一个简单的递归程序。由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资源。现在来看看Jaromil设计的 最简单的fork炸dan:

:() { :|:& };:

或者

.() { .|.& };.

一行看似无法理解的只有13个字符的命令,即可占用掉所有系统的资源。其实,这行命令如果这样写成bash script就不难理解了:

:()
{
:|: &
}
;
:

*?第?1?行说明下面要定义一个函数,函数名为小数点,没有可选参数。
*?第?2?行表示函数体开始。
*?第?3?行是函数体真正要做的事情,首先它递归调用本函数,然后利用管道调用一个新进程(它要做的事情也是递归调用本函数),并将其放到后台执行。
*?第?4?行表示函数体结束。
*?第?5?行并不会执行什么操作,在命令行中用来分隔两个命令用。从总体来看,它表明这段程序包含两个部分,首先定义了一个函数,然后调用这个函数。
*?第?6?行表示调用本函数。

冒号”:”其实是函数名,这个bash脚本就是在不断的执行该函数,然后不断fork出新的进程。

对于函数名,大家可能会有所疑惑,小数点也能做函数名使用吗?毕竟小数点是?shell?的一个内嵌命令,用来在当前?shell?环境中读取指定 文件,并运行其中的命令。实际上的确可以,这取决于bash对命令的解释顺序。

默认情况下,bash处于非POSIX模式,此时对命令的解释顺序如下:

*?关键字,例如?if、for?等。
*?别名。别名不能与关键字相同,但是可以为关键字定义别名,例如?end=fi。
*?特 殊内嵌命令,例如?break、continue?等。POSIX?定义的特殊内嵌命令包括:.(小数点)、:(冒号)、break、continue、 eval、exec、exit、export、readonly、?return、set、shift、times、trap?和?unset。 bash?又增加了一个特殊的内嵌命令?source。
*?函数。如果处于非?POSIX?模式,bash?会优先匹配函数,然后再匹配内嵌命令。
*?非特殊内嵌命令,例如?cd、test?等。
*?脚本和可执行程序。在?PATH?环境变量指定的目录中进行搜索,返回第一个匹配项。
由 于默认情况下,bash?处于非?POSIX?模式,因此fork炸dan中的小数点会优先当成一个函数进行匹配。(注:使用小数点代替其中的冒号,也能起到完全相同的效果。)

要使用POSIX模式来运行bash脚本,可以使用以下三种方法:

*?使用?–posix?选项启动?bash。
*?在运行bash之后,执行?set?-o?posix?命令。
*?使用?/bin/sh?。

那么,有没有办法扼制这种情况的发生呢?答案是肯定的,只需设置进程的limit数即可。

[root@localhost?~]#?ulimit -u?128
[root@localhost?~]#?ulimit?-a
core?file?size??????????(blocks,?-c)?0
data?seg?size???????????(kbytes,?-d)?unlimited
max?nice????????????????????????(-e)?20
file?size???????????????(blocks,?-f)?unlimited
pending?signals?????????????????(-i)?unlimited
max?locked?memory???????(kbytes,?-l)?unlimited
max?memory?size?????????(kbytes,?-m)?unlimited
open?files??????????????????????(-n)?1024
pipe?size????????????(512?bytes,?-p)?8
POSIX?message?queues?????(bytes,?-q)?unlimited
max?rt?priority?????????????????(-r)?unlimited
stack?size??????????????(kbytes,?-s)?8192
cpu?time???????????????(seconds,?-t)?unlimited
max?user processes??????????????(-u)?128
virtual?memory??????????(kbytes,?-v)?unlimited
file?locks??????????????????????(-x)?unlimited
[root@localhost?~]#?.()?{?.|.&?}?;?.
[1]?6152
[root@localhost?~]#?bash:?fork:?Resource?temporarily?unavailable
bash:?fork:?Resource?temporarily?unavailable
bash:?fork:?Resource?temporarily?unavailable

在上面的例子中,我们将用户可以创建的最大进程数限制为?128,执行fork炸dan会迅速fork出大量进程,此后会由于资源不足而无法继续执行。使用工具ulimit即可设置各种限制数,具体的请参考该工具的man或help。

fork 炸dan让我们认识到了递归函数的强大功能,同时也意识到一旦使用不当,递归函数所造成的破坏将是巨大的。实际上,fork?炸只是一个非常简单的递归函 数,它并不涉及参数传递、返回值等问题,而这些问题在使用bash编程时是否有完善的支持呢?在bash中编写递归函数时应该注意相关问题。

关于Fork炸的详细资料请看:http://en.wikipedia.org/wiki/Fork_bomb

永久链接 : http://www.ha97.com/2618.html

http://www.path8.net/tn/archives/3570