Как strace может контролировать себя?

Я думаю, что хорошо включить опции ls таким образом, поскольку cd не принимает никаких опций.

cdls() {
  cd ${$#} && ls ${@:0:$#-1}
}
5
12.02.2017, 12:41
1 ответ

Я отвечу только за Linux.

Удивительно, но в новых ядрах системный вызов ptrace , который используется 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 , хотя, конечно, вы все еще должны быть root, чтобы сделать это. Бинарный файл 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);
    }
}

печатает Операция запрещена ( т.е. результат 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 могут отслеживать друг друга; ядро этому не помешает, и вы сами можете наблюдать за результатом. Для меня последнее, что выводит первый процесс strace (PID = 5882), это:

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. Процесс 5882 вызывает ptrace (PTRACE_SYSCALL, 5890, ...) , чтобы продолжить процесс 5890.
  5. Процесс 5890 выходит из остановки трассировки и выполняет свою ptrace (PTRACE_SEIZE, 5882, ...) . Когда последний возвращается, процесс 5890 переходит в режим остановки трассировки.
  6. Процесс 5882 отправляется SIGCHLD , поскольку его трассируемый объект только что снова остановился. Поскольку он отслеживается, получение сигнала приводит к переходу к остановке трассировки.

Теперь оба процесса остановлены. Конец.

Как вы можете видеть из этого примера, ситуация, когда два процесса отслеживают друг друга, не создает никаких внутренних логических трудностей для ядра, вероятно, поэтому код ядра не содержит проверки, предотвращающей возникновение такой ситуации.Просто бывает не очень полезно, чтобы два процесса отслеживали друг друга.

4
27.01.2020, 20:33

Теги

Похожие вопросы