Perché non riesco a mandare in crash il mio sistema con una bomba a forcella?


54

Recentemente ho trovato informazioni sui processi in GNU / Linux e ho incontrato la famigerata bomba a forcella:

:(){ : | :& }; :

Teoricamente, dovrebbe duplicarsi all'infinito fino a quando il sistema esaurisce le risorse ...

Tuttavia, ho provato a testare sia su una CLI Debian che su una GUI Mint distro, e non sembra avere un grande impatto sul sistema. Sì, ci sono tonnellate di processi che vengono creati e dopo un po 'ho letto nei messaggi della console come:

bash: fork: risorsa temporaneamente non disponibile

bash: fork: retry: nessun processo figlio

Ma dopo qualche tempo, tutti i processi vengono uccisi e tutto torna alla normalità. Ho letto che ulimit ha impostato una quantità massima di processo per utente, ma non riesco a sollevarlo molto lontano.

Quali sono le protezioni del sistema contro una bomba a forcella? Perché non si replica da solo fino a quando tutto si blocca o almeno resta molto indietro? C'è un modo per far davvero schiantare un sistema con una bomba a forcella?


2
Qual è il tuo PID massimo attualmente impostato?
dsstorefile1

5
Nota che non "schianterai" il tuo sistema usando una bomba a forcella ... come hai detto, esaurirai le risorse e non sarai in grado di generare nuovi processi ma il sistema non dovrebbe andare in crash
Josh

2
Cosa succede se corri :(){ :& :; }; :invece? Alla fine finiscono anche per essere uccisi tutti? Che dire :(){ while :& do :& done; }; :?
mtraceur,

Questa tua meravigliosa domanda mi ha convinto a ripensare il mio precedente voto "lasciare chiuso". Tuttavia, "I" è sempre in maiuscolo in inglese, per favore non scriverlo più male.
user259412

Risposte:


85

Probabilmente hai una distro Linux che usa systemd.

Systemd crea un cgroup per ciascun utente e tutti i processi di un utente appartengono allo stesso cgroup.

Cgroups è un meccanismo Linux per impostare limiti su risorse di sistema come il numero massimo di processi, cicli di CPU, utilizzo della RAM, ecc. Questo è un livello di risorse diverso, più moderno, che limita ulimit(che utilizza la getrlimit()syscall).

Se si esegue systemctl status user-<uid>.slice(che rappresenta il cgroup dell'utente), è possibile visualizzare il numero corrente e massimo di attività (processi e thread) consentiti all'interno di quel cgroup.

$ systemctl status user- $ UID.slice
● user-22001.slice - User Slice di UID 22001
   Caricato: caricato
  Drop-In: /usr/lib/systemd/system/user-.slice.d
           └─10-defaults.conf
   Attivo: attivo da lun 2018-09-10 17:36:35 EEST; 1 settimane 3 giorni fa
    Compiti: 17 (limite: 10267)
   Memoria: 616,7 M.

Per impostazione predefinita, il numero massimo di attività consentite da systemd per ciascun utente è del 33% del "massimo a livello di sistema" ( sysctl kernel.threads-max); questo di solito equivale a ~ 10.000 attività. Se si desidera modificare questo limite:

  • In systemd v239 e versioni successive, l'impostazione predefinita dell'utente è impostata tramite TasksMax = in:

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

    Per regolare il limite per un utente specifico (che verrà applicato immediatamente e memorizzato in /etc/systemd/system.control), eseguire:

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

    I soliti meccanismi di sostituzione delle impostazioni di un'unità (come systemctl edit) possono essere utilizzati anche qui, ma richiedono un riavvio. Ad esempio, se si desidera modificare il limite per ogni utente, è possibile creare /etc/systemd/system/user-.slice.d/15-limits.conf.

  • In systemd v238 e precedenti, l'impostazione predefinita dell'utente è impostata tramite UserTasksMax = in /etc/systemd/logind.conf. La modifica del valore richiede generalmente un riavvio.

Maggiori informazioni su questo:


5
E 12288 processi (meno quello che era già stato generato prima della bomba) non facendo altro che cercare di crearne uno nuovo, non ha alcun impatto su un sistema moderno.
Mast

13

Questo comunque non farà più andare in crash i moderni sistemi Linux.

Crea accumuli di processi ma in realtà non brucia tutta la CPU mentre i processi diventano inattivi. A questo punto si esauriscono gli slot nella tabella dei processi prima di rimanere senza RAM.

Se non sei limitato al cgroup come sottolinea Hkoof, la seguente alterazione porta comunque i sistemi in giù:

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

5
Questo dipende davvero da ciò che consideri "crash" del sistema. Se si esauriscono gli slot nella tabella dei processi, nella maggior parte dei casi un sistema si mette in ginocchio, anche se non provoca completamente il panico del kernel.
Austin Hemmelgarn,

4
@AustinHemmelgarn: Ecco perché i sistemi saggi riservano gli ultimi 4 o più id di processo per root.
Giosuè,

2
Perché i processi dovrebbero diventare "inattivi"? Ogni processo biforcuto è in una ricorsione infinita di creazione di più processi. Quindi passa molto tempo nell'overhead delle chiamate di sistema ( forkripetutamente) e il resto del suo tempo fa la chiamata di funzione (usando incrementalmente più memoria per ogni chiamata nello stack di chiamate della shell, presumibilmente).
mtraceur,

4
@mtraceur: succede solo quando il fork inizia a fallire.
Giosuè,

1
Oh, lo riprendo. Stavo modellando la logica di un'implementazione della bomba a forcella leggermente diversa nella mia testa (come questa:) :(){ :& :; }; :invece di quella nella domanda. In realtà non ho riflettuto fino in fondo attraverso il flusso esecutivo di quello archetipico dato.
mtraceur,

9

Negli anni '90 ho accidentalmente scatenato uno di questi su me stesso. Avevo inavvertitamente impostato il bit di esecuzione su un file sorgente C che conteneva un comando fork (). Quando ho fatto doppio clic su di esso, csh ha provato a eseguirlo anziché aprirlo in un editor come volevo.

Anche allora, non ha provocato l'arresto anomalo del sistema. Unix è abbastanza robusto che il tuo account e / o il tuo sistema operativo avranno un limite di processo. Quello che succede invece è che diventa super pigro e probabilmente tutto ciò che deve iniziare un processo fallirà.

Quello che sta accadendo dietro le quinte è che la tabella dei processi si riempie di processi che stanno cercando di creare nuovi processi. Se uno di essi termina (o a causa di un errore sul fork perché la tabella dei processi è piena, o a causa di un operatore disperato che tenta di ripristinare la sanità mentale nel proprio sistema), uno degli altri processi fork allegramente uno nuovo per riempire il vuoto.

La "bomba a forcella" è fondamentalmente un sistema involontariamente autoriparante di processi in missione per mantenere piena la tabella dei processi. L'unico modo per fermarlo è in qualche modo ucciderli tutti in una volta.


1
Ucciderli tutti in una volta è più facile di quanto pensi - SIGSTOP prima di tutto.
Score_Under

2
@Score_Under - Spero che mi perdonerai se non mi precipito immediatamente al mio Harris Nighthawk più vicino per vedere se ciò avrebbe risolto il problema lì. Sto pensando di ottenere un PID e di inviargli il segnale prima che muoia dal fork fallito e un altro posto potrebbe essere una sfida, ma dovrei provarlo.
TED

@TED ​​kill -9 -1 potresti essere tuo amico qui (con lo stesso utente che esegue la bomba a forcella; non con root).
Andreas Krey,

@AndreasKrey - Quella bandiera non sembra familiare, quindi dubito che Nighthawk della mia era degli anni '90 ce l'abbia.
TED

1
@TED: -1non è una bandiera. killaccetta solo un'opzione, quindi interrompe l'analisi delle opzioni. Questo uccide l'id di processo -1, che è un alias per tutti i processi.
Joshua,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.