복붙노트

[PYTHON] 부모와 자식 살해

PYTHON

부모와 자식 살해

나는 CPU가 무겁고 불안정한 프로세스를 만들어 내고 의사 소통하는 프로그램을 가지고 있습니다. 내 응용 프로그램이 충돌하거나 SIGKILL에 의해 죽는다면, 나는 서브 프로세스가 죽기를 원하기 때문에 사용자는 그들을 추적하여 수동으로 죽일 필요가 없다.

나는이 주제가 이전에 다뤄 졌음을 알고 있지만 설명 된 모든 방법을 시도했지만 그 중 아무 것도 테스트에서 살아남을 수없는 것 같습니다.

터미널이 항상 그렇게하기 때문에 가능해야한다는 것을 알고 있습니다. 터미널에서 무언가를 실행하고 터미널을 죽이면 그 물건은 항상 죽습니다.

나는 atexit, double fork 및 ptys를 시도했다. atexit은 sigkill에 대해 작동하지 않습니다. 이중 포크가 전혀 작동하지 않습니다. 그리고 ptys 나는 파이썬을 사용하여 작업 할 수있는 방법을 찾지 못했습니다.

오늘은 prctl (PR_SET_PDEATHSIG, SIGKILL)에 대해 알아 냈습니다. PRTET_PDEATHSIG는 자식 프로세스가 부모 프로세스가 종료 될 때 자체 프로세스를 강제 종료하도록 지시해야합니다. 나는 그것을 popen과 함께 사용하려했지만, 아무런 효과가없는 이음새가있다 :

import ctypes, subprocess
libc = ctypes.CDLL('/lib/libc.so.6')
PR_SET_PDEATHSIG = 1; TERM = 15
implant_bomb = lambda: libc.prctl(PR_SET_PDEATHSIG, TERM)
subprocess.Popen(['gnuchess'], preexec_fn=implant_bomb)

위의 경우, 자식이 만들어지고 부모가 종료됩니다. 이제 당신은 멍청이가 SIGKILL을 받고 죽을 것이라고 기대하지만, 그렇지는 않습니다. 100 % CPU를 사용하는 프로세스 관리자에서 계속 찾을 수 있습니다.

아무도 내 prctl 사용에 문제가 있는지 말해 줄 수 있습니까? 또는 터미널에서 어떻게 자녀를 죽일 수 있는지 알고 있습니까?

