Sebagai hasil dari pipa di x | y
, sebuah subkulit dibuat untuk menampung pipa sebagai bagian dari grup proses latar depan. Ini terus membuat subkulit (melalui fork()
) tanpa batas, sehingga menciptakan bom fork.
$ for (( i=0; i<3; i++ )); do
> echo "$BASHPID"
> done
16907
16907
16907
$ for (( i=0; i<3; i++ )); do
> echo "$BASHPID" | cat
> done
17195
17197
17199
Garpu tidak benar-benar terjadi sampai kode dijalankan, bagaimanapun, yang merupakan pemanggilan terakhir dari :
dalam kode Anda.
Untuk membongkar cara kerja fork bomb:
:()
- tentukan fungsi baru bernama:
{ :|: & }
- definisi fungsi yang secara rekursif menyalurkan fungsi panggilan ke instance lain dari fungsi panggilan di latar belakang:
- panggil fungsi fork bomb
Ini cenderung tidak terlalu intensif memori, tetapi akan menyedot PID dan menghabiskan siklus CPU.
Bagian terakhir dari kode, ;:
sedang menjalankan fungsi :(){ ... }
. Di sinilah percabangan terjadi.
Tanda titik koma mengakhiri perintah pertama, dan kita memulai yang lain, yaitu menjalankan fungsi :
. Definisi fungsi ini mencakup panggilan ke dirinya sendiri (:
) dan output dari panggilan ini disalurkan ke versi latar belakang :
. Ini menopang proses tanpa batas.
Setiap kali Anda memanggil fungsi :()
Anda memanggil fungsi C fork()
. Pada akhirnya, ini akan menghabiskan semua ID proses (PID) pada sistem.
Contoh
Anda dapat menukar |:&
dengan sesuatu yang lain sehingga Anda bisa mendapatkan gambaran tentang apa yang terjadi.
Siapkan pengamat
Dalam satu jendela terminal lakukan ini:
$ watch "ps -eaf|grep \"[s]leep 61\""
Siapkan bom garpu "sekering tertunda"
Di jendela lain kita akan menjalankan versi fork bomb yang sedikit dimodifikasi. Versi ini akan mencoba membatasi dirinya sendiri sehingga kami dapat mempelajari apa yang dilakukannya. Versi kita akan tidur selama 61 detik sebelum memanggil fungsi :()
.
Kami juga akan melatar belakangi panggilan awal, setelah dipanggil. Ctrl + z , lalu ketik bg
.
$ :(){ sleep 61; : | : & };:
# control + z
[1]+ Stopped sleep 61
[2] 5845
$ bg
[1]+ sleep 61 &
Sekarang jika kita menjalankan jobs
perintah di jendela awal kita akan melihat ini:
$ jobs
[1]- Running sleep 61 &
[2]+ Running : | : &
Setelah beberapa menit:
$ jobs
[1]- Done sleep 61
[2]+ Done : | :
Hubungi pengamat
Sementara itu di jendela lain tempat kami menjalankan watch
:
Every 2.0s: ps -eaf|grep "[s]leep 61" Sat Aug 31 12:48:14 2013
saml 6112 6108 0 12:47 pts/2 00:00:00 sleep 61
saml 6115 6110 0 12:47 pts/2 00:00:00 sleep 61
saml 6116 6111 0 12:47 pts/2 00:00:00 sleep 61
saml 6117 6109 0 12:47 pts/2 00:00:00 sleep 61
saml 6119 6114 0 12:47 pts/2 00:00:00 sleep 61
saml 6120 6113 0 12:47 pts/2 00:00:00 sleep 61
saml 6122 6118 0 12:47 pts/2 00:00:00 sleep 61
saml 6123 6121 0 12:47 pts/2 00:00:00 sleep 61
Hierarki proses
Dan ps -auxf
menunjukkan hierarki proses ini:
$ ps -auxf
saml 6245 0.0 0.0 115184 5316 pts/2 S 12:48 0:00 bash
saml 6247 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
....
....
saml 6250 0.0 0.0 115184 5328 pts/2 S 12:48 0:00 bash
saml 6268 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
saml 6251 0.0 0.0 115184 5320 pts/2 S 12:48 0:00 bash
saml 6272 0.0 0.0 100988 468 pts/2 S 12:48 0:00 \_ sleep 61
saml 6252 0.0 0.0 115184 5324 pts/2 S 12:48 0:00 bash
saml 6269 0.0 0.0 100988 464 pts/2 S 12:48 0:00 \_ sleep 61
...
...
Waktu pembersihan
A killall bash
akan menghentikan hal-hal sebelum mereka keluar dari tangan. Melakukan pembersihan dengan cara ini mungkin sedikit berat, cara yang lebih lembut yang tidak berpotensi merobek setiap bash
shell down, akan melakukan hal berikut:
-
Tentukan terminal semu apa yang akan dijalankan oleh fork bomb
$ tty /dev/pts/4
-
Bunuh terminal semu
$ pkill -t pts/4
Jadi apa yang terjadi?
Baik setiap doa dari bash
dan sleep
adalah panggilan ke fungsi C fork()
dari bash
shell tempat perintah dijalankan.