Search code examples
linuxforktraceptrace

ptrace'ing of parent process


Can child process use the ptrace system call to trace its parent?

Os is linux 2.6

Thanks.

upd1: I want to trace process1 from "itself". It is impossible, so I do fork and try to do ptrace(process1_pid, PTRACE_ATTACH) from child process. But I can't, there is a strange error, like kernel prohibits child from tracing their parent processes

UPD2: such tracing can be prohibited by security policies. Which polices do this? Where is the checking code in the kernel?

UPD3: on my embedded linux I have no errors with PEEKDATA, but not with GETREGS:

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

errno = EPERM


Solution

  • This question really interested me. So I wrote some code to try it out.

    Firstly keep in mind, that when tracing a process, the tracing process becomes a parent for most purposes, except in name (i.e. getppid()). Firstly, a snippet of the PTRACE_ATTACH section of the manual is helpful:

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

    Now here is the code I wrote to test and verify that you can in fact ptrace() your parent (you can build this by dumping it in a file named blah.c and running 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;
    }
    

    Note that I'm exploiting the replication of the parent's virtual address space to know where to look. Also note that when the child then terminates, I suspect there's an implicit detach which must allow the parent to continue, I didn't investigate further.