簡體   English   中英

Systemcall子父執行問題(fork execve)Linux

[英]Systemcall child-parent execution problem (fork execve) Linux

我是系統調用的新手。 我在孩子內部使用 execve,因此父級應該正常運行並且不會被 execve 覆蓋。 問題是孩子在execve之后執行並停止了整個事情。 我的目標是計算 execve 執行的 bash 命令(參數)中執行的克隆數。

我讀過這個人,我還是有點困惑。 我只能使用 ptrace、fork、wait/waitpid。

爭論:

/bin/bash -c "echo 'first test' | wc -c"
int main(int argc, char *argv[]) {
    pid_t child_pid = fork();
    int status;
    int counter = 0;
    wait(&status);
    if (child_pid == -1) {
        exit(1);
    } else {
        while(status != child_pid){
            if (child_pid == 0) {
                ptrace(PTRACE_TRACEME, child_pid, 0, 0);
                raise(SIGSTOP);
                execve(argv[1], &argv[1], NULL);
                ptrace(PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACECLONE);
                ptrace(PTRACE_CONT, child_pid, 0L, 0L);
                if(status>>8 == (SIGTRAP | (PTRACE_EVENT_CLONE<<8)))
                    counter++;
            }
        }
    }
    printf("# of clone executions: %d", counter);
    return 0;
}

execve會覆蓋子進程,所以execve之后的任何指令都不會被執行,除非調用execve失敗。 您應該改為運行父進程中execve之后出現的ptrace跟蹤

編輯:這是一個計算克隆系統調用數量的注釋解決方案:

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/reg.h> // ORIG_RAX

int main(int argc, char *argv[]) {
  pid_t child_pid = fork();
  int counter = 0;
  int entering_syscall = 1;

  if(child_pid == -1) {
    perror("fork failed");
    exit(1);
  } else if(child_pid != 0) {
    // parent
    u_int64_t rax;
    int status;

    while(1) {
      // wait for the next signal by the child
      if(wait(&status) != child_pid)
        continue;

      if(WIFEXITED(status)) {
        puts("child exited");
        break;
      }

      // read the USER area, defined in sys/user.h, which contains the registers information
      // in linux, rax contains the syscall number
      rax = ptrace(PTRACE_PEEKUSER, child_pid, 8 * ORIG_RAX, NULL);

      if(rax == SYS_clone /* 56 */) {
        // PTRACE_SYSCALL generates a signal both when entering and exiting a syscall
        // only count the syscall during enter
        if(entering_syscall)
          counter++;

        entering_syscall = !entering_syscall;
      }

      //printf("syscall %ld\n", rax);

      // continue the child process until the next syscall enter/exit
      ptrace(PTRACE_SYSCALL, child_pid, NULL, NULL);
    }
  } else {
    // child

    // turns the calling thread into a tracee
    ptrace(PTRACE_TRACEME, child_pid, 0, 0);

    // signal and wait for the parent. This ensures that PTRACE_SYSCALL
    // will not miss any child syscall
    raise(SIGSTOP);

    execve(argv[1], &argv[1], NULL);

    // should be never reached
    perror("execve failed");
    exit(1);
  }

  printf("Num clone: %d\n", counter);
}

您可以對照 strace 交叉檢查strace 2>&1 your_command | grep clone | wc -l strace 2>&1 your_command | grep clone | wc -l

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM