在PTRACE_CONT之后PTRACE_DETACH失败并且errno = ESRCH

kar*_*kki 4 c linux ptrace

在我的项目中,我需要附加到进程,恢复它们,然后再使用ptrace.但是,分离失败了errno=ESRCH (No such process).

如果我没有恢复进程,则分离工作正常PTRACE_CONT,但在这种情况下,进程停止/无响应,这在我的项目中是不可接受的.在Arch和Ubuntu 12.04 LTS上测试,结果相同.

#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ptrace.h>
#include <sys/wait.h>

int main(int argc, char *argv[])
{
    pid_t pid = 21000;

    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) == -1) {
        perror("PTRACE_ATTACH");
        return 1;
    } 
    printf("attached\n");
    waitpid(pid, NULL, WUNTRACED);

    if (ptrace(PTRACE_CONT, pid, NULL, NULL) == -1) {
        perror("PTRACE_CONT");
        return 1;
    }
    printf("continued\n");

    if (ptrace(PTRACE_DETACH, pid, NULL, NULL) == -1) {
        perror("PTRACE_DETACH");
        return 1;
    }
    printf("detached\n");

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出:

attached
continued
PTRACE_DETACH: No such process
Run Code Online (Sandbox Code Playgroud)

bet*_*ido 5

根据ptrace手册页,应该在尝试从中删除之前停止该过程:

通过以下方式执行tracee的分离:

ptrace(PTRACE_DETACH,pid,0,sig);

PTRACE_DETACH是一个重启动作; 因此它需要tracee处于ptrace-stop.如果迹线处于信号传递停止状态,则可以注入信号.否则,可以静默忽略sig参数.如果跟踪器在跟踪器想要分离时正在运行,通常的解决方案是发送SIGSTOP(使用tgkill(2),以确保它转到正确的线程),等待tracee在信号传递停止时停止对于SIGSTOP然后分离它(抑制SIGSTOP注入).设计错误是它可以与并发SIGSTOP竞争.另一个复杂因素是tracee可能会进入其他ptrace-stops并需要重新启动并再次等待,直到看到SIGSTOP.另一个复杂因素是确保tracee尚未被停止,因为没有信号传递发生 - 甚至不是SIGSTOP.

在您的示例代码中,实际上不需要调用ptrace(PTRACE_CONT, ...).你可以脱离这个过程.如果该代码属于更大的代码段,那么您可以使用tgkill()(或者只是kill在您不使用线程时):

ptrace(PTRACE_CONT, ...);
kill(pid, SIGSTOP);
waitpid(pid, NULL, 0);
ptrace(PTRACE_DETACH, ...);
Run Code Online (Sandbox Code Playgroud)