ATTENZIONE NON TENTARE DI ESEGUIRE QUESTO SU UNA MACCHINA DI PRODUZIONE. NON FARE.
Avvertenza: per provare eventuali "bombe" assicurati che ulimit -u
sia in uso. Leggi sotto [a] .
Definiamo una funzione per ottenere il PID e la data (ora):
bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }
Una semplice bomb
funzione senza problemi per il nuovo utente (proteggiti: leggi [a] ):
bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2
Quando quella funzione viene chiamata per essere eseguita funziona come questa:
bize:~$ bomb
START 0002786 23:07:34
yes
END 0002786 23:07:35
bize:~$
Il comando date
viene eseguito, quindi viene stampato un "sì", uno sleep per 1 secondo, quindi il comando di chiusura date
e, infine, la funzione termina la stampa di un nuovo prompt dei comandi. Nulla di bello.
| tubo
Quando chiamiamo la funzione in questo modo:
bize:~$ bomb | bomb
START 0003365 23:11:34
yes
START 0003366 23:11:34
yes
END 0003365 23:11:35
END 0003366 23:11:35
bize:~$
Due comandi vengono avviati alla volta, i due terminano 1 secondo più tardi e quindi il prompt ritorna.
Questo è il motivo per cui la pipe |
avvia due processi in parallelo.
& sfondo
Se cambiamo la chiamata aggiungendo un finale &
:
bize:~$ bomb | bomb &
[1] 3380
bize:~$
START 0003379 23:14:14
yes
START 0003380 23:14:14
yes
END 0003379 23:14:15
END 0003380 23:14:15
Il prompt ritorna immediatamente (tutte le azioni vengono inviate in background) e i due comandi vengono eseguiti come prima. Si noti il valore di "numero lavoro" [1]
stampato prima del PID del processo 3380
. Successivamente, verrà stampato lo stesso numero per indicare che il tubo è terminato:
[1]+ Done bomb | bomb
Questo è l'effetto di &
.
Questo è il motivo per &
: avviare rapidamente i processi.
Nome più semplice
Possiamo creare una funzione chiamata semplicemente b
per eseguire i due comandi. Digitato in tre righe:
bize:~$ b(){
> bomb | bomb
> }
Ed eseguito come:
bize:~$ b
START 0003563 23:21:10
yes
START 0003564 23:21:10
yes
END 0003564 23:21:11
END 0003563 23:21:11
Nota che ;
nella definizione di non abbiamo usato b
(le nuove linee sono state usate per separare gli elementi). Tuttavia, per una definizione su una riga, è normale utilizzare ;
, in questo modo:
bize:~$ b(){ bomb | bomb ; }
Anche la maggior parte degli spazi non è obbligatoria, possiamo scrivere l'equivalente (ma meno chiaro):
bize:~$ b(){ bomb|bomb;}
Possiamo anche usare a &
per separare }
(e inviare i due processi in background).
La bomba.
Se facciamo in modo che la funzione si morda la coda (chiamando se stessa), otteniamo la "bomba a forcella":
bize:~$ b(){ b|b;} ### May look better as b(){ b | b ; } but does the same.
E per farlo chiamare più funzioni più velocemente, invia la pipe in background.
bize:~$ b(){ b|b&} ### Usually written as b(){ b|b& }
Se aggiungiamo la prima chiamata alla funzione dopo una richiesta ;
e cambiamo il nome in :
otteniamo:
bize:~$ :(){ :|:&};:
Solitamente scritto come :(){ :|:& }; :
Oppure, scritto in modo divertente, con qualche altro nome (un uomo delle nevi):
☃(){ ☃|☃&};☃
L'ulimit (che avresti dovuto impostare prima di eseguirlo) farà tornare il prompt abbastanza rapidamente dopo molti errori (premi Invio quando l'elenco degli errori si interrompe per ottenere il prompt).
La ragione per cui questa viene chiamata "fork bomb" è che il modo in cui la shell avvia una sub-shell è biforcando la shell in esecuzione e quindi chiamando exec () al processo biforcato con il comando per eseguire.
Una pipe "biforcerà" due nuovi processi. Farlo all'infinito provoca una bomba.
O un coniglio come originariamente chiamato perché si riproduce così rapidamente.
Timing:
:(){ (:) | (:) }; time :
0m45.627s
terminati reali
:(){ : | :; }; time :
0m15.283s
terminato reale
:(){ : | :& }; time :
real 0m00.002 s
Ancora in esecuzione
I tuoi esempi:
:(){ (:) | (:) }; :
Dove la seconda chiusura )
separa }
è una versione più complessa di :(){ :|:;};:
. Ogni comando in una pipe viene comunque chiamato all'interno di una sotto-shell. Qual è l'effetto di ()
.
:(){ : | :& }; :
È la versione più veloce, scritta per non avere spazi: :(){(:)|:&};:
(13 caratteri).
:(){ : | : }; :
### funziona in zsh ma non in bash.
Ha un errore di sintassi (in bash), è necessaria una metacarattere prima della chiusura }
,
come questo:
:(){ : | :; }; :
[a]
Crea un nuovo utente pulito (chiamerò il miobize
). Accedi a questo nuovo utente in una consolesudo -i -u bize
o:
$ su - bize
Password:
bize:~$
Controlla e poi modifica il max user processes
limite:
bize:~$ ulimit -a ### List all limits (I show only `-u`)
max user processes (-u) 63931
bize:~$ ulimit -u 10 ### Low
bize:~$ ulimit -a
max user processes (-u) 1000
Utilizzando solo 10 opere, come è solo una solitaria nuovo utente: bize
. Rende più facile chiamare killall -u bize
e liberare il sistema dalla maggior parte delle bombe (non tutte). Per favore, non chiedere quali funzionano ancora, non lo dirò. Ma comunque: è piuttosto basso ma per sicurezza, adattati al tuo sistema .
Ciò garantirà che una "bomba a forcella" non crollerà il sistema .
Ulteriori letture:
:(){ : | :; }; :