Linux父进程中Ptrace options工作异常问题求助
核心问题点
你的代码存在3个直接导致ptrace状态值读取异常的逻辑错误:
- 状态变量作用域错误:
wait_for_syscall函数内部定义了同名局部变量status,waitpid写入的状态仅存在于函数栈帧内,main函数中定义的status从未被更新,后续所有事件判断读取的都是第一次wait拿到的初始SIGSTOP状态的旧值,完全拿不到后续ptrace事件的真实返回。 - 位运算优先级错误:停止事件判断条件
WIFSTOPPED(status) && WSTOPSIG(status) | 0x80存在优先级问题,&&运算优先级高于|,实际执行逻辑等价于(WIFSTOPPED(status) && WSTOPSIG(status)) | 0x80,由于0x80恒为真,该判断永远返回成立,无法过滤非目标停止事件。另外你明确禁用了PTRACE_O_SYSGOOD,未开启该选项时系统调用停止事件不会携带0x80标记,这个判断本身就不成立。 - 事件判断分支位置错误:
PTRACE_O_TRACEEXEC、PTRACE_O_TRACESECCOMP触发时的停止信号为普通SIGTRAP,事件码存在于status的高8位,不会携带你判断的0x80标记,当前逻辑仅在匹配到0x80标记后才检查事件位,两类ptrace事件永远无法进入计数分支。
修正方案
- 移除
wait_for_syscall内的局部status变量,通过指针参数将waitpid拿到的状态传回main函数,保证状态值实时更新 - 修正停止事件判断逻辑:每次wait返回后优先判断ptrace事件位,匹配EXEC、SECCOMP事件时直接处理,无需依赖0x80标记
- 子进程中
PTRACE_TRACEME调用的pid参数无实际作用,按规范传0即可
修正后的可运行代码如下:
#include <stdlib.h> #include <unistd.h> #include <sys/wait.h> #include <sys/ptrace.h> #include <signal.h> int wait_for_ptrace_stop(pid_t child, int *status) { while (1) { ptrace(PTRACE_CONT, child, 0, 0); waitpid(child, status, 0); if (WIFEXITED(*status)) return 1; if (WIFSTOPPED(*status)) return 0; } } int main(int argc, char *argv[]) { int status; int counter = 0; pid_t pid = fork(); if (pid < 0) exit(1); else if (pid == 0) { ptrace(PTRACE_TRACEME, 0, NULL, NULL); raise(SIGSTOP); return execve(argv[1], &argv[1], NULL); } else { wait(&status); ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_EXITKILL | PTRACE_O_TRACEEXEC | PTRACE_O_TRACESECCOMP); while (1) { if (wait_for_ptrace_stop(pid, &status) != 0) break; if ((status >> 8) == (SIGTRAP | (PTRACE_EVENT_EXEC << 8))) counter++; if ((status >> 8) == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8))) counter++; } } return 0; }
测试运行命令:/bin/bash -c "echo 'first test' | wc -c"
注:如果需要捕获系统调用入口/出口事件,在禁用PTRACE_SYSCALL、SYSGOOD的约束下,只能通过SECCOMP_RET_TRACE规则配置seccomp过滤器触发PTRACE_EVENT_SECCOMP事件,仅靠当前代码中的ptrace选项无法自动捕获所有系统调用的进出。
内容的提问来源于stack exchange,提问作者Olivia22
相关产品推荐
相关产品推荐

