AVERTISSEMENT N'ESSAYEZ PAS DE L'EXÉCUTER SUR UNE MACHINE DE PRODUCTION. JUSTE PAS.
Avertissement: pour essayer des "bombes", assurez-vous qu'elles ulimit -u
sont en cours d'utilisation. Lisez ci-dessous [a] .
Définissons une fonction pour obtenir le PID et la date (heure):
bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }
Une fonction simple et sans problème bomb
pour le nouvel utilisateur (protégez-vous: lisez [a] ):
bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2
Lorsque cette fonction est appelée pour être exécutée, cela fonctionne comme suit:
bize:~$ bomb
START 0002786 23:07:34
yes
END 0002786 23:07:35
bize:~$
La commande date
est exécutée, puis un "oui" est imprimé, un sommeil pendant 1 seconde, puis la commande de fermeture date
et, enfin, la fonction quitte l'impression d'une nouvelle invite de commande. Rien d'extraordinaire.
| tuyau
Lorsque nous appelons la fonction comme ceci:
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:~$
Deux commandes démarrent à un moment donné, les deux se terminent 1 seconde plus tard, puis l'invite revient.
C'est la raison pour laquelle la pipe |
, pour démarrer deux processus en parallèle.
& Contexte
Si nous changeons l'appel en ajoutant une fin &
:
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
L'invite revient immédiatement (toute l'action est envoyée en arrière-plan) et les deux commandes sont exécutées comme précédemment. Veuillez noter la valeur du "numéro de travail" [1]
imprimé avant le PID du processus 3380
. Plus tard, le même numéro sera imprimé pour indiquer que le tuyau est terminé:
[1]+ Done bomb | bomb
C'est l'effet de &
.
C'est la raison de &
: accélérer le démarrage des processus.
Nom plus simple
Nous pouvons créer une fonction appelée simplement b
pour exécuter les deux commandes. Tapé en trois lignes:
bize:~$ b(){
> bomb | bomb
> }
Et exécuté comme:
bize:~$ b
START 0003563 23:21:10
yes
START 0003564 23:21:10
yes
END 0003564 23:21:11
END 0003563 23:21:11
Notez que nous avons utilisé non ;
dans la définition de b
(les retours à la ligne ont été utilisés pour séparer les éléments). Cependant, pour une définition sur une ligne, il est habituel d'utiliser ;
, comme ceci:
bize:~$ b(){ bomb | bomb ; }
La plupart des espaces ne sont pas non plus obligatoires, nous pouvons écrire l'équivalent (mais moins clair):
bize:~$ b(){ bomb|bomb;}
Nous pouvons également utiliser un &
pour séparer le }
(et envoyer les deux processus en arrière-plan).
La bombe.
Si nous faisons mordre sa queue (en se faisant appeler), nous obtenons la "bombe fourchette":
bize:~$ b(){ b|b;} ### May look better as b(){ b | b ; } but does the same.
Et pour le faire appeler plus de fonctions plus rapidement, envoyez le tuyau en arrière-plan.
bize:~$ b(){ b|b&} ### Usually written as b(){ b|b& }
Si nous ajoutons le premier appel à la fonction après un requis ;
et changeons le nom, :
nous obtenons:
bize:~$ :(){ :|:&};:
Habituellement écrit comme :(){ :|:& }; :
Ou, écrit d'une manière amusante, avec un autre nom (un bonhomme de neige):
☃(){ ☃|☃&};☃
L'ulimit (que vous auriez dû définir avant d'exécuter ceci) fera revenir l'invite assez rapidement après beaucoup d'erreurs (appuyez sur Entrée lorsque la liste d'erreurs s'arrête pour obtenir l'invite).
La raison pour laquelle on appelle cela une "bombe fork" est que la façon dont le shell démarre un sous-shell est de forker le shell en cours d'exécution, puis d'appeler exec () au processus forké avec la commande à exécuter.
Un tuyau va "bifurquer" deux nouveaux processus. Le faire à l'infini provoque une bombe.
Ou un lapin comme on l'appelait à l'origine parce qu'il se reproduit si rapidement.
Horaire:
:(){ (:) | (:) }; time :
Terminé
réel 0m45.627s
:(){ : | :; }; time :
Terminé
réel 0m15.283s
:(){ : | :& }; time :
réel 0m00.002 s
Toujours en marche
Vos exemples:
:(){ (:) | (:) }; :
Là où la deuxième fermeture )
sépare, }
c'est une version plus complexe de :(){ :|:;};:
. Chaque commande d'un tube est de toute façon appelée dans un sous-shell. Quel est l'effet du ()
.
:(){ : | :& }; :
Est la version la plus rapide, écrite sans espaces: :(){(:)|:&};:
(13 caractères).
:(){ : | : }; :
### fonctionne en zsh mais pas en bash.
A une erreur de syntaxe (en bash), un métacaractère est nécessaire avant la fermeture }
,
comme ceci:
:(){ : | :; }; :
[a]
Créez un nouvel utilisateur propre (j'appellerai le mienbize
). Connectez-vous à ce nouvel utilisateur dans une consolesudo -i -u bize
, ou:
$ su - bize
Password:
bize:~$
Vérifiez puis modifiez la 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
En utilisant seulement 10 fonctionne comme qu'un seul nouvel utilisateur solitaire: bize
. Il est plus facile d'appeler killall -u bize
et de débarrasser le système de la plupart des bombes (pas toutes). S'il vous plaît ne demandez pas lesquels fonctionnent toujours, je ne le dirai pas. Mais quand même: est assez faible mais du côté sûr, adaptez-vous à votre système .
Cela garantira qu'une "bombe à fourche" n'effondrera pas votre système .
Lectures complémentaires:
:(){ : | :; }; :