Como o strace pode monitorar a si mesmo?

4

Eu tenho uma situação hipotética:

  1. Vamos dizer que temos dois processos strace S1 & S2, que estão simplesmente monitorando um ao outro.
    Como isso pode ser possível?
    Bem, nas opções de linha de comando para strace, -p PID é a maneira de passar o PID necessário, que (no nosso caso) ainda não é conhecido quando emitimos o comando strace. Poderíamos alterar o código-fonte strace, tal que -P 0 significa, pergunte ao usuário para PID. Por exemplo, leia () de STDIN. Quando podemos executar dois processos de strace em duas sessões de shell e encontrar os PIDs em um terceiro shell, podemos fornecer essa entrada para S1 & S2 e deixá-los monitorar uns aos outros.
    S1 & S2 fica preso? Ou entrar em loops infinitos ou travar imediatamente ou ...?

  2. Novamente, vamos dizer que temos outro processo de strace S3, com -p -1 , que, modificando o código-fonte, usamos para dizer ao S3 para monitorar a si mesmo. Por exemplo, use getpid () sem usar STDIN. O S3 travaria? Ou seria suspenso sem mais processamento possível? Esperaria que algum evento acontecesse, mas, porque está esperando, nenhum evento aconteceria?

Na página man strace, diz que não podemos monitorar um processo de inicialização. Existe alguma outra limitação imposta pela strace, ou pelo kernel, para evitar uma dependência circular ou loop?

Alguns casos especiais:
S4 monitora S5, S5 monitora S6, S6 monitora S4.
S7 & S8 monitorando um ao outro onde S7 é o pai do S8.
Casos mais especiais são possíveis.

EDIT (após comentários de @Ralph Rönnquist & @pfnuesel): link / a>

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.");
}

Especificamente, o que acontecerá se strace.c não verificar pid == strace_tracer_pid ou outros casos especiais? Existe alguma limitação técnica (no kernel) sobre o próprio processo de monitoramento? Que tal um grupo de 2 (ou 3 ou mais) processos monitorando-se? O sistema irá falhar ou travar?

    
por Prem 29.02.2016 / 05:00

3 respostas

7

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

: -)

    
por 29.02.2016 / 05:45
2

Só quero mostrar um exemplo real de Dependência circular ou loop que pode causar o congelamento do sistema.

Em sua sessão X e no emulador de terminal gráfico, execute este comando para obter o pid do Xorg.bin:

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

Então faça:

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

Ele irá congelar toda a área de trabalho após alguns segundos (~ 5), pelo menos no meu fedora 21 gnome 3.14.0, eu tenho que desligar o botão liga / desliga.

Mas se você tentar executar sudo strace -p 1780 no outro tty via Ctrl-alt-F1 | 7 OU sudo strace -p 1780 2>/tmp/strace.log , ambos não congelarão.

Portanto, podemos concluir que o strace recebe a saída do Xorg, depois imprime-o no Xorg e causa infinitamente loop e congelamento.

    
por 10.05.2016 / 09:35
2

Vou responder apenas para Linux.

Surpreendentemente, em novos kernels, a chamada de sistema ptrace , que é usada por strace para realmente executar o rastreio, tem permissão para rastrear o processo init. A página de manual diz:

   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).

sugerindo que a partir da versão 2.6.26, você pode rastrear init , embora, claro, você ainda precise ser root para fazer isso. O binário strace no meu sistema me permite rastrear init e, na verdade, posso até usar gdb para anexar a init e eliminá-lo. (Quando fiz isso, o sistema imediatamente parou).

ptrace não pode ser usado por um processo para se rastrear, portanto, se strace não tiver verificado, ele falhará no rastreamento. O seguinte programa:

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

imprime Operation not permitted ( isto é, o resultado é EPERM ). O kernel executa esta verificação em ptrace.c :

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

Agora, é possível que dois processos strace possam rastrear um ao outro; o kernel não impedirá isso, e você mesmo poderá observar o resultado. Para mim, a última coisa que o primeiro processo strace (PID = 5882) imprime é:

ptrace(PTRACE_SEIZE, 5882, 0, 0x11

enquanto o segundo processo strace (PID = 5890) não imprime nada. ps mostra os dois processos no estado t , que, de acordo com a página de manual proc(5) , significa rastreio interrompido.

Isso ocorre porque uma tracee pára sempre que entra ou sai de uma chamada de sistema e sempre que um sinal está prestes a ser entregue a ela (diferente de SIGKILL ).

Suponha que o processo 5882 já esteja rastreando o processo 5890. Então, podemos deduzir a seguinte sequência de eventos:

  1. O processo 5890 entra na chamada do sistema ptrace , tentando rastrear o processo 5882. O processo 5890 entra no rastreamento-parada.
  2. O processo 5882 recebe SIGCHLD para informar que sua tracee, processo 5890, parou. (Um processo trace-stopped aparece como se recebesse o sinal 'SIGTRAP').
  3. O processo 5882, visto que sua tracee fez uma chamada ao sistema, exibe devidamente as informações sobre o syscall que o processo 5890 está prestes a realizar e os argumentos. Esta é a última saída que você vê.
  4. O processo 5882 chama ptrace(PTRACE_SYSCALL, 5890, ...) para permitir que o processo 5890 continue.
  5. O processo 5890 deixa o rastreio e executa seu ptrace(PTRACE_SEIZE, 5882, ...) . Quando o último retorna, o processo 5890 entra no rastreio.
  6. O processo 5882 é enviado SIGCHLD desde que sua tracee acabou de parar novamente. Como está sendo rastreado, o recebimento do sinal faz com que ele entre no rastreamento.

Agora ambos os processos estão parados. O fim.

Como você pode ver neste exemplo, a situação de dois processos rastreando um ao outro não cria nenhuma dificuldade lógica inerente ao kernel, o que provavelmente é o motivo pelo qual o código do kernel não contém uma verificação para evitar que essa situação aconteça. Acontece que não é muito útil para dois processos traçarem um ao outro.

    
por 12.02.2017 / 10:27