bash에서 포크 폭탄이 죽는 것처럼 왜 zsh에서 죽을 수 없습니까?

bash에서 포크 폭탄이 죽는 것처럼 왜 zsh에서 죽을 수 없습니까?

나는 내 시스템을 포크 폭탄에 더 탄력적으로 만들고 싶습니다. 이는 systemd에 대한 인수를 사용하거나 cgrulesengd를 통해 모든 유효한 쉘 에 대한 컨트롤러를 DefaultTasksMax사용하여 부분적으로 달성할 수 있습니다 .cgrouppids

*:bash               pids                             users/shells/bash/
*:zsh                pids                             users/shells/zsh/

쉘 제한을 설정하기 위한 작은 스크립트도 있습니다:

CGDIR=/sys/fs/cgroup/
mkdir -p       $CGDIR/pids/users/shells/
echo '8192'  > $CGDIR/pids/users/shells/pids.max
mkdir -p       $CGDIR/pids/users/shells/bash/
echo '2048'  > $CGDIR/pids/users/shells/bash/pids.max
mkdir -p       $CGDIR/pids/users/shells/zsh/
echo '1024'  > $CGDIR/pids/users/shells/zsh/pids.max

bash 쉘을 사용하여 터미널을 시작하고 :(){ :|:& };:실행하면 아무 일도 일어나지 않습니다. pids.current50-60%의 CPU 사용률로 거의 즉시 2048을 얻습니다 . 터미널을 닫으면 포크폭탄이 사라지고 모든 것이 정상으로 돌아갑니다.

zsh 쉘을 사용하여 터미널에서 동일한 작업을 수행하려는 경우 즉시 100% CPU를 사용하고 터미널을 닫은 후에도 포크 폭탄으로 인해 시스템이 여전히 종료됩니다. 이 문제를 해결하는 유일한 방법은 killall -9 zsh다른 쉘이 있는 터미널에서 명령을 여러 번 실행하는 것입니다.

bash에서 포크 폭탄이 죽는 것처럼 왜 zsh에서 죽을 수 없습니까? 즉, 터미널을 닫으면 폭탄이 터질 것입니다.

답변1

에서 EAGAIN이 실패 bash하면 fork()제한에 도달하면(setrlimit 사용 또는 해당 cgroup pid 제한 사용) 절전 모드로 bash전환하고 1초 후에 다시 시도한 다음 2초 후에(다시 실패할 경우), 4초 후에 절전 모드로 전환합니다. 8초 동안 더 포크(!)) 시도도 하지 않고 포기합니다.

그런 다음 bash한도에 도달하면(조용한 시스템에서는 1초 미만) 대부분의 bash가 절전 모드로 처리됩니다. 이것이 포크폭탄이 bash다른 포탄보다 훨씬 덜 해로운 이유입니다.

터미널을 닫아도 이러한 프로세스는 종료되지 않습니다. 아마도 여러분이 보고 있는 것은 15초가 조금 넘는 시간(1+2+4+8) 후에 포크 폭탄이 사라지는 것입니다. 이 시점에서 성공적으로 시작되고 절전 모드로 전환된 모든 프로세스는 시작된 지 8초 후에 동시에 종료됩니다. 네 번째 포크 시도.

에서는 zsh재시도 및 절전 모드가 없으며 모든 프로세스가 분기되어 종료됩니다. 프로세스가 종료되면 포크된 프로세스 중 하나에서 사용할 수 있도록 프로세스가 해제됩니다.

포크 폭탄을 종료하려는 경우 가장 쉬운 방법은 전체 프로세스 그룹을 종료하는 것입니다. 이는 프로세스 목록을 수집한 다음 각 프로세스에 대해 개별적으로 종료를 보내야 하기 killall때문에 실현 가능하지 않습니다 . killall모든 프로세스가 절전 모드인 경우에는 문제가 없지만 bash프로세스가 항상 생성되어 각 종료 사이에 시작될 수 있는 다른 셸에는 적합하지 않습니다.

를 사용하여 pgid를 얻을 수 ps -j있고 를 사용하여 프로세스 그룹을 종료할 수 있습니다 kill -- "-$pgid".

관련 정보