Mengapa saya tidak bisa mematikan sistem saya dengan bom fork?

54

Baru-baru ini saya telah menggali informasi tentang proses di GNU / Linux dan saya bertemu dengan bom fork yang terkenal:

:(){ : | :& }; :

Secara teoritis, seharusnya duplikat itu sendiri tak terbatas hingga sistem kehabisan sumber daya ...

Namun, saya sudah mencoba menguji baik pada CLI Debian dan distro GUI Mint , dan sepertinya tidak terlalu berdampak pada sistem. Ya ada banyak proses yang dibuat, dan setelah beberapa saat saya membaca di pesan konsol seperti:

bash: fork: Sumber daya tidak tersedia untuk sementara

bash: fork: coba lagi: Tidak ada proses anak

Tetapi setelah beberapa waktu, semua proses terbunuh dan semuanya kembali normal. Saya telah membaca bahwa ulimit menetapkan jumlah maksimum proses per pengguna, tetapi saya sepertinya tidak dapat meningkatkannya terlalu jauh.

Apa perlindungan sistem terhadap bom-garpu? Mengapa itu tidak mereplikasi dirinya sendiri sampai semuanya membeku atau setidaknya banyak tertinggal? Apakah ada cara untuk benar-benar menghancurkan sistem dengan bom fork?

Plancton
sumber
2
Untuk apa PID maks Anda saat ini diatur?
dsstorefile1
5
Perhatikan bahwa Anda tidak akan "crash" sistem Anda menggunakan bom fork ... seperti yang Anda katakan, Anda akan menghabiskan sumber daya dan tidak dapat menelurkan proses baru tetapi sistem tidak akan crash
Josh
2
Apa yang terjadi jika Anda menjalankan :(){ :& :; }; :saja? Apakah mereka semua akhirnya terbunuh pada akhirnya? Bagaimana dengan :(){ while :& do :& done; }; :?
mtraceur
Pertanyaan Anda yang luar biasa ini meyakinkan saya untuk memikirkan kembali pemungutan suara "cuti saya" sebelumnya. Namun, "Saya" selalu huruf besar dalam bahasa Inggris, tolong jangan menulisnya lagi.
user259412

Jawaban:

85

Anda mungkin memiliki distro Linux yang menggunakan systemd.

Systemd membuat cgroup untuk setiap pengguna, dan semua proses pengguna milik cgroup yang sama.

Cgroups adalah mekanisme Linux untuk menetapkan batasan pada sumber daya sistem seperti jumlah proses maksimum, siklus CPU, penggunaan RAM, dll. Ini adalah lapisan pembatas sumber daya yang berbeda, lebih modern, daripada ulimit(yang menggunakan getrlimit()syscall).

Jika Anda menjalankan systemctl status user-<uid>.slice(yang mewakili kelompok pengguna), Anda dapat melihat jumlah tugas saat ini dan maksimum (proses dan utas) yang diizinkan di dalam kelompok tersebut.

$ systemctl status user- $ UID.slice
● user-22001.slice - Bagian Pengguna dari UID 22001
   Dimuat: dimuat
  Drop-In: /usr/lib/systemd/system/user-.slice.d
           └─10-defaults.conf
   Aktif: aktif sejak Senin 2018-09-10 17:36:35 EEST; 1 minggu 3 hari yang lalu
    Tugas: 17 (batas: 10267)
   Memori: 616.7M

Secara default, jumlah maksimum tugas yang akan diizinkan systemd untuk setiap pengguna adalah 33% dari "maksimum seluruh sistem" ( sysctl kernel.threads-max); ini biasanya berjumlah ~ 10.000 tugas. Jika Anda ingin mengubah batas ini:

  • Dalam systemd v239 dan yang lebih baru, standar pengguna ditetapkan melalui TasksMax = di:

    /usr/lib/systemd/system/user-.slice.d/10-defaults.conf
    

    Untuk menyesuaikan batas untuk pengguna tertentu (yang akan diterapkan segera serta disimpan di /etc/systemd/system.control), jalankan:

    systemctl [--runtime] set-property user-<uid>.slice TasksMax=<value>
    

    Mekanisme biasa untuk menimpa pengaturan unit (seperti systemctl edit) dapat digunakan di sini juga, tetapi mereka akan membutuhkan reboot. Misalnya, jika Anda ingin mengubah batas untuk setiap pengguna, Anda dapat membuat /etc/systemd/system/user-.slice.d/15-limits.conf.

  • Dalam systemd v238 dan yang lebih lama, standar pengguna ditetapkan melalui UserTasksMax = in /etc/systemd/logind.conf. Mengubah nilai umumnya membutuhkan reboot.

