设置PTRACE_O_TRACEFORK后ptrace仍无法追踪fork子进程
解决ptrace无法追踪fork/clone子进程的问题
以下是你代码可能存在的几个关键问题及对应修复方案:
1. 仅维护单个追踪PID,丢失原进程追踪
你提到通过wait更新child变量,但fork后原父进程和新子进程都处于需被追踪的状态,只保留一个PID会导致原进程的后续系统调用被忽略。必须用集合(比如数组、链表)保存所有需要追踪的进程ID,每次处理完一个进程的事件后,继续监听所有进程的状态变化。
2. 未正确处理fork/clone事件以获取子进程PID
当设置PTRACE_O_TRACEFORK/PTRACE_O_TRACECLONE后,被追踪进程执行fork/clone时,你会收到带PTRACE_EVENT_FORK/PTRACE_EVENT_CLONE标识的SIGTRAP。此时需要:
- 调用
PTRACE_GETEVENTMSG获取新生成的子进程PID - 对新PID执行
PTRACE_SYSCALL(或PTRACE_CONT),同时为它设置相同的追踪选项(比如PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE),确保它后续的fork/clone操作也能被追踪
3. waitpid调用参数错误
必须使用waitpid(-1, &status, __WALL | WUNTRACED)来监听所有被追踪进程的状态变化,而非仅监听最初的child PID。其中-1表示等待任意子进程,__WALL包含对clone生成进程的监听,WUNTRACED确保捕获进程暂停的状态。
修复后的tracer.c关键代码示例
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ptrace.h> #include <sys/wait.h> #include <sys/types.h> #include <errno.h> #define MAX_PROCS 100 pid_t tracked_procs[MAX_PROCS]; int proc_count = 0; void add_tracked_proc(pid_t pid) { if (proc_count < MAX_PROCS) { tracked_procs[proc_count++] = pid; } } int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s <program> [args]\n", argv[0]); exit(1); } pid_t child = fork(); if (child == 0) { // 子进程:启动被追踪程序 ptrace(PTRACE_TRACEME, 0, NULL, NULL); execvp(argv[1], &argv[1]); perror("execvp failed"); exit(1); } else { add_tracked_proc(child); int status; waitpid(child, &status, WUNTRACED); // 设置初始追踪选项 ptrace(PTRACE_SETOPTIONS, child, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE | PTRACE_O_EXITKILL); while (proc_count > 0) { // 等待任意被追踪进程的状态变化 pid_t pid = waitpid(-1, &status, __WALL | WUNTRACED); if (pid == -1) { perror("waitpid failed"); break; } if (WIFEXITED(status)) { // 进程退出,从追踪列表移除 for (int i = 0; i < proc_count; i++) { if (tracked_procs[i] == pid) { tracked_procs[i] = tracked_procs[--proc_count]; break; } } continue; } if (WIFSTOPPED(status)) { int sig = WSTOPSIG(status); if ((sig == SIGTRAP) && (status >> 16) != 0) { // 处理追踪事件 int event = status >> 16; if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_CLONE) { pid_t new_pid; ptrace(PTRACE_GETEVENTMSG, pid, NULL, &new_pid); printf("New process created: %d\n", new_pid); // 对新进程设置追踪选项并继续执行 ptrace(PTRACE_SETOPTIONS, new_pid, NULL, PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE | PTRACE_O_EXITKILL); ptrace(PTRACE_SYSCALL, new_pid, NULL, NULL); add_tracked_proc(new_pid); } } // 继续当前进程的系统调用追踪 ptrace(PTRACE_SYSCALL, pid, NULL, NULL); } } } return 0; }
额外注意事项
- 确保被追踪程序(random.c)中的fork/clone调用未被其他手段拦截或修改
- 运行tracer需要足够权限(比如root,或临时设置ptrace_scope为0:
echo 0 > /proc/sys/kernel/yama/ptrace_scope)
内容的提问来源于stack exchange,提问作者frazz
相关产品推荐
相关产品推荐

