포크 폭탄의 포크 ()는 어디에 있습니까 : () {: | : &}; :?


25

경고 : 대부분의 셸에서이 명령을 실행하면 시스템이 손상되어 강제로 종료해야합니다.

재귀 함수 :(){ :|: & };:와 그 기능을 이해합니다 . 그러나 포크 시스템 호출이 어디에 있는지 모르겠습니다. 확실하지 않지만 파이프가 의심됩니다 |.


관련 (그리고 읽을 가치가있는) : 포크 폭탄은 어떻게 작동합니까?
terdon

답변:


30

파이프 in의 결과로 x | y포 그라운드 프로세스 그룹의 일부로 파이프 라인을 포함하도록 서브 쉘이 작성됩니다. 이것은 fork()무기한으로 서브 쉘을 계속 생성하여 포크 폭탄을 만듭니다.

$ for (( i=0; i<3; i++ )); do
>     echo "$BASHPID"
> done
16907
16907
16907
$ for (( i=0; i<3; i++ )); do
>     echo "$BASHPID" | cat
> done
17195
17197
17199

그러나 코드가 실행될 때까지는 실제로 포크가 발생하지 않습니다. 이는 코드에서 최종 호출입니다 :.

포크 폭탄의 작동 방식을 분해하려면 :

  • :() -라는 새로운 기능을 정의 :
  • { :|: & } -호출 함수를 백그라운드에서 호출 함수의 다른 인스턴스로 재귀 적으로 파이프하는 함수 정의
  • : -포크 폭탄 기능을 호출

이것은 메모리를 많이 사용하지 않는 경향이 있지만 PID를 빨아 들여 CPU 사이클을 소비합니다.


에서 x | y, 왜 서브 쉘이 생성된다? 내 이해를 위해 bash가을 볼 때 시스템 호출을 pipe실행 하여 pipe()2를 반환합니다 fds. 이제 command_left가 execed되고 출력이 command_right에 입력으로 공급됩니다. 이제 command_right는 execed입니다. 그렇다면 왜 BASHPID매번 다른가?
Abhijeet Rastogi

2
@shadyabhi 그것은 간단하다 - x그리고 y당신이 개 별도의 서브 쉘을 가지고 있으므로,이 개 별도의 프로세스에서 실행이 별도의 명령이다. x쉘과 동일한 프로세스에서 실행되는 경우 x내장되어 있어야합니다.
jw013

24

코드의 마지막 비트 ;:는 함수를 실행 중 :(){ ... }입니다. 여기서 포크가 발생합니다.

세미콜론은 첫 번째 명령을 종료하고 다른 명령을 시작합니다 (예 : 함수 호출) :. 이 함수의 정의에는 자체 :호출이 포함되며이 호출의 출력은 백그라운드 버전으로 파이프됩니다 :. 이것은 프로세스를 무기한으로 진행합니다.

함수 :()를 호출 할 때마다 C 함수를 호출합니다 fork(). 결국 이것은 시스템의 모든 프로세스 ID (PID)를 소진합니다.

|:&다른 것으로 바꿔서 무슨 일이 일어나고 있는지 알 수 있습니다.

감시자 설정

하나의 터미널 창에서 다음을 수행하십시오.

$ watch "ps -eaf|grep \"[s]leep 61\""

"퓨즈 지연"포크 폭탄 설정

다른 창에서는 약간 수정 된 포크 폭탄 버전을 실행합니다. 이 버전은 스로틀을 시도하여 수행중인 작업을 연구 할 수 있습니다. 우리의 버전은 함수를 호출하기 전에 61 초 동안 대기합니다 :().

또한 호출 후 초기 호출도 배경으로합니다. Ctrl+ z를 입력 한 다음을 입력하십시오 bg.

$ :(){ sleep 61; : | : & };:

# control + z
[1]+  Stopped                 sleep 61
[2] 5845
$ bg
[1]+ sleep 61 &

이제 jobs초기 창에서 명령을 실행하면 다음을 볼 수 있습니다.

$ jobs
[1]-  Running                 sleep 61 &
[2]+  Running                 : | : &

몇 분 후 :

$ jobs
[1]-  Done                    sleep 61
[2]+  Done                    : | :

감시자에게 체크인

한편 우리가 실행중인 다른 창에서 watch:

Every 2.0s: ps -eaf|grep "[s]leep 61"                                                                                                                                             Sat Aug 31 12:48:14 2013

saml      6112  6108  0 12:47 pts/2    00:00:00 sleep 61
saml      6115  6110  0 12:47 pts/2    00:00:00 sleep 61
saml      6116  6111  0 12:47 pts/2    00:00:00 sleep 61
saml      6117  6109  0 12:47 pts/2    00:00:00 sleep 61
saml      6119  6114  0 12:47 pts/2    00:00:00 sleep 61
saml      6120  6113  0 12:47 pts/2    00:00:00 sleep 61
saml      6122  6118  0 12:47 pts/2    00:00:00 sleep 61
saml      6123  6121  0 12:47 pts/2    00:00:00 sleep 61

프로세스 계층

그리고이 ps -auxf프로세스 계층 구조를 보여줍니다 :

$ ps -auxf
saml      6245  0.0  0.0 115184  5316 pts/2    S    12:48   0:00 bash
saml      6247  0.0  0.0 100988   468 pts/2    S    12:48   0:00  \_ sleep 61
....
....
saml      6250  0.0  0.0 115184  5328 pts/2    S    12:48   0:00 bash
saml      6268  0.0  0.0 100988   468 pts/2    S    12:48   0:00  \_ sleep 61
saml      6251  0.0  0.0 115184  5320 pts/2    S    12:48   0:00 bash
saml      6272  0.0  0.0 100988   468 pts/2    S    12:48   0:00  \_ sleep 61
saml      6252  0.0  0.0 115184  5324 pts/2    S    12:48   0:00 bash
saml      6269  0.0  0.0 100988   464 pts/2    S    12:48   0:00  \_ sleep 61
...
...

정리 시간

A killall bash는 손을 떼기 전에 물건을 멈출 것입니다. 이 방법으로 청소하는 것은 약간 무거운 손 bash이 될 수 있습니다.

  1. 포크 폭탄이 어떤 의사 터미널에서 실행 될지 결정

    $ tty
    /dev/pts/4
  2. 의사 터미널을 죽이십시오

    $ pkill -t pts/4

무슨 일이야?

음의 각 호출 bash하고 sleepC 함수를 호출입니다 fork()로부터 bash명령이 실행 된 곳에서 쉘은.


7
bash별도의 터미널에서 실행 중일 수 있습니다. 사용하는 것이 좋습니다 pkill -t pts/2.
Maciej Piechotka

@MaciejPiechotka-팁 주셔서 감사합니다. 한 번도 본 적이 없어 답변에 추가했습니다!
slm
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.