terça-feira, 15 de maio de 2007

Fork Bomb: Não façam isso em ksa


Antes de continuar lendo, nunca, em ocasião nenhuma, execute o seguinte código:

:(){ :|:& };:

Oops, esqueci de falar o que acontece né ?? Vc digitou e travou tudo aí foi ?? Eu te avisei, vc digitou de curioso !! Não funcionou ?? Ah é, ele só funciona em sistemas operacionais decentes (isso exclui Redmond Like SOs). (;P)

Antes de qualquer explicação mais complexa, este código é uma função em bash script. Bash o quê ??

Ele basicamente cria um número exponencial de processos muito rapidamente, mais rápido do que o processador é capaz de aguentar. Uma vez disparado, o processador é entupido com vários processos em thread impossibilitando o carregamento de novos programas e deixando os programas existentes em baixa prioridade (-n19). Não se preocupe, isto levará apenas alguns milésimos de segundos, quanto mais rápido o processador, mais rápido ele vai agir, ou seja, é uma forma incomumente insustentável de retroatividade.

Outros exemplos:
script em perl
perl -e "fork while fork" &

Em C/C++
#include <unistd.h>
int main() {
while(1)
fork();
}

Outro em C
main() {for(;;)fork();}

Shell
$0 & $0 &


Que sistemas estão vulneráveis?

Praticamente todo sistema que suportar a função ‘fork’, ou seja, todos os sistemas operacionais de computadores.

O Windows, não escapa desta também (que dúvida…), mas há uma diferença… até onde sei, não é possível limitar o número de processos no Windows (Se você quiser fazer um teste com seu amigo que usa Windows basta criar um batch com o seguinte conteúdo:
bomb.bat
:s
start %0
goto s

Seria, no mínimo, interessante botar isto no autorun do "Pequenas e Macias Janelas à Vista" (:D)

Como parar?

Uma vez que um fork bomb é ativado com sucesso no sistema, não é possível continuar as operações normais sem reiniciar a máquina, visto que a única solução para parar o fork bomb é destruir todas as instâncias do mesmo. Tentar rodar um programa para matar os processos requer normalmente que outro processo seja criado, o que não é possível por não haver slots vazios na tabela de processos ou mesmo espaço disponível nas estruturas de memória.

Como se previnir?

Um fork bomb é uma forma de ataque DoS (Denial of Service). Uma maneira de prevenir que o fork bomb derrube o sistema é limitar o número de processos que um usuário pode ter. Quando o processo tenta criar qualquer outro processo além do máximo permitido, a criação falha.

Sistemas baseados em unix normalmente tem uma forma de limitar, com o comando ulimit:
ulimit -u 1000

Onde 1000 é o número de máximo de processos por usuário.

No entanto, em prática, algumas dessas bombas podem ser facilmente "curadas". Considerando a fork bomb do começo do post:
:(){ :|:& };:

Uma coisa bem interessante deste código é que um processo que não possa criar novas instâncias de si mesmo, não fica em espera e logo se finaliza.
Cura em Z Shell
while (sleep 100 &!) do; done

Se nós pegarmos e conseguirmos executar este código, ele irá criar um novo processo que não faz nada, o que por si só elimina a possibilidade do fork bomb iniciar mais uma de suas instâncias. O comando então iria eliminar as instâncias do fork um por um até a sua extinção. Mas aí, nós teríamos o problema de que seria nosso comando agora quem tomaria conta do computador. Só que, quando isto acontecesse, a condição do laço while deixaria de ser satisfeita, finalizando a mesma. Este código poderia acabar com o fork bomb em aproximadamente um minuto, dependendo do sistema e dos recursos disponíveis para o crescimento desenfreado da bomba.

Explicando a função:

Vou tentar explicar resumidamente a função: ":(){ :|:& };:"

Esta linha de comando cria uma função chamada ":" que não aceita nenhum argumento - representada no comando por ":(){ ... }".

O código dentro da função recursivamente chama a função e envia o retorno desta para outra instância da mesma função - representada no comando por ":|:". O símbolo "&" pega a chamada e a coloca para ser executada em segundo plano. Desta forma, os processos filhos não caem caso o processo pai seja finalizado. Note que por invocar a função duas vezes, o crescimento do número de processos se dá de forma exponencial!!

O símbolo ";" fecha a definição da função e o ":" no final é a primeira execução da função que inicia o funcionamento do fork bomb.

Considerações finais:

Reza a lenda que esta função é um dos fork bombs mais fatais, que sua execução pode até mesmo vir a causar um buffer overflow, queimando o processador.