简体   繁体   English

Systemcall子父执行问题(fork execve)Linux

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

Im new to systemcall.我是系统调用的新手。 Im using execve inside a child so the parent should run as normal and not be ovewritten by execve.我在孩子内部使用 execve,因此父级应该正常运行并且不会被 execve 覆盖。 The problem is that the child executes and stops the whole thing after execve.问题是孩子在execve之后执行并停止了整个事情。 My goal here is to count the number of clone executed in the bash command(argument) executed by execve.我的目标是计算 execve 执行的 bash 命令(参数)中执行的克隆数。

Ive read the man, Im still a bit confused.我读过这个人,我还是有点困惑。 I can only use ptrace, fork, wait/waitpid.我只能使用 ptrace、fork、wait/waitpid。

argument:争论:

/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 will overwrite the child process, so any instruction after execve will not be executed, unless the call to execve fails. execve会覆盖子进程,所以execve之后的任何指令都不会被执行,除非调用execve失败。 You should instead run the ptrace tracing that appears after the execve in the parent process您应该改为运行父进程中execve之后出现的ptrace跟踪

Edit: here is a commented solution to count the number of clone syscalls:编辑:这是一个计算克隆系统调用数量的注释解决方案:

#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);
}

You can cross-check it against strace strace 2>&1 your_command | grep clone | wc -l您可以对照 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