해결법

  1. ==============================

    1.prctl의 PR_SET_DEATHSIG는 prctl을 호출하는 바로 그 프로세스에 대해서만 설정할 수 있습니다 -이 특정 프로세스의 하위를 포함하여 다른 프로세스에는 해당되지 않습니다. 내가 가리키고있는 맨 페이지는 "이 값은 fork ()에서 지워집니다"입니다 - 물론 포크는 다른 프로세스가 생성되는 방식입니다 (Linux 및 다른 Unix-y OS에서).

    prctl의 PR_SET_DEATHSIG는 prctl을 호출하는 바로 그 프로세스에 대해서만 설정할 수 있습니다 -이 특정 프로세스의 하위를 포함하여 다른 프로세스에는 해당되지 않습니다. 내가 가리키고있는 맨 페이지는 "이 값은 fork ()에서 지워집니다"입니다 - 물론 포크는 다른 프로세스가 생성되는 방식입니다 (Linux 및 다른 Unix-y OS에서).

    서브 프로세스에서 실행하고자하는 코드에 대한 제어권이 없다면 (사실, gnuchess 예제와 같이) 필자는 먼저 작은 "모니터"프로세스를 생성하는 것이 좋습니다. 그것의 형제 자매 (당신의 부모 과정은 모니터가 그 형제 자매의 pids에 관해서 그것을 알게 할 수 있습니다.) 그리고 일반 부모가 죽었을 때 살인자 신호를 보냅니다. (모니터는 그것을 조사해야합니다. N 초 동안 잠에서 깨어나야합니다. 부모가 아직 살아 있는지 확인하기위한 선택, 루프 내에서 N 초의 시간 초과가있는 부모로부터 추가 정보를 기다리려면 select를 사용하십시오.

    평범하지는 않지만 그런 시스템 작업은 종종 그렇지 않습니다. 터미널은 다르게 (프로세스 그룹의 "제어 터미널"이라는 개념을 통해) 수행하지만 물론 모든 자식이이를 차단하는 것은 쉽지 않습니다 (이중 분기, nohup 등).

  2. ==============================

    2.몇 년이 걸렸다는 것을 알고 있지만이 문제에 대한 간단한 (약간 해키 한) 해결책을 발견했습니다. 상위 프로세스에서 모든 호출을 prctl ()을 호출 한 매우 간단한 C 프로그램으로 래핑 한 다음 exec ()를 사용하면 Linux에서이 문제를 해결할 수 있습니다. 나는 그것을 "yeshup"이라고 부른다.

    몇 년이 걸렸다는 것을 알고 있지만이 문제에 대한 간단한 (약간 해키 한) 해결책을 발견했습니다. 상위 프로세스에서 모든 호출을 prctl ()을 호출 한 매우 간단한 C 프로그램으로 래핑 한 다음 exec ()를 사용하면 Linux에서이 문제를 해결할 수 있습니다. 나는 그것을 "yeshup"이라고 부른다.

    #include <linux/prctl.h>
    #include <signal.h>
    #include <unistd.h>
    
    int main(int argc, char **argv) {
         if(argc < 2)
              return 1;
         prctl(PR_SET_PDEATHSIG, SIGHUP, 0, 0, 0);
         return execvp(argv[1], &argv[1]);
    }
    

    자식 프로세스를 파이썬 (또는 다른 언어)에서 생성 할 때 "yeshup gnuchess [argments]"를 실행할 수 있습니다. 부모 프로세스가 종료되면 모든 자식 프로세스가 올바르게 처리되어야 함을 알 수 있습니다.

    이는 forkv ()와는 달리 execvp가 호출 된 후에도 Linux가 prctl에 대한 호출을 받아들이 기 때문에 (yeshup 프로세스를 gnuchess 프로세스 또는 사용자가 지정한 명령으로 효과적으로 "변환"하기 때문에) 작동합니다.

  3. ==============================

    3.실제로 원래의 접근 방식이 저에게 잘 돌아갔다는 것을 알았습니다. 제가 테스트 한 정확한 예제 코드는 다음과 같습니다.

    실제로 원래의 접근 방식이 저에게 잘 돌아갔다는 것을 알았습니다. 제가 테스트 한 정확한 예제 코드는 다음과 같습니다.

    echoer.py

    #!/bin/env python
    
    import time
    import sys
    i = 0
    try:
        while True:
            i += 1
            print i
            time.sleep(1)
    except KeyboardInterrupt:
        print "\nechoer caught KeyboardInterrupt"
        exit(0)
    

    parentProc.py

    #!/bin/env python
    
    import ctypes
    import subprocess
    import time
    
    libc = ctypes.CDLL('/lib64/libc.so.6')
    PR_SET_PDEATHSIG = 1
    SIGINT = 2
    SIGTERM = 15
    
    def set_death_signal(signal):
        libc.prctl(PR_SET_PDEATHSIG, signal)
    
    def set_death_signal_int():
        set_death_signal(SIGINT)
    
    def set_death_signal_term():
        set_death_signal(SIGTERM)
    
    #subprocess.Popen(['./echoer.py'], preexec_fn=set_death_signal_term)
    subprocess.Popen(['./echoer.py'], preexec_fn=set_death_signal_int)
    time.sleep(1.5)
    print "parentProc exiting..."
    
  4. ==============================

    4.더블 포크는 제어 터미널에서 분리하는 것이었다. 어떻게 사용하려고하는지 잘 모르겠습니다.

    더블 포크는 제어 터미널에서 분리하는 것이었다. 어떻게 사용하려고하는지 잘 모르겠습니다.

    그것은 해킹이지만, 당신은 언제나 'ps'라고 부르며 죽이려고하는 프로세스 이름을 검색 할 수 있습니다.

  5. ==============================

    5.나는 ps xuawww와 같은 것을 사용하여 "정리"하는 매우 불쾌한 방법을 보았다. grep myApp | awk '{print $ 1}'| xargs -n1 kill -9

    나는 ps xuawww와 같은 것을 사용하여 "정리"하는 매우 불쾌한 방법을 보았다. grep myApp | awk '{print $ 1}'| xargs -n1 kill -9

    클라이언트 프로세스가 populate되면 SIG_PIPE를 catch하여 죽을 수 있습니다. 이 문제를 해결할 수있는 방법은 여러 가지가 있지만 실제로 많은 요소에 따라 달라집니다. 자식에게 ping 코드 (부모에게 ping)를 보내면 사망시 SIG_PIPE가 발행되도록 할 수 있습니다. 그것이 잡히면, 그것은 끝내야 만합니다. 제대로 작동하려면 양방향 통신이 필요하거나 통신의 발신자 인 클라이언트를 항상 차단해야합니다. 하위 항목을 수정하지 않으려면이 항목을 무시하십시오.

    실제 파이썬 인터프리터가 segfault를 기대하지 않는다고 가정하면 각 PID를 시퀀스에 추가 한 다음 종료시 종료 할 수 있습니다. 이것은 빠져 나오거나 심지어 잡히지 않는 예외에도 안전해야합니다. 파이썬에는 정리를 위해 종료 코드를 수행 할 수있는 기능이 있습니다.

    더 안전한 방법은 다음과 같습니다. 마스터 프로세스 (별도 파일)를 포함하여 각 하위 PID를 파일에 추가합니다. 파일 잠금을 사용하십시오. 마스터 PID의 flock () 상태를 확인하는 워치 독 데몬을 빌드하십시오. 잠겨 있지 않으면 자식 PID 목록의 모든 PID를 삭제하십시오. 시작시 동일한 코드를 실행하십시오.

    더 심한 경우 : 위와 같이 파일에 PID를 작성한 다음 하위 셸에서 앱을 호출합니다. (./myMaster; ./killMyChildren)

  6. ==============================

    6.PR_SET_PDEATHSIG 플래그가 지워지는지 궁금 해서요, 비록 당신이 포크 후 (그리고 exec 전에) 설정 했더라도, 문서가 보이지 않게되어서는 안된다.

    PR_SET_PDEATHSIG 플래그가 지워지는지 궁금 해서요, 비록 당신이 포크 후 (그리고 exec 전에) 설정 했더라도, 문서가 보이지 않게되어서는 안된다.

    그 이론을 테스트하기 위해서 다음과 같이해볼 수 있습니다. 동일한 코드를 사용하여 C로 작성된 서브 프로세스를 실행하고 기본적으로 prctl (PR_GET_PDEATHSIG, & result)을 호출하고 그 결과를 인쇄합니다.

    시도 할 수도있는 다른 방법 : prctl을 호출 할 때 arg3, arg4 및 arg5에 명시적인 0을 추가하십시오. 나는

    >>> implant_bomb = lambda: libc.prctl(PR_SET_PDEATHSIG, TERM, 0, 0, 0)
    
  7. ==============================

    7.우리가 execv 후에 setuid를 호출하면 자식이 신호를받을 수 없기 때문에 고려해야 할 몇 가지 보안 제한이 있습니다. 이 제한 사항의 전체 목록은 여기에 있습니다.

    우리가 execv 후에 setuid를 호출하면 자식이 신호를받을 수 없기 때문에 고려해야 할 몇 가지 보안 제한이 있습니다. 이 제한 사항의 전체 목록은 여기에 있습니다.

    행운을 빕니다 ! / 모하메드

  8. from https://stackoverflow.com/questions/1884941/killing-the-children-with-the-parent by cc-by-sa and MIT license