strace는 어떻게 자체를 모니터링합니까?

strace는 어떻게 자체를 모니터링합니까?

가상의 상황이 있습니다.

  1. 서로를 모니터링하는 두 개의 strace 프로세스 S1과 S2가 있다고 가정합니다.
    어떻게 이럴 수있어?
    strace의 명령줄 옵션에는 -p PID필요한 PID를 전달하는 방법이 있는데, 우리의 경우 strace 명령을 실행할 때 이를 알 수 없습니다. strace 소스 코드를 변경할 수 있습니다. 이는 -P 0사용자에게 PID를 묻는 것을 의미합니다. 예를 들어 STDIN의 read()입니다. 두 개의 셸 세션에서 두 개의 strace 프로세스를 실행하고 세 번째 셸에서 PID를 찾을 수 있으면 해당 입력을 S1과 S2에 제공하고 서로 모니터링하도록 할 수 있습니다.
    S1과 S2가 막히나요? 아니면 무한 루프에 들어가거나 즉시 충돌하거나...?

  2. 다시 말하지만, 또 다른 strace 프로세스 S3이 있다고 가정하고 -p -1이를 사용하여 소스 코드를 수정하여 S3에게 자체 모니터링을 지시합니다. 예를 들어 STDIN 대신 getpid()를 사용합니다. S3가 충돌할까요? 아니면 추가 처리 없이 중단되나요? 어떤 이벤트가 발생하기를 기다리지만 기다리고 있기 때문에 아무 일도 일어나지 않습니까?

strace 매뉴얼 페이지에는 init 프로세스를 모니터링할 수 없다고 나와 있습니다.순환 종속성 또는 순환을 피하기 위해 strace 또는 커널에 의해 시행되는 다른 제한 사항이 있습니까?

일부 특수한 경우:
S4는 S5를 모니터링하고, S5는 S6을 모니터링하고, S6은 S4를 모니터링합니다.
S7과 S8은 S7이 S8의 상위가 되어 서로 모니터링합니다.
더 특별한 경우도 가능합니다.

편집(@Ralph Rönnquist 및 @pfnuesel의 댓글 이후):
https://github.com/bnoordhuis/strace/blob/master/strace.c#L941

if (pid <= 0) {
    error_msg_and_die("Invalid process id: '%s'", opt);
}
if (pid == strace_tracer_pid) {
    error_msg_and_die("I'm sorry, I can't let you do that, Dave.");
}

strace.c구체적으로 pid == strace_tracer_pid검사가 이루어지지 않거나 기타 특별한 사정이 있는 경우에는 어떻게 되나요? 프로세스 모니터 자체에 (커널에) 기술적 제한이 있습니까? 2개(또는 3개 이상) 프로세스 그룹이 스스로를 모니터링하는 것은 어떻습니까? 시스템이 충돌하거나 중단됩니까?

답변1

% sh -c 'exec strace -p $$'    
strace: I'm sorry, I can't let you do that, Dave.

:-)

답변2

나는 리눅스에만 대답한다.

놀랍게도 최신 커널에서는 ptrace실제로 추적을 수행하기 위해 사용되는 시스템 호출이 init 프로세스를 추적하도록 허용됩니다. strace매뉴얼 페이지에는 다음과 같이 나와 있습니다.

   EPERM  The specified process cannot be traced.  This could  be  because
          the  tracer has insufficient privileges (the required capability
          is CAP_SYS_PTRACE); unprivileged  processes  cannot  trace  pro‐
          cesses  that  they  cannot send signals to or those running set-
          user-ID/set-group-ID programs, for  obvious  reasons.   Alterna‐
          tively,  the process may already be being traced, or (on kernels
          before 2.6.26) be init(8) (PID 1).

이는 버전 2.6.26부터 추적할 수 있음을 의미합니다 init. 물론 이를 수행하려면 루트 권한이 있어야 합니다. 내 시스템의 바이너리를 strace사용하면 이를 추적할 수 있으며 init실제로 이를 사용하여 gdb연결 init하고 종료할 수도 있습니다. (이렇게 하면 시스템이 즉시 중지됩니다.)

ptrace프로세스는 이를 사용하여 자체를 추적할 수 없으므로 strace선택하지 않으면 자체 추적 중에 계속 실패합니다. 다음 절차:

