отслеживание родительского процесса - PullRequest
9 голосов
/ 07 февраля 2010

Может ли дочерний процесс использовать системный вызов ptrace для отслеживания своего родителя?

ОС - это Linux 2.6

Спасибо.

upd1: Я хочу отследить process1 от "себя". Это невозможно, поэтому я делаю fork и пытаюсь сделать ptrace(process1_pid, PTRACE_ATTACH) из дочернего процесса. Но я не могу, есть странная ошибка, как ядро ​​запрещает дочерним процессам отслеживать их родительские процессы

UPD2: такая трассировка может быть запрещена политиками безопасности. Какие политики делают это? Где проверочный код в ядре?

UPD3: в моем встроенном linux у меня нет ошибок с PEEKDATA, но не с GETREGS:

child: getregs parent: -1
errno is 1, strerror is Operation not permitted 

errno = EPERM

Ответы [ 2 ]

7 голосов
/ 07 февраля 2010

Этот вопрос действительно интересовал меня. Поэтому я написал некоторый код, чтобы опробовать его.

Во-первых, имейте в виду, что при отслеживании процесса процесс отслеживания становится родительским для большинства целей, за исключением имени (т.е. getppid()). Во-первых, полезен фрагмент раздела PTRACE_ATTACH руководства:

   PTRACE_ATTACH
          Attaches to the process specified in pid,  making  it  a  traced
          "child"  of the calling process; the behavior of the child is as
          if it had done a PTRACE_TRACEME.  The calling  process  actually
          becomes the parent of the child process for most purposes (e.g.,
          it will receive notification of  child  events  and  appears  in
          ps(1)  output  as  the  child's parent), but a getppid(2) by the
          child will still return the PID of  the  original  parent.   The
          child  is  sent a SIGSTOP, but will not necessarily have stopped
          by the completion of this call; use  wait(2)  to  wait  for  the
          child to stop.  (addr and data are ignored.)

Теперь вот код, который я написал, чтобы проверить и убедиться, что вы действительно можете ptrace() ваш родитель (вы можете создать его, поместив его в файл с именем blah.c и запустив make blah:

#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>

int main()
{
    pid_t pid = fork();
    assert(pid != -1);
    int status;
    long readme = 0;
    if (pid)
    {
        readme = 42;
        printf("parent: child pid is %d\n", pid);
        assert(pid == wait(&status));
        printf("parent: child terminated?\n");
        assert(0 == status);
    }
    else
    {
        pid_t tracee = getppid();
        printf("child: parent pid is %d\n", tracee);
        sleep(1); // give parent time to set readme
        assert(0 == ptrace(PTRACE_ATTACH, tracee));
        assert(tracee == waitpid(tracee, &status, 0));
        printf("child: parent should be stopped\n");
        printf("child: peeking at parent: %ld\n", ptrace(PTRACE_PEEKDATA, tracee, &readme));
    }
    return 0;
}

Обратите внимание, что я использую репликацию виртуального адресного пространства родителя, чтобы знать, где искать. Также обратите внимание, что когда ребенок завершает работу, я подозреваю, что есть неявное отсоединение, которое должно позволить родителю продолжить, я больше не расследовал.

1 голос
/ 08 февраля 2010

Да, это возможно ... Даже GETREGS работает. Проверено на x86 (на основе кода Мэтта Джойнера, спасибо ему)

#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/user.h>

int main()
{
    pid_t pid = fork();
//    assert(pid != -1);
    int status;
    long readme = 0;
    struct user_regs_struct regs;
    if (pid)
    {
        readme = 42;
        printf("parent: child pid is %d\n", pid);
        assert(pid == wait(&status));
        printf("parent: child terminated?\n");
        assert(0 == status);
    }
    else
    {
        pid_t tracee = getppid();
        printf("child: parent pid is %d\n", tracee);
        sleep(1); // give parent time to set readme
        assert(0 == ptrace(PTRACE_ATTACH, tracee));
        assert(tracee == waitpid(tracee, &status, 0));
        printf("child: parent should be stopped\n");
        printf("child: peeking at parent: %ld\n", ptrace(PTRACE_PEEKDATA, tracee, &readme, NULL));
        printf("Regs was %p, %p, %p, %p; &status is %p \n", regs.eax, regs.ebx, regs.ecx, regs.edx, &status);
        printf("child: getregs parent: %ld\n", ptrace(PTRACE_GETREGS, tracee, NULL, &regs));
        printf("Regs is %p, %p, %p, %p; &status is %p \n", regs.eax, regs.ebx, regs.ecx, regs.edx, &status);
    }
    return 0;
}

результат:

child: parent pid is 1188
parent: child pid is 1189
child: parent should be stopped
child: peeking at parent: 42
Regs was (nil), (nil), (nil), (nil); &status is 0xbfffea50
child: getregs parent: 0
Regs is 0xfffffe00, 0xffffffff, 0xbfffea50, (nil); &status is 0xbfffea50
parent: child terminated?
...