在ptraced Linux进程中调用ptrace

Fin*_*ter 6 c linux ptrace

有人在维基百科上写了一篇文章"ptrace",声称在Linux上,一个ptraced进程本身无法启动另一个进程.我试图确定是否(以及如果是这样的原因)就是这种情况.下面是一个我试图测试的简单程序.我的程序失败(子子进程无法正常运行)但我确信这是我的错误,而不是基本的东西.

在本质上是初始过程叉过程这反过来叉Ç.一个 ptraces其子, ptraces其子Ç.一旦完成设置后,所有三个过程被写入只是打印A,BC到标准输出每秒一次.

在实践中发生的事情是AB工作正常,但C只打印一次然后卡住.检查ps -eo pid,cmd,wchan显示C卡在内核函数中,ptrace_stop而其余的都在hrtimer_nanosleep我希望所有三个都在的位置.

偶尔三个都可以工作(所以程序打印Cs以及As和Bs),这让我相信初始设置中存在一些竞争条件.

猜测可能出现的问题是:

  • 事与做一个看到SIGCHLD相关的B看到SIGCHLD一个信号,做ç,并等待(2)报告既从未来(但PTRACE_CONT的双方的PID哈克调用不解决的事情)?
  • C应该被B跟踪- 而C继承了A的ptrace (B的调用ptrace既没有错也没有覆盖它)?

谁能弄清楚我做错了什么?谢谢.

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

static void a(){
  while(1){
    printf ("A\n");
    fflush(stdout);
    sleep(1);
  }
}

static void b(){
  while(1){
    printf ("B\n");
    fflush(stdout);
    sleep(1);
  }
}

static void c(){
  while(1){
    printf ("C\n");
    fflush(stdout);
    sleep(1);
  }
}

static void sigchld_handler(int sig){
  int result;
  pid_t child_pid = wait(NULL); // find who send us this SIGCHLD

  printf("SIGCHLD on %d\n", child_pid);
  result=ptrace(PTRACE_CONT, child_pid, sig, NULL);
  if(result) {
    perror("continuing after SIGCHLD");
  }
}

int main(int  argc,
         char **argv){

  pid_t mychild_pid;
  int   result;

  printf("pidA = %d\n", getpid());

  signal(SIGCHLD, sigchld_handler);

  mychild_pid = fork();

  if (mychild_pid) {
    printf("pidB = %d\n", mychild_pid);
    result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL);
    if(result==-1){
      perror("outer ptrace");
    }
    a();
  }
  else {
    mychild_pid = fork();

    if (mychild_pid) {
      printf("pidC = %d\n", mychild_pid);

      result = ptrace(PTRACE_ATTACH, mychild_pid, NULL, NULL);
      if(result==-1){
        perror("inner ptrace");
      }
      b();
    }
    else {
      c();
    }
  }

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

caf*_*caf 5

你确实看到了竞争条件.您可以通过sleep(1);第二次 fork()呼叫之前立即重复发生它.

由于进程A未正确地将信号传递给进程B,因此导致竞争条件.这意味着如果进程B在进程A开始跟踪进程B之后开始跟踪进程C,则进程B永远不会获得SIGCHLD指示进程C已停止的信号,所以它永远不会继续下去.

要解决此问题,您只需修复SIGCHLD处理程序:

static void sigchld_handler(int sig){
    int result, status;
    pid_t child_pid = wait(&status); // find who send us this SIGCHLD

    printf("%d received SIGCHLD on %d\n", getpid(), child_pid);
    if (WIFSTOPPED(status))
    {
        result=ptrace(PTRACE_CONT, child_pid, 0, WSTOPSIG(status));
        if(result) {
            perror("continuing after SIGCHLD");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)