首页 > 解决方案 > ptrace PTRACE_EVENT_FORK 挂起

问题描述

嗨,我正在尝试创建一个程序 fork 并在 child 中执行 /bin/sh 并跟踪 /bin/sh 内的所有系统调用,每次你在 sh shell 中编写命令时,sh 二进制文件将 fork() 并产生一个新进程,我知道我应该使用PTRACE_O_TRACEFORK,无论如何,每当我得到PTRACE_EVENT_FORK时,我都能够获取新的进程 PID,但我无法让它继续执行.. 这是我的代码,非常感谢!

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

#define elog(...) fprintf(stderr, __VA_ARGS__)
#define FILE_EXISTS(f) (access(f, F_OK ) != -1)
#define SAFECHECK(r,e,f) (r!=e?fatal(f):0)
#define IS_EVENT(s,e) (s >> 8 == (SIGTRAP| e << 8))

void fatal(char * f) {
  perror(f);
  abort();
}

void set_self_trace() {
  SAFECHECK(ptrace(PTRACE_TRACEME, 0, 0, 0), 0, "ptrace(PTRACE_TRACEME)");
  raise(SIGSTOP);
}

void parent_set_child_options(int pid, int options) {
  // PTRACE_O_TRACEEXEC
  int status;
  waitpid(pid, &status, 0);
  assert(WIFSTOPPED(status));
  SAFECHECK(ptrace(PTRACE_SETOPTIONS, pid, 0, options), 0, "ptrace(PTRACE_SETOPTIONS)");
  SAFECHECK(ptrace(PTRACE_CONT, pid, 0, 0), 0, "ptrace(PTRACE_CONT)");
}

long get_ptrace_eventmsg(int pid) {
  long result;
  SAFECHECK(ptrace(PTRACE_GETEVENTMSG, pid, 0, &result), 0, "ptrace(PTRACE_GETEVENTMSG)");
  return result;
}

int main(int argc, char **argv) {
  if(argc > 1) {
    if(FILE_EXISTS(argv[1])) {
      int pid = fork();
      if(pid == 0) {
        set_self_trace();
        char * envp[] = {NULL};
        execve(argv[1], &argv[1], envp);
      }else{
        parent_set_child_options(pid, PTRACE_O_TRACEFORK);
        int s;
        int wait_pid;
        elog("Child pid: %d\n", pid);
        while(1) {
          wait_pid = waitpid(pid, &s, __WALL);
          if(wait_pid == -1) {
            fatal("waitpid(-1, __WALL)");
          }
          if(WIFSTOPPED(s) && WSTOPSIG(s) == SIGTRAP) {
            // We got an event!
            int event = (s >> 8);
            switch (event) {
              case (SIGTRAP | PTRACE_EVENT_EXEC << 8):
                elog("Got event PTRACE_EVENT_EXEC\n", event);
                SAFECHECK(ptrace(PTRACE_CONT, wait_pid, 0, 0), 0, "ptrace(PTRACE_CONT)");
                break;
              case (SIGTRAP | PTRACE_EVENT_FORK << 8):
                elog("Got event PTRACE_EVENT_FORK\n", event);
                long new_child = get_ptrace_eventmsg(wait_pid);
                elog("Forked to proc: %d\n", new_child);
                // THOSE WON'T WORK HERE new_Child HANG I SUPPOSE
                SAFECHECK(ptrace(PTRACE_CONT, new_child, 0, 0), 0, "ptrace(PTRACE_CONT) (new_child)");
                SAFECHECK(ptrace(PTRACE_CONT, wait_pid, 0, 0), 0, "ptrace(PTRACE_CONT)");
                // END
                break;
              default:
                elog("Uknown event %d\n", event);
                SAFECHECK(ptrace(PTRACE_CONT, wait_pid, 0, 0), 0, "ptrace(PTRACE_CONT)");
            }
          }else if(WIFEXITED(s)) {
            elog("Process %d exited with status code: %d\n", wait_pid, WEXITSTATUS(s));
            break;
          }else if(WIFSIGNALED(s)) {
            elog("Process %d exited received signal: %d\n", wait_pid, WTERMSIG(s));
            break;
          }
        }
      }
    }else{
      elog("File %s does not exists!\n", argv[1]);
    }
  }else{
    elog("%s\n","Missing arguments.");
    elog("Usage: %s <program> <arguments>\n", argv[0]);
  }
}

这是执行输出:

dan@host:~/Scrivania/tracer$ ./tracer /bin/sh
Child pid: 11688
Got event PTRACE_EVENT_EXEC
$ id
Got event PTRACE_EVENT_FORK
Forked to proc: 11689

*** HERE HANG /usr/bin/id IS NEVER EXECUTED**

标签: clinuxsystem-callsptrace

解决方案


推荐阅读