나는 일반적인 포크 폭탄이 어떻게 작동하는지 이해하지만 공개 bash 포크 폭탄의 끝에 &가 필요한 이유와 이러한 스크립트가 다르게 작동하는 이유를 잘 이해하지 못합니다.
:(){ (:) | (:) }; :
그리고
:(){ : | :& }; :
전자는 CPU 사용량을 급증시킨 다음 로그인 화면으로 돌아갑니다. 후자로 인해 시스템이 정지되어 하드 재부팅을 해야 했습니다. 왜 그런 겁니까? 둘 다 지속적으로 새로운 프로세스를 생성하고 있는데 왜 시스템이 다르게 작동합니까?
두 스크립트도 다르게 동작합니다.
:(){ : | : }; :
비슷하다고 생각했지만 전혀 문제가 발생하지 않았습니다. Bash 매뉴얼 페이지에는 파이프라인의 명령이 이미 서브셸에서 실행되었다고 나와 있으므로 다음과 같이 생각합니다. | 나는 새로운 서브셸에서 파이프를 실행해야 한다고 믿고 있지만 왜 그렇게 큰 변화가 필요한 걸까요?
편집: htop을 사용하고 프로세스 수를 제한하면 첫 번째 변형은 실제 프로세스 트리를 생성하고 두 번째 변형은 동일한 수준에서 모든 프로세스를 생성하며 마지막 변형은 프로세스를 전혀 생성하지 않는 것 같습니다. 아니요 . 이것이 나를 더욱 혼란스럽게 하지만 어쩌면 도움이 될까요?
답변1
경고 프로덕션 시스템에서 이 프로그램을 실행하지 마십시오. 하지 마세요.ulimit -u
경고: "폭탄"을 시도하기 전에 그것이 사용되고 있는지 확인하십시오 . 아래 [a]를 읽어보세요 .
PID와 날짜(시간)를 가져오는 함수를 정의해 보겠습니다.
bize:~$ d(){ printf '%7s %07d %s\n' "$1" "$BASHPID" "$(date +'%H:%M:%S')"; }
bomb
이는 신규 사용자를 위한 간단하고 문제 없는 기능입니다(자신을 보호하세요: [a] 읽기 ):
bize:~$ bomb() { d START; echo "yes"; sleep 1; d END; } >&2
이 함수가 실행을 위해 호출되면 다음과 같이 작동합니다.
bize:~$ bomb
START 0002786 23:07:34
yes
END 0002786 23:07:35
bize:~$
명령이 date
실행된 다음 "yes"를 인쇄하고 1초 동안 대기한 다음 명령을 닫고 date
마지막으로 함수가 새 명령 프롬프트 인쇄를 종료합니다. 멋진 것은 없습니다.
|파이프라인
다음과 같이 함수를 호출하면:
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:~$
두 명령은 동시에 시작되고 두 명령은 1초 후에 종료됩니다.그 다음에프롬프트가 반환됩니다.
|
이것이 파이프라인이 두 프로세스를 병렬로 시작하는 이유입니다.
& 배경
엔딩을 추가하기 위해 호출을 변경하면 다음과 같습니다 &
.
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
프롬프트가 즉시 반환되고(모든 작업이 백그라운드로 전송됨) 두 명령 모두 이전과 같이 실행됩니다. [1]
프로세스 PID에 대해 이전에 인쇄된 "작업 번호" 값을 참고하세요 3380
. 나중에 파이프가 끝났음을 나타내기 위해 동일한 숫자가 인쇄됩니다.
[1]+ Done bomb | bomb
이것이 효과입니다 &
.
이것이 &
바로 프로세스를 더 빠르게 시작하는 이유입니다.
더 간단한 이름
b
이 두 명령을 실행하는 간단한 함수를 만들 수 있습니다 . 세 줄로 입력하세요.
bize:~$ b(){
> bomb | bomb
> }
다음과 같이 실행됩니다.
bize:~$ b
START 0003563 23:21:10
yes
START 0003564 23:21:10
yes
END 0003564 23:21:11
END 0003563 23:21:11
;
정의에서 no를 사용했다는 점에 유의하세요 b
(개행 문자는 요소를 구분하는 데 사용됩니다). 그러나 한 줄 정의의 경우 ;
다음과 같이 사용하는 것이 일반적입니다.
bize:~$ b(){ bomb | bomb ; }
대부분의 공백도 필수는 아니며, 이에 상응하는 내용을 작성할 수 있습니다(그러나 덜 명확함).
bize:~$ b(){ bomb|bomb;}
&
a를 사용 하여 분리 }
하고 두 프로세스를 모두 백그라운드로 보낼 수도 있습니다 .
폭탄.
함수가 자신을 호출하여 꼬리를 물면 "포크 폭탄"이 발생합니다.
bize:~$ b(){ b|b;} ### May look better as b(){ b | b ; } but does the same.
더 많은 기능을 더 빠르게 호출하려면 파이프를 배경으로 보냅니다.
bize:~$ b(){ b|b&} ### Usually written as b(){ b|b& }
함수에 대한 첫 번째 호출에 필수를 추가 ;
하고 이름을 다음과 같이 변경하면 :
다음과 같은 결과를 얻습니다.
bize:~$ :(){ :|:&};:
일반적으로 다음과 같이 작성됩니다.:(){ :|:& }; :
또는 다른 이름(눈사람)을 사용하여 재미있는 방법으로 작성했습니다.
☃(){ ☃|☃&};☃
ulimit(이 명령을 실행하기 전에 설정해야 함)는 많은 수의 오류가 발생한 후 프롬프트가 곧 반환되도록 합니다(오류 목록이 중지되면 Enter를 눌러 프롬프트를 표시합니다).
쉘이 서브쉘을 시작하는 방식은 실행 중인 쉘을 포크한 다음 실행할 명령과 함께 포크된 프로세스에서 exec()를 호출하는 것이기 때문에 "포크 폭탄"이라고 합니다.
파이프라인은 두 개의 새로운 프로세스를 "포크"합니다. 이것을 무한대로 하면 폭탄이 생길 것입니다.
또는 너무 빨리 번식했기 때문에 원래 "토끼"라고 불렸습니다.
타이밍:
:(){ (:) | (:) }; time :
종료
참 0m45.627s:(){ : | :; }; time :
종료
참 0m15.283s:(){ : | :& }; time :
True 0m00.002 s가
여전히 실행 중입니다.
귀하의 예:
:(){ (:) | (:) }; :
두 번째 엔딩이
)
분리 되는 곳은 의}
더 복잡한 버전입니다:(){ :|:;};:
. 그럼에도 불구하고 파이프라인의 각 명령은 서브셸 내에서 호출됩니다. 이것이 효과입니다()
.:(){ : | :& }; :
공백 없이 작성된 더 빠른 버전입니다
:(){(:)|:&};:
(13자).:(){ : | : }; :
### zsh에서는 작동하지만 bash에서는 작동하지 않습니다.(bash에) 구문 오류가 있습니다. 다음과 같이 end 앞에 메타 문자가 필요합니다
}
.:(){ : | :; }; :
[ㅏ]
새로운 클린 사용자를 생성합니다(이를 광산이라고 부르겠습니다 bize
). 콘솔에서 새 사용자로 로그인 sudo -i -u bize
하거나 다음을 수행합니다.
$ su - bize
Password:
bize:~$
max user processes
제한을 확인한 후 변경하십시오 .
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
10개의 조각만 사용하는 것은 새로운 사용자가 단 한 명인 것과 같습니다 bize
. 이는 killall -u bize
시스템에서 대부분의(전부는 아님) 폭탄을 불러오고 제거하는 것을 더 쉽게 만듭니다 . 어느 것이 아직 유효한지는 묻지 마세요. 말하지 않겠습니다. 하지만 여전히:상당히 낮지만 안전을 위해 시스템에 적응하세요..
이것"포크 폭탄"이 시스템을 충돌시키지 않도록 보장합니다..
추가 자료: