Mengapa bom bash fork ini bekerja secara berbeda dan apa arti penting dari & di dalamnya?

16

Saya mengerti bagaimana bom fork normal berfungsi, tapi saya tidak begitu mengerti mengapa & pada akhir bom forash umum diperlukan dan mengapa skrip ini berperilaku berbeda:

:(){ (:) | (:) }; :

dan

:(){ : | :& }; :

Yang pertama menyebabkan lonjakan penggunaan cpu sebelum melemparkan saya kembali ke layar login. Yang terakhir malah menyebabkan sistem saya macet, memaksa saya untuk reboot. Mengapa demikian? Keduanya terus menerus menciptakan proses baru, jadi mengapa sistem berperilaku berbeda?

Kedua skrip juga berperilaku berbeda

:(){ : | : }; :

yang tidak menyebabkan masalah sama sekali, meskipun saya berharap mereka akan sama. Halaman manual bash menyatakan bahwa perintah dalam pipeline sudah dieksekusi dalam sebuah subshell, jadi saya dituntun untuk percaya bahwa: | : sudah cukup. Saya percaya & hanya harus menjalankan pipa dalam subkulit baru, tetapi mengapa hal itu banyak berubah?

Sunting: Menggunakan htop dan membatasi jumlah proses, saya dapat melihat bahwa varian pertama membuat pohon proses yang sebenarnya, varian kedua menciptakan semua proses pada tingkat yang sama dan varian terakhir tampaknya tidak membuat proses apa pun sama sekali. Ini lebih membingungkan saya, tapi mungkin itu bisa membantu?

Dan K.
sumber
2
saya pikir varian terakhir Anda kehilangan titik koma::(){ : | :; }; :
adonis

Jawaban:

22

PERINGATAN JANGAN MENJALANKAN INI PADA MESIN PRODUKSI. JANGAN LAKUKAN. Peringatan: Untuk mencoba "bom" apa pun pastikan ulimit -usudah digunakan. Baca di bawah [a] .

Mari kita mendefinisikan fungsi untuk mendapatkan PID dan tanggal (waktu):

bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }

Fungsi sederhana dan tidak masalah bombbagi pengguna baru (lindungi diri Anda: baca [a] ):

bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2

Ketika fungsi itu dipanggil untuk dieksekusi bekerja seperti ini:

bize:~$ bomb
  START 0002786 23:07:34
yes
    END 0002786 23:07:35
bize:~$

Perintah datedieksekusi, lalu "ya" dicetak, tidur selama 1 detik, lalu perintah penutup date, dan, akhirnya, fungsi tersebut keluar mencetak prompt perintah baru. Tidak ada yang mewah.

| pipa

Ketika kita memanggil fungsi seperti ini:

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:~$

Dua perintah memulai pada suatu waktu, kedua ujungnya 1 detik kemudian dan kemudian kembali.

Itulah alasan pipa |, untuk memulai dua proses secara paralel.

& Latar Belakang

Jika kami mengubah panggilan menambahkan akhiran &:

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

Prompt kembali segera (semua tindakan dikirim ke latar belakang) dan dua perintah dijalankan seperti sebelumnya. Harap perhatikan nilai "nomor pekerjaan" yang [1]dicetak sebelum PID proses 3380. Nantinya, nomor yang sama akan dicetak untuk menunjukkan bahwa pipa telah berakhir:

[1]+  Done                    bomb | bomb

Itulah efek dari &.

Itulah alasan &: untuk memulai proses lebih cepat.

Nama yang lebih sederhana

Kita dapat membuat fungsi yang disebut hanya buntuk menjalankan dua perintah. Diketik dalam tiga baris:

bize:~$ b(){
> bomb | bomb
> }

Dan dieksekusi sebagai:

bize:~$ b
  START 0003563 23:21:10
yes
  START 0003564 23:21:10
yes
    END 0003564 23:21:11
    END 0003563 23:21:11

Perhatikan bahwa kami tidak menggunakan ;dalam definisi b(baris baru digunakan untuk memisahkan elemen). Namun, untuk definisi pada satu baris, biasanya digunakan ;, seperti ini:

bize:~$ b(){ bomb | bomb ; }

Sebagian besar ruang juga tidak wajib, kita dapat menulis yang setara (tapi kurang jelas):

bize:~$ b(){ bomb|bomb;}

Kita juga dapat menggunakan a &untuk memisahkan }(dan mengirim dua proses ke latar belakang).

Bom.

Jika kita membuat fungsi menggigit ekornya (dengan menyebut dirinya), kita mendapatkan "bom garpu":

bize:~$ b(){ b|b;}       ### May look better as b(){ b | b ; } but does the same.

Dan untuk membuatnya memanggil lebih banyak fungsi lebih cepat, kirim pipa ke latar belakang.

bize:~$ b(){ b|b&}       ### Usually written as b(){ b|b& }

Jika kita menambahkan panggilan pertama ke fungsi setelah diperlukan ;dan mengubah nama untuk :kita dapatkan:

bize:~$ :(){ :|:&};:

Biasanya ditulis sebagai :(){ :|:& }; :

Atau, ditulis dengan cara yang menyenangkan, dengan nama lain (manusia salju):

☃(){ ☃|☃&};☃

Ulimit (yang seharusnya Anda atur sebelum menjalankan ini) akan membuat prompt kembali dengan cepat setelah banyak kesalahan (tekan enter ketika daftar kesalahan berhenti untuk mendapatkan prompt).

Alasan ini disebut "bom fork" adalah bahwa cara shell memulai sub-shell adalah dengan forking shell yang sedang berjalan dan kemudian memanggil exec () ke proses bercabang dengan perintah untuk menjalankan.

Sebuah pipa akan "bercabang" dua proses baru. Melakukannya hingga tak terbatas menyebabkan bom.
Atau kelinci seperti awalnya disebut karena mereproduksi begitu cepat.


Pengaturan waktu:

  1. :(){ (:) | (:) }; time :
    Dihentikan
    0m45.627s yang sebenarnya

  2. :(){ : | :; }; time :
    Dihentikan
    0m15.283s yang sebenarnya

  3. :(){ : | :& }; time :
    real 0m00.002 s
    Masih Berjalan


Contoh Anda:

  1. :(){ (:) | (:) }; :

    Di mana penutupan kedua )memisahkan itu }adalah versi yang lebih kompleks :(){ :|:;};:. Tiap perintah dalam pipa disebut di dalam sub-shell. Yang merupakan efek dari ().

  2. :(){ : | :& }; :

    Apakah versi yang lebih cepat, ditulis untuk tidak memiliki spasi: :(){(:)|:&};:(13 karakter).

  3. :(){ : | : }; : ### bekerja di zsh tetapi tidak di bash.

    Memiliki kesalahan sintaks (dalam bash), metacharacter diperlukan sebelum penutupan },
    karena ini:

    :(){ : | :; }; :

[a] Buat pengguna bersih baru (saya akan memanggil sayabize). Masuk ke pengguna baru ini di konsolsudo -i -u bize, atau:

$ su - bize
Password: 
bize:~$

Periksa dan kemudian ubah max user processesbatasnya:

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

Hanya menggunakan 10 karya sebagai hanya satu pengguna baru soliter: bize. Itu membuat lebih mudah untuk memanggil killall -u bizedan menyingkirkan sistem dari sebagian besar (tidak semua) bom. Tolong jangan tanya mana yang masih berfungsi, saya tidak akan memberi tahu. Tetapi tetap: Cukup rendah tetapi di sisi yang aman, beradaptasi dengan sistem Anda .
Ini akan memastikan bahwa "bom fork" tidak akan menghancurkan sistem Anda .

Bacaan lebih lanjut:

Komunitas
sumber