為什麼這些 bash fork 炸彈的工作方式不同,其中 & 的意義是什麼?
我知道普通的叉子炸彈是如何工作的,但我真的不明白為什麼需要在普通 bash 叉子炸彈末尾的 & 以及為什麼這些腳本的行為不同:
:(){ (:) | (:) }; :
和
:(){ : | :& }; :
前者在讓我回到登錄螢幕之前會導致 CPU 使用率飆升。相反,後者只會導致我的系統凍結,迫使我硬重啟。這是為什麼?兩者都在不斷創建新流程,那麼為什麼系統的行為會有所不同呢?
這兩個腳本的行為也不同於
:(){ : | : }; :
這根本不會引起任何問題,即使我希望它們是相似的。bash 手冊頁指出管道中的命令已經在子 shell 中執行,所以我相信:| : 應該已經足夠了。我相信&應該只在一個新的子shell中執行管道,但為什麼會發生如此大的變化?
編輯:使用 htop 並限制程序數量,我可以看到第一個變體創建了一個實際的程序樹,第二個變體在同一級別上創建了所有程序,最後一個變體似乎沒有創建任何程序一點也不。這讓我更加困惑,但也許它以某種方式有所幫助?
警告不要試圖在生產機器上執行它。只是不要。 警告:要嘗試任何“炸彈”,請確保
ulimit -u
正在使用中。參見下文$$ a $$.讓我們定義一個函式來獲取 PID 和日期(時間):
bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }
一個簡單的、非問題
bomb
的新使用者功能(保護自己:閱讀$$ a $$):bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2
當呼叫該函式以執行時,如下所示:
bize:~$ bomb START 0002786 23:07:34 yes END 0002786 23:07:35 bize:~$
執行命令
date
,然後列印“是”,休眠 1 秒,然後關閉命令date
,最後,函式退出列印新的命令提示符。沒有什麼花哨。| 管道
當我們這樣呼叫函式時:
bize:~$ bomb | bomb START 0003365 23:11:34 yes START 0003366 23:11:34 yes END 0003365 23:11:35 END 0003366 23:11:35 bize:~$
兩個命令同時啟動,兩個命令都將在 1 秒後結束,然後提示返回。
這就是 pipe
|
並行啟動兩個程序的原因。& 背景
如果我們更改通話添加結尾
&
:bize:~$ bomb | bomb & [1] 3380 bize:~$ START 0003379 23:14:14 yes START 0003380 23:14:14 yes END 0003379 23:14:15 END 0003380 23:14:15
提示立即返回(所有操作都發送到後台),並且兩個命令像以前一樣執行。
[1]
請注意在程序的 PID 之前列印的“作業號”的值3380
。稍後,將列印相同的數字以指示管道已結束:[1]+ Done bomb | bomb
這就是 的效果
&
。這就是
&
: 讓程序更快啟動的原因。更簡單的名字
我們可以創建一個簡單呼叫的函式
b
來執行這兩個命令。輸入三行:bize:~$ b(){ > bomb | bomb > }
並執行為:
bize:~$ b START 0003563 23:21:10 yes START 0003564 23:21:10 yes END 0003564 23:21:11 END 0003563 23:21:11
請注意,我們
;
在定義中使用了 nob
(換行符用於分隔元素)。但是,對於一行上的定義,通常使用;
,如下所示:bize:~$ b(){ bomb | bomb ; }
大多數空格也不是強制性的,我們可以寫成等價的(但不太清楚):
bize:~$ b(){ bomb|bomb;}
我們也可以使用a
&
來分隔}
(並將兩個程序發送到後台)。炸彈。
如果我們讓函式咬住它的尾巴(通過呼叫它自己),我們就會得到“叉子炸彈”:
bize:~$ b(){ b|b;} ### May look better as b(){ b | b ; } but does the same.
為了讓它更快地呼叫更多函式,請將管道發送到後台。
bize:~$ b(){ b|b&} ### Usually written as b(){ b|b& }
如果我們在 required 之後附加對函式的第一次呼叫並將
;
名稱更改為:
我們得到:bize:~$ :(){ :|:&};:
或者,以一種有趣的方式寫成,用其他名字(雪人):
☃(){ ☃|☃&};☃
ulimit(您應該在執行此之前設置)將使提示在出現大量錯誤後很快返回(當錯誤列表停止以獲取提示時按輸入鍵)。
這被稱為“分叉炸彈”的原因是外殼啟動子外殼的方式是分叉正在執行的外殼,然後使用執行命令呼叫 exec() 到分叉的程序。
管道將“分叉”兩個新程序。做到無窮遠會導致炸彈。
或者是最初被稱為兔子的兔子,因為它的繁殖速度非常快。
定時:
:(){ (:) | (:) }; time :
終止
實數 0m45.627s 2.
:(){ : | :; }; time :
終止
實0m15.283s 3.
:(){ : | :& }; time :
real 0m00.002 s
仍在執行
你的例子:
:(){ (:) | (:) }; :
第二次關閉
)
分隔 的地方}
是更複雜的:(){ :|:;};:
. 無論如何,管道中的每個命令都會在子外殼中呼叫。哪個是效果()
。 2.:(){ : | :& }; :
是更快的版本,寫成沒有空格:
:(){(:)|:&};:
(13 個字元)。 3.:(){ : | : }; :
### 在 zsh 中有效,但在 bash 中無效。有語法錯誤(在 bash 中),在結束之前需要一個元字元
}
,如下所示:
:(){ : | :; }; :
$$ a $$ 創建一個新的干淨使用者(我會打電話給我的
bize
)。在控制台中登錄這個新使用者sudo -i -u bize
,或者:$ su - bize Password: bize:~$
檢查然後更改
max user processes
限制:bize:~$ ulimit -a ### List all limits (I show only `-u`) max user processes (-u) 63931 bize:~$ ulimit -u 10 ### Low bize:~$ ulimit -a max user processes (-u) 1000
僅使用 10 個作品,因為只有一個新使用者:
bize
. 它更容易呼叫killall -u bize
並讓系統擺脫大多數(不是全部)炸彈。請不要問哪些仍然有效,我不會說。但仍然:相當低,但為了安全起見,適應你的系統。進一步閱讀: