GNU/Linux >> Linux Esercitazione >  >> Linux

Dov'è il fork() sulla fork bomb :(){ :|:&};:?

Come risultato della pipa in x | y , viene creata una subshell per contenere la pipeline come parte del gruppo di processi in primo piano. Questo continua a creare subshell (tramite fork() ) all'infinito, creando così una fork bomb.

$ for (( i=0; i<3; i++ )); do
>     echo "$BASHPID"
> done
16907
16907
16907
$ for (( i=0; i<3; i++ )); do
>     echo "$BASHPID" | cat
> done
17195
17197
17199

Tuttavia, il fork non si verifica fino a quando il codice non viene eseguito, che è l'invocazione finale di : nel tuo codice.

Per smontare come funziona la fork bomb:

  • :() - definire una nuova funzione chiamata :
  • { :|: & } - una definizione di funzione che convoglia ricorsivamente la funzione chiamante in un'altra istanza della funzione chiamante in background
  • : - chiama la funzione fork bomb

Questo tende a non essere troppo intensivo per la memoria, ma assorbirà i PID e consumerà i cicli della CPU.


L'ultimo bit del codice, ;: sta eseguendo la funzione :(){ ... } . È qui che si verifica il fork.

Il punto e virgola termina il primo comando e ne iniziamo un altro, ovvero invocando la funzione : . La definizione di questa funzione include una chiamata a se stessa (: ) e l'output di questa chiamata viene reindirizzato a una versione in background : . Questo sostiene il processo a tempo indeterminato.

Ogni volta che chiami la funzione :() stai chiamando la funzione C fork() . Alla fine questo esaurirà tutti gli ID di processo (PID) sul sistema.

Esempio

Puoi sostituire il |:& con qualcos'altro in modo da farti un'idea di cosa sta succedendo.

Imposta un osservatore

In una finestra di terminale, fai questo:

$ watch "ps -eaf|grep \"[s]leep 61\""

Imposta la fork bomb "miccia ritardata"

In un'altra finestra eseguiremo una versione leggermente modificata della fork bomb. Questa versione tenterà di rallentare se stessa in modo da poter studiare cosa sta facendo. La nostra versione dormirà per 61 secondi prima di chiamare la funzione :() .

Inoltre, eseguiremo il background anche della chiamata iniziale, dopo che è stata richiamata. Ctrl + z , quindi digita bg .

$ :(){ sleep 61; : | : & };:

# control + z
[1]+  Stopped                 sleep 61
[2] 5845
$ bg
[1]+ sleep 61 &

Ora, se eseguiamo il file jobs comando nella finestra iniziale vedremo questo:

$ jobs
[1]-  Running                 sleep 61 &
[2]+  Running                 : | : &

Dopo un paio di minuti:

$ jobs
[1]-  Done                    sleep 61
[2]+  Done                    : | :

Controlla con l'osservatore

Nel frattempo nell'altra finestra in cui stiamo eseguendo watch :

Every 2.0s: ps -eaf|grep "[s]leep 61"                                                                                                                                             Sat Aug 31 12:48:14 2013

saml      6112  6108  0 12:47 pts/2    00:00:00 sleep 61
saml      6115  6110  0 12:47 pts/2    00:00:00 sleep 61
saml      6116  6111  0 12:47 pts/2    00:00:00 sleep 61
saml      6117  6109  0 12:47 pts/2    00:00:00 sleep 61
saml      6119  6114  0 12:47 pts/2    00:00:00 sleep 61
saml      6120  6113  0 12:47 pts/2    00:00:00 sleep 61
saml      6122  6118  0 12:47 pts/2    00:00:00 sleep 61
saml      6123  6121  0 12:47 pts/2    00:00:00 sleep 61

Gerarchia dei processi

E un ps -auxf mostra questa gerarchia di processi:

$ ps -auxf
saml      6245  0.0  0.0 115184  5316 pts/2    S    12:48   0:00 bash
saml      6247  0.0  0.0 100988   468 pts/2    S    12:48   0:00  \_ sleep 61
....
....
saml      6250  0.0  0.0 115184  5328 pts/2    S    12:48   0:00 bash
saml      6268  0.0  0.0 100988   468 pts/2    S    12:48   0:00  \_ sleep 61
saml      6251  0.0  0.0 115184  5320 pts/2    S    12:48   0:00 bash
saml      6272  0.0  0.0 100988   468 pts/2    S    12:48   0:00  \_ sleep 61
saml      6252  0.0  0.0 115184  5324 pts/2    S    12:48   0:00 bash
saml      6269  0.0  0.0 100988   464 pts/2    S    12:48   0:00  \_ sleep 61
...
...

Tempo di pulizia

Un killall bash fermerà le cose prima che sfuggano di mano. Pulire in questo modo potrebbe essere un po' pesante, un modo più gentile e gentile che potenzialmente non strapperà ogni bash shell down, sarebbe quello di fare quanto segue:

  1. Determina in quale pseudo terminale verrà eseguito il fork bomb

    $ tty
    /dev/pts/4
    
  2. Uccidi lo pseudo terminale

    $ pkill -t pts/4
    

Allora cosa sta succedendo?

Bene ogni invocazione di bash e sleep è una chiamata alla funzione C fork() dal bash shell da cui è stato eseguito il comando.


Linux
  1. Dov'è l'eseguibile PHP su Ubuntu?

  2. Dove si trova il filesystem del sottosistema Linux in Windows 10?

  3. Dov'è il comando gem in RHEL6?

  4. Dov'è la vista terminale di tty7

  5. Linux:dove mettere il file di scambio

Dov'è la descrizione dei contenuti delle sezioni uomo?

Dov'è la funzione itoa in Linux?

Dov'è il file php.ini su un PC Linux/CentOS?

Dove è documentato l'ABI x86-64 System V?

Dove va la memoria rimanente di vm.overcommit_ratio?

dove si trova il database aggiornatob?