ADVERTENCIA NO INTENTE EJECUTAR ESTO EN UNA MÁQUINA DE PRODUCCIÓN. SOLO NO.
Advertencia: Para probar cualquier "bomba" asegúrese de que ulimit -u
esté en uso. Lea a continuación [a] .
Definamos una función para obtener el PID y la fecha (hora):
bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }
Una función simple y sin problemas bomb
para el nuevo usuario (protéjase: lea [a] ):
bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2
Cuando se llama a esa función para que se ejecute funciona así:
bize:~$ bomb
START 0002786 23:07:34
yes
END 0002786 23:07:35
bize:~$
Se date
ejecuta el comando , luego se imprime un "sí", un sueño durante 1 segundo, luego el comando de cierre date
y, finalmente, la función sale imprimiendo un nuevo símbolo del sistema. Nada sofisticado.
El | tubo
Cuando llamamos a la función así:
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:~$
Dos comandos se inician en algún momento, los dos finalizan 1 segundo más tarde y luego vuelve el indicador.
Esa es la razón de la tubería |
, para iniciar dos procesos en paralelo.
& antecedentes
Si cambiamos la llamada agregando un final &
:
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
La solicitud vuelve inmediatamente (toda la acción se envía al fondo) y los dos comandos se ejecutan como antes. Tenga en cuenta el valor del "número de trabajo" [1]
impreso antes del PID del proceso 3380
. Más tarde, se imprimirá el mismo número para indicar que la tubería ha terminado:
[1]+ Done bomb | bomb
Ese es el efecto de &
.
Esa es la razón de &
: comenzar los procesos más rápido.
Nombre más simple
Podemos crear una función llamada simplemente b
para ejecutar los dos comandos. Escrito en tres líneas:
bize:~$ b(){
> bomb | bomb
> }
Y ejecutado como:
bize:~$ b
START 0003563 23:21:10
yes
START 0003564 23:21:10
yes
END 0003564 23:21:11
END 0003563 23:21:11
Tenga en cuenta que no utilizamos ;
en la definición de b
(las nuevas líneas se utilizaron para separar elementos). Sin embargo, para una definición en una línea, es habitual usar ;
, como este:
bize:~$ b(){ bomb | bomb ; }
La mayoría de los espacios tampoco son obligatorios, podemos escribir el equivalente (pero menos claro):
bize:~$ b(){ bomb|bomb;}
También podemos usar a &
para separar el }
(y enviar los dos procesos a un segundo plano).
La bomba.
Si hacemos que la función muerda su cola (llamándose a sí misma), obtenemos la "bomba tenedor":
bize:~$ b(){ b|b;} ### May look better as b(){ b | b ; } but does the same.
Y para que llame a más funciones más rápido, envíe la canalización a un segundo plano.
bize:~$ b(){ b|b&} ### Usually written as b(){ b|b& }
Si agregamos la primera llamada a la función después de un requerimiento ;
y cambiamos el nombre :
, obtenemos:
bize:~$ :(){ :|:&};:
Usualmente escrito como :(){ :|:& }; :
O, escrito de forma divertida, con algún otro nombre (un hombre de nieve):
☃(){ ☃|☃&};☃
El ulimit (que debería haber configurado antes de ejecutar esto) hará que la solicitud vuelva rápidamente después de muchos errores (presione enter cuando la lista de errores se detenga para obtener la solicitud).
La razón de que esto se llame una "bomba tenedor" es que la forma en que el shell inicia un sub-shell es bifurcando el shell en ejecución y luego llamando a exec () al proceso bifurcado con el comando para ejecutar.
Una tubería "bifurcará" dos nuevos procesos. Hacerlo hasta el infinito causa una bomba.
O un conejo como se llamaba originalmente porque se reproduce muy rápido.
Sincronización:
:(){ (:) | (:) }; time :
Terminado
real 0m45.627s
:(){ : | :; }; time :
Terminado
0m15.283s reales
:(){ : | :& }; time :
0m00.002 verdadera s
Still Running
Sus ejemplos:
:(){ (:) | (:) }; :
Donde el segundo cierre )
separa }
es una versión más compleja de :(){ :|:;};:
. Cada comando en una tubería se llama dentro de un sub-shell de todos modos. ¿Cuál es el efecto de la ()
.
:(){ : | :& }; :
Es la versión más rápida, escrita para no tener espacios: :(){(:)|:&};:
(13 caracteres).
:(){ : | : }; :
### funciona en zsh pero no en bash.
Tiene un error de sintaxis (en bash), se necesita un metacarácter antes del cierre }
,
ya que esto:
:(){ : | :; }; :
[a]
Cree un nuevo usuario limpio (lo llamaré míobize
). Inicie sesión con este nuevo usuario en una consolasudo -i -u bize
, o bien:
$ su - bize
Password:
bize:~$
Verifique y luego cambie el max user processes
límite:
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
Usando sólo 10 obras, es sólo un nuevo usuario solitaria: bize
. Hace más fácil llamar killall -u bize
y eliminar el sistema de la mayoría (no todas) de las bombas. Por favor, no pregunte cuáles siguen funcionando, no lo diré. Pero aún así: es bastante bajo, pero en el lado seguro, adáptese a su sistema .
Esto asegurará que una "bomba tenedor" no colapsará su sistema .
Otras lecturas:
:(){ : | :; }; :