Bagaimana tepatnya shell khas “fork bomb” menyebut dirinya dua kali?


15

Setelah melalui pertanyaan-pertanyaan terkenal tentang Bom Bom di Askubuntu dan banyak situs Stack Exchange lainnya, saya tidak begitu mengerti apa yang dikatakan semua orang seperti itu sudah jelas.

Banyak jawaban ( contoh terbaik ) mengatakan ini:

" {:|: &}Berarti jalankan fungsi :dan kirim outputnya ke :fungsi lagi"

Nah, sebenarnya apa outputnya :? Apa yang diteruskan ke yang lain :?

Dan juga:

Pada dasarnya Anda membuat fungsi yang memanggil dirinya sendiri dua kali setiap panggilan dan tidak memiliki cara untuk mengakhiri sendiri.

Bagaimana tepatnya itu dieksekusi dua kali ? Menurut pendapat saya, tidak ada yang diteruskan ke yang kedua :sampai yang pertama :selesai eksekusi, yang sebenarnya tidak akan pernah berakhir.

Sebagai Ccontoh,

foo()
{
    foo();
    foo(); // never executed 
}

yang kedua foo()tidak dieksekusi sama sekali, hanya karena yang pertama foo()tidak pernah berakhir.

Saya berpikir bahwa logika yang sama berlaku untuk :(){ :|: & };:dan

:(){ : & };:

melakukan pekerjaan yang sama dengan

:(){ :|: & };:

Tolong bantu saya memahami logikanya.


9
Perintah dalam pipa berjalan secara paralel, di :|:, yang kedua :tidak perlu menunggu yang pertama selesai.
cuonglm

Jawaban:


26

Perpipaan tidak mengharuskan instance pertama selesai sebelum yang lain dimulai. Sebenarnya, yang benar-benar dilakukannya adalah mengarahkan stdout dari instance pertama ke stdin yang kedua, sehingga mereka dapat berjalan secara simultan (seperti yang harus dilakukan agar bom fork berfungsi).

Nah, sebenarnya apa outputnya :? apa yang diteruskan ke yang lain :?

':' tidak menulis apa pun ke yang lain ':' instance, itu hanya mengarahkan stdout ke stdin dari instance kedua. Jika ia menulis sesuatu selama eksekusi (yang tidak akan pernah terjadi, karena ia tidak melakukan apa-apa selain forking sendiri) ia akan pergi ke stdin dari contoh lain.

Akan membantu membayangkan stdin dan stdout sebagai tumpukan:

Apa pun yang ditulis ke stdin akan ditumpuk siap ketika program memutuskan untuk membaca darinya, sementara stdout bekerja dengan cara yang sama: tumpukan Anda dapat menulis, sehingga program lain dapat membaca dari itu ketika mereka mau.

Dengan begitu mudah membayangkan situasi seperti pipa yang tidak memiliki komunikasi terjadi (dua tumpukan kosong) atau menulis dan membaca yang tidak disinkronkan.

Bagaimana tepatnya itu dieksekusi dua kali? Menurut pendapat saya, tidak ada yang diteruskan ke yang kedua :sampai yang pertama :selesai eksekusi, yang sebenarnya tidak akan pernah berakhir.

Karena kita hanya mengarahkan input dan output dari instance, tidak ada persyaratan untuk instance pertama selesai sebelum yang kedua dimulai. Sebenarnya biasanya diinginkan bahwa keduanya berjalan secara bersamaan sehingga yang kedua dapat bekerja dengan data yang diuraikan oleh yang pertama dengan cepat. Itulah yang terjadi di sini, keduanya akan dipanggil tanpa perlu menunggu yang pertama selesai. Itu berlaku untuk semua jalur rantai pipa perintah.

Saya berpikir bahwa logika yang sama berlaku untuk: () {: |: &} ;: dan

:(){ : & };:

Apakah pekerjaan yang sama dengan

:(){ :|: & };:

Yang pertama tidak akan berfungsi, karena meskipun berjalan sendiri secara rekursif, fungsinya dipanggil di latar belakang ( : &). Yang pertama :tidak menunggu sampai "anak" :kembali sebelum mengakhiri sendiri, jadi pada akhirnya Anda mungkin hanya memiliki satu contoh :berjalan. Jika Anda memilikinya :(){ : };:akan berhasil, karena yang pertama :akan menunggu "anak" :untuk kembali, yang akan menunggu "anak" sendiri :untuk kembali, dan seterusnya.

Berikut adalah bagaimana berbagai perintah akan terlihat dalam hal berapa banyak contoh akan berjalan:

:(){ : & };:

1 instance (panggilan :dan berhenti) -> 1 instance (panggilan :dan berhenti) -> 1 instance (panggilan :dan berhenti) -> 1 instance -> ...

:(){ :|: &};:

1 instance (panggilan 2 :dan berhenti) -> 2 instance (masing-masing panggilan 2 :dan berhenti) -> 4 instance (masing-masing panggilan 2 :dan berhenti) -> 8 instance -> ...

:(){ : };:

1 instance (memanggil :dan menunggu untuk kembali) -> 2 instance (child memanggil yang lain :dan menunggu untuk kembali) -> 3 instance (child memanggil yang lain :dan menunggu sampai kembali) -> 4 instance -> ...

:(){ :|: };:

1 instance (memanggil 2 :'s dan menunggu mereka kembali) -> 3 instance (anak-anak memanggil 2 :masing-masing dan menunggu mereka kembali) -> 7 instance (anak-anak memanggil :masing-masing 2 dan menunggu mereka kembali) -> 15 instance -> ...

Seperti yang Anda lihat, memanggil fungsi di latar belakang (menggunakan &) sebenarnya memperlambat bom fork, karena callee akan berhenti sebelum fungsi yang dipanggil kembali.


Pertanyaan. Apakah :(){ : & && : &}; :juga berfungsi sebagai bom fork? Anda juga akan meningkat secara eksponensial, dan, pada kenyataannya, Anda dapat menempatkan banyak : &di sana untuk meningkatkannya lebih cepat.
JFA

@JFA `─> $: () {: & &&: &}; : `memberikan kesalahan sintaksis bash: syntax error near unexpected token &&' . Anda dapat melakukan ini: :(){ $(: &) && $(: &)}; :Tapi sekali lagi, tidak seperti pipa, itu tidak akan berjalan paralel. Yang akan setara dengan :(){: & };:. Ingin memverifikasi? coba ini time $( $(sleep 1 & ) && $(sleep 1 &) )dan initime $(sleep 1 | sleep 1)
Severus Tux

Tepatnya, :(){ $(: &) && $(: &)};ini adalah fungsi yang mengeluarkan operasi AND logis dalam nilai kembali dari instance pertama dan kedua. Masalahnya adalah, karena logika AND hanya benar jika kedua nilai tersebut benar, untuk efisiensi hanya instance pertama yang akan dijalankan. Jika nilai pengembaliannya adalah 1 maka instans kedua akan berjalan. Jika Anda ingin membuat bom fork lebih cepat, saya pikir Anda bisa memasukkan lebih banyak contoh ke dalam rantai, seperti:(){ :|:|: &}; :
IanC

Sama seperti catatan tambahan, banyak skrip menggunakan perilaku AND ini dalam situasi berikut: Katakan Anda ingin menjalankan prog2 jika prog1 mengembalikan true (yang dalam bash adalah 0). Alih-alih melakukan if-statement ( if [ prog1 ]; then; prog2; fi) Anda bisa menulis ( prog1 && prog2), dan prog2 hanya akan berjalan jika nilai kembalinya prog1 benar.
IanC

Ok, ini semua poin bagus. Saya biasa &&menelepon apt-get update && apt-get upgrade, dan &pada akhir baris untuk menjalankan di latar belakang, tapi itu bagus bahwa mereka tidak akan bekerja bersama. Tanda titik koma juga tidak berfungsi dengan ampersand.
JFA
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.