AVISO NÃO TENTE EXECUTAR ISTO EM UMA MÁQUINA DE PRODUÇÃO. APENAS NÃO.
Aviso: Para tentar qualquer "bomba", verifique se ulimit -u
está em uso. Leia abaixo [a] .
Vamos definir uma função para obter o PID e a data (hora):
bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }
Uma função simples e sem problemas bomb
para o novo usuário (proteja-se: leia [a] ):
bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2
Quando essa função é chamada para ser executada, funciona assim:
bize:~$ bomb
START 0002786 23:07:34
yes
END 0002786 23:07:35
bize:~$
O comando date
é executado, um "sim" é impresso, um sono por 1 segundo, o comando de fechamento date
e, finalmente, a função sai da impressão de um novo prompt de comando. Nada chique.
| tubo
Quando chamamos a função assim:
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:~$
Dois comandos começar em algum momento, os dois terminam 1 segundo mais tarde e , em seguida, o prompt retornos.
Essa é a razão do canal |
, para iniciar dois processos em paralelo.
& fundo
Se mudarmos a chamada, adicionamos um 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
O prompt retorna imediatamente (toda a ação é enviada para o plano de fundo) e os dois comandos são executados como antes. Observe o valor do "número do trabalho" [1]
impresso antes do PID do processo 3380
. Posteriormente, o mesmo número será impresso para indicar que o tubo terminou:
[1]+ Done bomb | bomb
Esse é o efeito de &
.
Essa é a razão da &
: para iniciar os processos mais rapidamente.
Nome mais simples
Podemos criar uma função chamada simplesmente b
para executar os dois comandos. Digitado em três linhas:
bize:~$ b(){
> bomb | bomb
> }
E executado 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
Observe que não usamos no ;
na definição de b
(as novas linhas foram usadas para separar elementos). No entanto, para uma definição em uma linha, é comum usar ;
, assim:
bize:~$ b(){ bomb | bomb ; }
A maioria dos espaços também não é obrigatória, podemos escrever o equivalente (mas menos claro):
bize:~$ b(){ bomb|bomb;}
Também podemos usar a &
para separar o }
(e enviar os dois processos para o plano de fundo).
A bomba
Se fizermos a função morder sua cauda (chamando a si mesma), obteremos a "bomba de forquilha":
bize:~$ b(){ b|b;} ### May look better as b(){ b | b ; } but does the same.
E para torná-lo mais rápido, envie o canal para o segundo plano.
bize:~$ b(){ b|b&} ### Usually written as b(){ b|b& }
Se anexarmos a primeira chamada à função após um requisito ;
e alterar o nome para :
obtermos:
bize:~$ :(){ :|:&};:
Geralmente escrito como :(){ :|:& }; :
Ou, escrito de uma maneira divertida, com outro nome (um homem da neve):
☃(){ ☃|☃&};☃
O ulimit (que você deveria ter definido antes de executar isso) fará com que o prompt retorne rapidamente depois de muitos erros (pressione enter quando a lista de erros parar para obter o prompt).
A razão para isso ser chamado de "fork pump" é que a maneira pela qual o shell inicia um sub shell é bifurcando o shell em execução e depois chamando exec () para o processo bifurcado com o comando para executar.
Um tubo "bifurcará" dois novos processos. Fazer isso até o infinito causa uma bomba.
Ou um coelho como era originalmente chamado porque se reproduz muito rapidamente.
Cronometragem:
:(){ (:) | (:) }; time :
Terminados
0m45.627s reais
:(){ : | :; }; time :
Terminados
0m15.283s reais
:(){ : | :& }; time :
0m00.002 s reais
ainda em execução
Seus exemplos:
:(){ (:) | (:) }; :
Onde o segundo fechamento )
separa }
é uma versão mais complexa de :(){ :|:;};:
. Cada comando em um pipe é chamado dentro de um sub-shell de qualquer maneira. Qual é o efeito do ()
.
:(){ : | :& }; :
É a versão mais rápida, escrita para não ter espaços: :(){(:)|:&};:
(13 caracteres).
:(){ : | : }; :
### funciona no zsh, mas não no bash.
Possui um erro de sintaxe (no bash), um metacaractere é necessário antes do fechamento }
,
assim:
:(){ : | :; }; :
[a]
Crie um novo usuário limpo (eu chamarei de meubize
). Efetue login neste novo usuário em um consolesudo -i -u bize
ou:
$ su - bize
Password:
bize:~$
Verifique e altere o 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
Usando apenas 10 obras, como é apenas um usuário novo solitária: bize
. Torna mais fácil chamar killall -u bize
e livrar o sistema da maioria das bombas (não todas). Por favor, não pergunte quais ainda funcionam, não vou contar. Mas ainda: é bastante baixo, mas no lado seguro, adapte-se ao seu sistema .
Isso garantirá que uma "bomba de forquilha" não entrará em colapso no seu sistema .
Leitura adicional:
:(){ : | :; }; :