
Entiendo cómo funciona una bomba fork normal, pero realmente no entiendo por qué se requiere el & al final de la bomba bash fork común y por qué estos scripts se comportan de manera diferente:
:(){ (:) | (:) }; :
y
:(){ : | :& }; :
El primero provoca un aumento en el uso de la CPU antes de devolverme a la pantalla de inicio de sesión. En cambio, este último simplemente hace que mi sistema se congele, lo que me obliga a reiniciarlo por completo. ¿Porqué es eso? Ambos crean continuamente nuevos procesos, entonces, ¿por qué el sistema se comporta de manera diferente?
Ambos guiones también se comportan de manera diferente a
:(){ : | : }; :
lo cual no causa ningún problema en absoluto, aunque hubiera esperado que fueran similares. La página del manual de bash indica que los comandos de una canalización ya se ejecutan en un subshell, por lo que me hacen creer que: | : ya debería ser suficiente. Creo que debería ejecutar la canalización en una nueva subcapa, pero ¿por qué eso cambia tanto?
Editar: usando htop y limitando la cantidad de procesos, pude ver que la primera variante crea un árbol de procesos real, la segunda variante crea todos los procesos en el mismo nivel y la última variante no parece crear ningún proceso. en absoluto. Esto me confunde aún más, pero ¿tal vez ayude de alguna manera?
Respuesta1
ADVERTENCIA NO INTENTE EJECUTAR ESTO EN UNA MÁQUINA DE PRODUCCIÓN. SIMPLEMENTE NO LO HAGAS.
Advertencia: Para probar cualquier "bomba", asegúrese ulimit -u
de que 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égete: lee [a] ):
bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2
Cuando se llama a esa función para ser ejecutada, funciona así:
bize:~$ bomb
START 0002786 23:07:34
yes
END 0002786 23:07:35
bize:~$
Se ejecuta el comando date
, luego se imprime un "sí", un reposo por 1 segundo, luego el comando de cierre date
, y, finalmente, la función sale imprimiendo un nuevo símbolo del sistema. Nada sofisticado.
| 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 comienzan al mismo tiempo, ambos comandos finalizarán 1 segundo después yentoncesel mensaje regresa.
Ese es el motivo de la tubería |
, para iniciar dos procesos en paralelo.
& fondo
Si cambiamos la llamada añadiendo una terminación &
:
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
El mensaje regresa inmediatamente (toda la acción se envía a un segundo plano) 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
. Posteriormente 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 &
: iniciar 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 usamos no ;
en la definición de b
(las nuevas líneas se usaron para separar elementos). Sin embargo, para una definición en una línea, lo habitual es utilizar ;
, así:
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 }
(y enviar los dos procesos a un segundo plano).
La bomba.
Si hacemos que la función se muerda la cola (llamándose a sí misma), obtenemos la "bomba fork":
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 requerido ;
y cambiamos el nombre, :
obtenemos:
bize:~$ :(){ :|:&};:
Generalmente escrito como:(){ :|:& }; :
O, escrito de forma divertida, con algún otro nombre (un muñeco de nieve):
☃(){ ☃|☃&};☃
El ulimit (que debería haber configurado antes de ejecutar esto) hará que el mensaje regrese bastante rápido después de muchos errores (presione Intro cuando la lista de errores se detenga para obtener el mensaje).
La razón por la que esto se llama "bomba de bifurcación" 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 provoca una bomba.
O un conejo como se llamaba originalmente porque se reproduce muy rápidamente.
Momento:
:(){ (:) | (:) }; time :
Terminado
real 0m45.627s:(){ : | :; }; time :
Terminado
real 0m15.283s:(){ : | :& }; time :
real 0m00.002 s
Sigue funcionando
Tus ejemplos:
:(){ (:) | (:) }; :
Donde el segundo cierre
)
separa}
hay una versión más compleja de:(){ :|:;};:
. De todos modos, cada comando en una tubería se llama dentro de un subshell. ¿Cuál es el efecto del()
.:(){ : | :& }; :
Es la versión más rápida, escrita sin 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
}
,
como este::(){ : | :; }; :
[a]
Crea un nuevo usuario limpio (yo llamaré al mío bize
). Inicie sesión con este nuevo usuario en una consola sudo -i -u bize
o:
$ 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
Usar solo 10 funciona ya que es solo un nuevo usuario solitario: bize
. Hace que sea más fácil llamar killall -u bize
y eliminar la mayoría de las bombas (no todas). Por favor, no preguntes cuáles todavía funcionan, no te lo diré. Pero aún:Es bastante bajo pero seguro, adáptese a su sistema.
Estegarantizará que una "bomba bifurcación" no colapse su sistema.
Otras lecturas: