¿Por qué las C-forkbombs no funcionan como las bash?

5 minutos de lectura

avatar de usuario
peoro

Si ejecuto el clásico bash forkbomb:

:(){ :&:&};:

mi sistema cuelga después de unos segundos.

Traté de escribir un forkbomb en C, aquí está el código:

#include <unistd.h>

int main( )
{
    while(1) {
        fork();
    }
    return 0;
}

Cuando lo ejecuto, el sistema responde menos, pero puedo cancelar ese proceso (incluso después de minutos) simplemente presionando ^C.


El código anterior es diferente del bash forkbomb original que publiqué: es algo más como:

:( )
{
    while true
    do
        :
    done
}

(No lo probé; no sé si lo haría colgar el sistema).

Así que también traté de implementar la versión original; aquí el código:

#include <unistd.h>

inline void colon( const char *path )
{
    pid_t pid = fork( );
    if( pid == 0 ) {
        execl( path, path, 0 );
    }
}

int main( int argc, char **argv )
{
    colon( argv[0] );
    colon( argv[0] );
    return 0;
}

Pero aún nada: puedo ejecutarlo y luego matarlo fácilmente. No es colgando mi sistema


¿Por qué?

¿Qué tienen de especial las bombas bash fork? ¿Es porque bash usa mucha más memoria/CPU? ¿Porque los procesos de bash llaman a muchas más llamadas al sistema (por ejemplo, para acceder al sistema de archivos) que las mías?

  • Como dice el refrán, los avances científicos rara vez van acompañados de “¡Eureka!”, comúnmente acompañados de “Hmm, eso es extraño”.

    – Camille Goudeseune

    13 de enero de 2014 a las 22:45

Ese programa en C es diminuto, en serio diminuto. Además, bifurcar() un programa como ese es muy, muy eficiente. Sin embargo, un intérprete, como Bash, es mucho más costoso en términos de uso de RAM y necesita acceder al disco todo el tiempo.

Intenta ejecutarlo durante mucho más tiempo. 🙂

  • Además, los Unix modernos tienden a usar copia en escritura para la memoria virtual. A menos que cada proceso realmente escriba en una ubicación de memoria, todos usarán las mismas páginas físicas, incluso después de la exec. Ponga algunos mallocs aleatorios y escriba en la memoria malloced. Creo que eso matará a la máquina.

    – JeremyP

    22 de noviembre de 2010 a las 9:54

  • Sí, ya mencioné estas cosas, pero ¿cuáles de ellas son las que cuelgan el sistema y por qué? Si para cualquier proceso que genero, asigno 1 MB de memoria en el montón/pila, ¿colgará mi sistema? ¿O si algún proceso hace 1 segundo de cálculo intensivo? ¿O si algún proceso llama a algunas llamadas al sistema?

    – peoro

    22 de noviembre de 2010 a las 12:17

  • @peoro: Técnicamente no lo hiciste. Mi punto no era que cada nuevo proceso usa poca memoria, sino que en realidad no usa memoria adicional (aparte de las estructuras del kernel). Cuando haces una bifurcación, el proceso hijo usa exactamente las mismas páginas físicas que el padre hasta que escribe algo en la memoria. Incluso con exec, la imagen ejecutable se comparte. Se creará una nueva página de pila, pero el gran asesino del rendimiento es el intercambio y esto no sucederá a menos que haga algunas escrituras.

    – JeremyP

    22 de noviembre de 2010 a las 13:31


  • No, esta no es la verdadera causa de tal comportamiento. Esto es lo que es: stackoverflow.com/a/19322116/585725

    – Shnatsel

    11/10/2013 a las 15:42

  • @SudipBhandari: estás leyendo demasiado en la respuesta. Sin embargo, para responder a su pregunta, un pequeño programa implementado en C, sin un recolector de basura, en un sistema operativo que implemente páginas COW (Copy On Write), como lo hacen la mayoría de los sistemas Linux, incurrirá en muy poca sobrecarga. Otro proceso que requiere varios GB de memoria seguirá bifurcándose eficientemente en un sistema de este tipo, ya que la memoria no se copia hasta que se modifica. Este no es el caso en ventanas o programas que tienen un GC de marcar y barrer (o similar). Pero el programa C que se muestra fue el escenario más simple posible, que será eficiente.

    – Arafangión

    6 de junio de 2017 a las 6:24

los real la causa de esto es que en BASH el proceso que crea está separado del padre. Si el proceso principal (el que inició inicialmente) se cancela, el resto de los procesos continúan. Pero en las implementaciones de C que enumeró, los procesos secundarios mueren si el padre muere, por lo que es suficiente para derribar el proceso inicial que comenzó para derribar el entero árbol de procesos siempre bifurcados.

Todavía no se me ocurrió una implementación de C forkbomb que separe los procesos secundarios para que no se eliminen si el padre muere. Se agradecerían los enlaces a tales implementaciones.

En su bash forkbomb, está colocando nuevos procesos en nuevos grupos de procesos en segundo plano, por lo que no podrá ^C a ellos.

Eso es básicamente por el tamaño. Cuando está ejecutando la bomba bash fork, carga grandes programas de monstruos en la memoria (con respecto a su programa c), cada uno de ellos comienza a acaparar los recursos de su CPU. Definitivamente, cuando los grandes monstruos comienzan a reproducirse, los problemas surgen más rápidamente que si las abejas comienzan a hacer lo mismo. . Entonces, la computadora se cuelga inmediatamente. Sin embargo, si mantiene su ejecutable c funcionando durante mucho tiempo, también colgará el sistema. Solo que el tiempo será mucho más. Si desea comparar el tamaño de bash con el tamaño del programa c, consulte /proc//status. primero con el pid de cualquier instancia en ejecución de bash, y luego con el pid de cualquier instancia en ejecución del programa ac

¿Ha sido útil esta solución?