Dlaczego nie mogę rozbić mojego systemu bombą widełkową?

54

Ostatnio kopałem informacje o procesach w GNU / Linux i spotkałem niesławną bombę widelcową:

:(){ : | :& }; :

Teoretycznie ma się powielać w nieskończoność, dopóki systemowi nie zabraknie zasobów ...

Jednak próbowałem przetestować zarówno Debian CLI, jak i dystrybucję GUI Mint i wydaje się, że nie ma to większego wpływu na system. Tak, powstaje mnóstwo procesów, a po chwili czytam w komunikatach konsoli, takich jak:

bash: fork: zasób tymczasowo niedostępny

bash: fork: retry: Brak procesów potomnych

Ale po pewnym czasie wszystkie procesy po prostu giną i wszystko wraca do normy. Czytałem, że ulimit ustawił maksymalną liczbę procesów na użytkownika, ale nie wydaje mi się, żeby być w stanie podnieść go naprawdę daleko.

Jakie są zabezpieczenia systemu przed bombą widełkową? Dlaczego się nie powiela, dopóki wszystko się nie zawiesi lub przynajmniej nie zostanie zbyt długo opóźnione? Czy istnieje sposób na naprawdę rozbicie systemu za pomocą bomby widelcowej?

Plancton
źródło
2
Jaki jest obecnie Twój maksymalny PID?
dsstorefile1
5
Pamiętaj, że nie „rozbicie” systemu za pomocą bomby widelcowej ... jak powiedziałeś, wyczerpiesz zasoby i nie będziesz w stanie odrodzić nowych procesów, ale system nie powinien się zawiesić
Josh
2
Co się stanie, jeśli :(){ :& :; }; :zamiast tego pobiegniesz ? Czy oni też ostatecznie zostaną zabici? Co :(){ while :& do :& done; }; :?
mtraceur
Twoje cudowne pytanie przekonało mnie do ponownego przemyślenia poprzedniego głosowania w sprawie „pozostawienia zamkniętego”. Jednak „I” jest zawsze pisane wielkimi literami po angielsku, proszę, nie pisz już więcej źle.
user259412

Odpowiedzi:

86

Prawdopodobnie masz dystrybucję Linuksa, która używa systemd.

Systemd tworzy grupę cgroup dla każdego użytkownika, a wszystkie procesy użytkownika należą do tej samej grupy cgroup.

Cgroups to mechanizm Linuksa służący do ustawiania limitów zasobów systemowych, takich jak maksymalna liczba procesów, cykli procesora, użycia pamięci RAM itp. Jest to inna, bardziej nowoczesna, warstwa ograniczająca zasoby niż ulimit(która korzysta z getrlimit()syscall).

Jeśli uruchomisz systemctl status user-<uid>.slice(która reprezentuje grupę użytkownika), możesz zobaczyć bieżącą i maksymalną liczbę zadań (procesów i wątków), które są dozwolone w tej grupie.

$ systemctl status user- $ UID.slice
● user-22001.slice - plasterek użytkownika o identyfikatorze UID 22001
   Załadowano: załadowano
  Drop-In: /usr/lib/systemd/system/user-.slice.d
           └─10-defaults.conf
   Aktywne: aktywne od Pon 2018-09-10 17:36:35 EEST; 1 tydzień 3 dni temu
    Zadania: 17 (limit: 10267)
   Pamięć: 616,7 mln

Domyślnie maksymalna liczba zadań, które systemd pozwoli na każdego użytkownika, wynosi 33% „maksimum ogólnosystemowego” ( sysctl kernel.threads-max); zwykle wynosi to około 10 000 zadań. Jeśli chcesz zmienić ten limit:

  • W systemd v239 i nowszych, domyślna wartość użytkownika jest ustawiona poprzez TasksMax = w

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

    Aby dostosować limit dla konkretnego użytkownika (który zostanie zastosowany natychmiast, a także zapisany w /etc/systemd/system.control), uruchom:

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

    systemctl editMożna tu również użyć zwykłych mechanizmów zastępowania ustawień jednostki (takich jak ), ale będą one wymagały ponownego uruchomienia. Na przykład, jeśli chcesz zmienić limit dla każdego użytkownika, możesz utworzyć /etc/systemd/system/user-.slice.d/15-limits.conf.

  • W wersji systemowej v238 i wcześniejszych domyślną wartością użytkownika jest UserTasksMax = in /etc/systemd/logind.conf. Zmiana wartości zazwyczaj wymaga ponownego uruchomienia.

Więcej informacji na ten temat:

Hkoof
źródło
5
A 12288 procesów (pomniejszonych o to, co już powstało przed bombą), nic nie robiąc oprócz próby stworzenia nowego, tak naprawdę nie wpływa na nowoczesny system.
Maszt
13

To i tak nie spowoduje awarii nowoczesnych systemów Linux.

Tworzy mnóstwo procesów, ale tak naprawdę nie spala tyle procesora, gdy procesy stają się bezczynne. Skończyło Ci się miejsce w tabeli procesów, zanim zabraknie pamięci RAM.

Jeśli nie jesteś ograniczony do grupy, jak wskazuje Hkoof, następująca zmiana nadal obniża systemy:

:(){ : | :& : | :& }; :
Jozuego
źródło
5
To naprawdę zależy od tego, co uważasz za „awarię” systemu. Wyczerpanie się gniazd w tabeli procesów w większości przypadków spowoduje, że system upadnie na kolana, nawet jeśli nie spowoduje to całkowicie paniki jądra.
Austin Hemmelgarn,
4
@AustinHemmelgarn: Właśnie dlatego mądre systemy rezerwują 4 ostatnie identyfikatory procesów dla roota.
Joshua,
2
Dlaczego procesy miałyby być „bezczynne”? Każdy rozwidlony proces podlega nieskończonej rekurencji, tworząc więcej procesów. Dlatego spędza dużo czasu w narzutu wywołania systemowego ( forkw kółko), a resztę czasu wykonuje na wywołaniu funkcji (przyrostowo zużywa więcej pamięci dla każdego wywołania w stosie wywołań powłoki, prawdopodobnie).
mtraceur
4
@mtraceur: Dzieje się tak tylko wtedy, gdy rozwidlenie zaczyna się nie udać.
Joshua,
1
Och, cofam to. Modelowałem logikę nieco innej implementacji bomby widelcowej w mojej głowie (jak to :(){ :& :; }; ::) zamiast tej w pytaniu. Właściwie nie do końca przemyślałem przepływ egzekucji tego archetypowego.
mtraceur
9

W latach 90. przypadkowo uwolniłem jeden z nich na siebie. Nieumyślnie ustawiłem bit wykonania w pliku źródłowym C, który zawierał polecenie fork (). Kiedy go dwukrotnie kliknąłem, csh próbował uruchomić go, a nie otworzyć w edytorze takim, jak chciałem.

Nawet wtedy nie spowodował awarii systemu. Unix jest na tyle solidny, że twoje konto i / lub system operacyjny będą miały limit procesów. Zamiast tego robi się bardzo powolny i wszystko, co musi rozpocząć proces, może zawieść.

Za kulisami tabela procesów zapełnia się procesami, które próbują utworzyć nowe procesy. Jeśli jeden z nich zakończy działanie (albo z powodu błędu na rozwidleniu, ponieważ tabela procesów jest pełna, albo z powodu desperackiego operatora próbującego przywrócić zdrowie psychiczne do swojego systemu), jeden z pozostałych procesów wesoło rozwiąże nowy do wypełnienia pustka.

„Bomba widełkowa” jest zasadniczo niezamierzonym samonaprawiającym się systemem procesów mających na celu utrzymanie pełnego stołu roboczego. Jedynym sposobem na powstrzymanie tego jest jakoś ich wszystkich zabić naraz.

PRZETRZĄSAĆ
źródło
1
Zabicie ich wszystkich naraz jest łatwiejsze niż myślisz - najpierw SIGSTOP je wszystkie.
Score_Under
2
@Score_Under - Mam nadzieję, że mi wybaczysz, jeśli nie od razu wybiegnę do mojego najbliższego Harrisa Nighthawka, aby sprawdzić, czy to rozwiązałoby problem. Myślę, że dostanie PID i wysłanie mu sygnału, zanim umrze z nieudanego rozwidlenia, a inne zajęcie go może być wyzwaniem, ale musiałbym go wypróbować.
TED,
@ TED kill -9 -1 może być twoim przyjacielem tutaj (z tym samym użytkownikiem, który uruchamia bombę wideł; nie z rootem).
Andreas Krey,
@AndreasKrey - Ta flaga nie wygląda znajomo, więc wątpię, by Nighthawk z lat 90. ją miał.
TED,
1
@TED: -1nie jest flagą. killbierze tylko jedną opcję, a następnie zatrzymuje opcje analizy. To zabija identyfikator procesu -1, który jest aliasem dla wszystkich procesów.
Joshua