gpt4 book ai didi

在 ptraced Linux 进程中调用 ptrace

转载 作者:IT王子 更新时间:2023-10-29 00:54:19 26 4
gpt4 key购买 nike

有人添加到 Wikipedia "ptrace" article声称在 Linux 上,一个 ptraced 进程本身不能 ptrace 另一个进程。我正在尝试确定是否(如果是,为什么)是这种情况。下面是我设计的一个简单程序来测试它。我的程序失败(sub 子进程未正常运行)但我非常确信这是我的错误,而不是根本性的错误。

本质上,初始进程A fork 进程B,后者又 fork CA追踪它的 child BB追踪它的 child C。设置完成后,所有三个进程都被编写为仅每秒打印一次 ABC 到标准输出。

在实践中,AB 工作正常,但 C 只打印一次,然后就卡住了。使用 ps -eo pid,cmd,wchan 检查显示 C 卡在内核函数 ptrace_stop 而其余部分在 hrtimer_nanosleep 我希望这三个人都在的地方。

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

我的猜测可能出了什么问题:

  • A 看到 SIGCHLD 有关 B 看到 SIGCHLD 与信号有关到 C,并等待 (2) 报告两者都来自 B(但是对两个 pid 的 PTRACE_CONT 的 hacky 调用并不能解决问题)?
  • C 应该由 B 追踪 - C 继承了 A 的追踪(并且 >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;
}

最佳答案

您确实看到了竞争条件。您可以通过将 sleep(1); 紧接在 second 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");
}
}
}

关于在 ptraced Linux 进程中调用 ptrace,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2359581/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com