#include <sys/ptrace.h>
#include <stdio.h>
#include <unistd.h>
int main() {
    if (ptrace(PTRACE_ATTACH, getpid(), 0, 0) == -1) {
        perror(NULL);
    }
}

인쇄 Operation not permitted(즉,) EPERM. 커널 실행이번 숙박ptrace.c:

 retval = -EPERM;
 if (unlikely(task->flags & PF_KTHREAD))
         goto out;
 if (same_thread_group(task, current)) // <-- this is the one
         goto out;

이제 두 strace프로세스는 서로를 추적할 수 있습니다. 커널은 이를 방지하지 않으며 결과를 직접 관찰할 수 있습니다. 내 경우 첫 번째 프로세스(PID = 5882)에서 마지막으로 인쇄된 내용은 다음 strace과 같습니다.

ptrace(PTRACE_SEIZE, 5882, 0, 0x11

그리고 두 번째 strace프로세스(PID = 5890)는 전혀 아무것도 인쇄하지 않습니다. ps는 두 프로세스가 모두 상태에 있음을 보여줍니다 t. proc(5)맨 페이지에 따르면 이는 추적이 중지되었음을 의미합니다.

이런 일이 발생하는 이유는 SIGKILL추적자가 시스템 호출에 들어가거나 나갈 때마다 중지되고 신호(예외)가 전달되려고 하기 때문입니다.

프로세스 5882가 이미 프로세스 5890을 추적하고 있다고 가정합니다. 그러면 우리는 다음과 같은 일련의 사건을 추론할 수 있습니다.

  1. 프로세스 5890은 ptrace시스템 호출을 시작하고 프로세스 5882를 추적하려고 시도합니다. 프로세스 5890이 추적 중지에 들어갑니다.
  2. 프로세스 5882에는 SIGCHLD추적 중인 프로세스 5890이 중지되었음을 알립니다. (추적된 중지된 프로세스는 "SIGTRAP" 신호를 받은 것처럼 보입니다.)
  3. 프로세스 5882는 추적 대상이 시스템 호출을 수행한 것을 확인하고 프로세스 5890이 수행하려는 시스템 호출에 대한 정보와 매개변수를 충실하게 인쇄합니다. 이것이 마지막 출력입니다.
  4. ptrace(PTRACE_SYSCALL, 5890, ...)프로세스 5890이 계속되도록 5882 호출을 처리합니다 .
  5. 프로세스 5890은 추적 중지를 종료하고 이를 실행합니다 ptrace(PTRACE_SEIZE, 5882, ...). 후자가 반환되면 프로세스 5890이 추적 중지로 들어갑니다.
  6. SIGCHLD추적 대상이 방금 다시 중지되었기 때문에 프로세스 5882가 전송되었습니다 . 추적 중이므로 신호를 수신하면 추적 중지 상태로 들어갑니다.

이제 두 프로세스가 모두 중지되었습니다.마치다.

이 예에서 볼 수 있듯이 두 프로세스가 서로 추적하는 상황은 커널에 본질적인 논리적 어려움을 초래하지 않습니다. 이는 아마도 커널 코드에 이러한 상황을 방지하기 위한 검사가 포함되어 있지 않은 이유일 것입니다. 서로를 추적하는 두 프로세스에는 그다지 유용하지 않습니다.

답변3

시스템을 정지시킬 수 있는 순환 종속성 또는 루프의 실제 예를 보여드리고 싶었습니다.

X 세션 및 그래픽 터미널 에뮬레이터에서 다음 명령을 실행하여 Xorg.bin pid를 얻습니다.

[xiaobai@xiaobai tmp]$ pgrep Xorg
1780
[xiaobai@xiaobai tmp]$

그런 다음 다음을 수행하십시오.

[xiaobai@xiaobai tmp]$ sudo strace -p 1780

몇 초(~5초) 후에 Fedora 21 gnome 3.14.0에서는 전체 데스크탑이 정지되고 전원 버튼을 꺼야 합니다.

sudo strace -p 1780그러나 Ctrl-alt-F1|7 또는 다른 tty를 통해 실행 하려고 하면 sudo strace -p 1780 2>/tmp/strace.log둘 다 정지되지 않습니다.

따라서 우리는 strace가 Xorg의 출력을 수신한 다음 이를 Xorg에 인쇄하고 무한 루프 및 정지를 발생시킨다고 결론을 내릴 수 있습니다.

관련 정보