Info lebih lanjut tentang ini:

Hkoof
sumber
5
Dan proses 12288 (minus apa yang sudah terjadi sebelum bom) melakukan apa-apa kecuali mencoba membuat yang baru, tidak benar-benar berdampak pada sistem modern.
Tiang
13

Ini tidak akan merusak sistem Linux modern lagi.

Ini menciptakan banyak proses tetapi tidak benar-benar membakar semua CPU sebanyak itu karena prosesnya tidak bekerja. Anda kehabisan slot di tabel proses sebelum kehabisan RAM sekarang.

Jika Anda tidak terbatas pada grup seperti yang ditunjukkan oleh Hkoof, perubahan berikut masih menurunkan sistem:

:(){ : | :& : | :& }; :
Joshua
sumber
5
Ini benar-benar tergantung pada apa yang Anda anggap 'menabrak' sistem. Kehabisan slot di tabel proses akan membuat sistem berlutut dalam banyak kasus, bahkan jika itu tidak sepenuhnya menyebabkan kepanikan kernel.
Austin Hemmelgarn
4
@AustinHemmelgarn: Itulah sebabnya sistem bijak menyimpan 4 atau lebih id proses terakhir untuk root.
Joshua
2
Mengapa prosesnya menjadi "idle"? Setiap proses bercabang adalah rekursi tak terbatas dalam menciptakan lebih banyak proses. Jadi ia menghabiskan banyak waktu di overhead panggilan sistem ( forkberulang-ulang), dan sisa waktunya melakukan panggilan fungsi (secara bertahap menggunakan lebih banyak memori untuk setiap panggilan dalam tumpukan panggilan shell, mungkin).
mtraceur
4
@traceur: Itu hanya terjadi ketika forking mulai gagal.
Yosua
1
Oh, saya ambil kembali. Saya memodelkan logika implementasi bom fork yang sedikit berbeda di kepala saya (seperti ini :(){ :& :; }; ::) daripada yang ada di pertanyaan. Saya belum benar-benar sepenuhnya memikirkan alur eksekusi dari pola dasar seperti yang diberikan.
mtraceur
9

Kembali di tahun 90-an, saya tidak sengaja melepaskan salah satu dari ini pada diri saya sendiri. Secara tidak sengaja saya telah menetapkan bit eksekusi pada file sumber C yang memiliki perintah fork () di dalamnya. Ketika saya mengklik dua kali, csh mencoba menjalankannya daripada membukanya di editor seperti yang saya inginkan.

Bahkan kemudian, itu tidak merusak sistem. Unix cukup kuat sehingga akun Anda dan / atau OS akan memiliki batas proses. Apa yang terjadi malah menjadi super lamban, dan apa pun yang perlu memulai proses cenderung gagal.

Apa yang terjadi di balik layar adalah bahwa tabel proses dipenuhi dengan proses yang mencoba membuat proses baru. Jika salah satu dari mereka berakhir (baik karena mendapatkan kesalahan pada garpu karena tabel proses penuh, atau karena operator putus asa mencoba mengembalikan kewarasan ke sistem mereka), salah satu dari proses lain akan dengan senang hati garpu yang baru untuk diisi kekosongan.

"Bom fork" pada dasarnya adalah sistem perbaikan-sendiri yang tidak disengaja dari sebuah misi untuk menjaga agar meja proses Anda tetap penuh. Satu-satunya cara untuk menghentikannya adalah entah bagaimana membunuh mereka sekaligus.

TED
sumber
1
Membunuh mereka sekaligus lebih mudah daripada yang Anda pikirkan - SIGSTOP semuanya terlebih dahulu.
Score_Under
2
@Score_Under - Saya harap Anda akan memaafkan saya jika saya tidak segera bergegas ke Harris Nighthawk terdekat untuk melihat apakah itu akan menyelesaikan masalah di sana. Saya berpikir untuk mendapatkan PID dan mengirimkannya sinyalnya sebelum mati dari garpu yang gagal dan yang lain mengambilnya mungkin merupakan tantangan, tetapi saya harus mencobanya.
TED
@TED ​​kill -9 -1 mungkin Anda teman di sini (dengan pengguna yang sama yang menjalankan bom fork; bukan dengan root).
Andreas Krey
@AndreasKrey - Bendera itu tidak terlihat familier, jadi saya ragu era 90-an saya Nighthawk memilikinya.
TED
1
@ TED: -1bukan bendera. killhanya mengambil satu opsi kemudian berhenti opsi parsing. Ini membunuh id proses -1, yang merupakan alias untuk semua proses.
Joshua