Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
运行PTRACE时,偶尔会错过PTRACE\u事件\u工作_C_Linux_Ptrace - Fatal编程技术网

运行PTRACE时,偶尔会错过PTRACE\u事件\u工作

运行PTRACE时,偶尔会错过PTRACE\u事件\u工作,c,linux,ptrace,C,Linux,Ptrace,很抱歉,我无法发布代码来复制此内容。我的问题恰恰是我不知道如何调试这个问题 我正在使用ptrace和ptrace_O_TRACEFORK | ptrace_O_TRACEEXEC | ptrace_O_TRACEFORK | ptrace_O_traceforkdone | ptrace_TRACECLONE来跟踪进程及其子进程(以及子进程的子进程)。该机制与strace非常相似,但用途略有不同,因为我只是跟踪读取或修改的文件 我的代码(用C编写)在x86-64体系结构的Debian wheez

很抱歉,我无法发布代码来复制此内容。我的问题恰恰是我不知道如何调试这个问题

我正在使用ptrace和
ptrace_O_TRACEFORK | ptrace_O_TRACEEXEC | ptrace_O_TRACEFORK | ptrace_O_traceforkdone | ptrace_TRACECLONE
来跟踪进程及其子进程(以及子进程的子进程)。该机制与strace非常相似,但用途略有不同,因为我只是跟踪读取或修改的文件

我的代码(用C编写)在x86-64体系结构的Debian wheezy和Debian jessie上运行良好(在i386上测试也较少)。当我试图在Ubuntu精确x86-64虚拟机(使用3.2.0内核)上编译和运行时,我遇到了麻烦

在精确的机器上,我有时发现在调用
VFORK
后,我不会立即收到
PTRACE\u事件\u VFORK
,而是在没有得到
PTRACE\u事件\u VFORK
事件的情况下开始接收事件(几个
SIGSTOP
事件和几个系统调用)。在执行的系统调用中,我没有看到任何可疑的东西,而且这种行为是不可预测的

我不确定如何将这一错误减少到最小,我也不知道可能会出现什么问题,因为我以前从未见过这种丢失事件的行为。可以想象,区别不在于内核,而在于我正在跟踪的构建工具(它是python+gcc的组合)


有什么建议吗?

我最近也在做类似的事情。我怀疑你很久以前就解决了问题,或者放弃了,但让我们在这里为子孙后代写一个答案

使用
PTRACE_SETOPTIONS
注册的各种事件生成与正常
PTRACE
事件不同的消息。但正常事件仍在生成。一个正常事件是,新分叉的进程开始停止,并且必须从跟踪程序继续

这意味着,如果您已注册了使用
PTRACE\u O\u TRACEFORK
(或VFORK)观看的事件,则
waitpid
将在fork之后为同一进程触发两次

其中一个的状态为:

WIFSTOPPED(status) && (WSTOPSIG(status) & 0xff == SIGSTOP)
另一个是:

WIFSTOPPED(status) && (WSTOPSIG(status) & 0xff == 0) &&
    ((status >> 16) == PTRACE_EVENT_FORK) /* or VFORK */
内核似乎无法保证它们的到达顺序。我发现在我的系统中接近50/50

要处理此问题,我的代码如下所示:

static void
proc_register(struct magic *pwi, pid_t pid, bool fork) {
    /*
     * When a new process starts two things happen:
     *  - We get a wait with STOPPED, SIGTRAP, PTRACE_EVENT_{CLONE,FORK,VFORK}
     *  - We get a wait with STOPPED, SIGSTOP
     *
     * Those can come in any order, so to get the proc in the right
     * state this function should be called twice on every new proc. If
     * it's called with fork first, we set the state to NEW_FORKED, if
     * it's called with STOP first, we set NEW_STOPPED. Then when the
     * other call comes, we set the state to TRACED and continue the
     * process.
     */
    if ((p = find_proc(pwi, pid)) == NULL) {
            p = calloc(1, sizeof(*p));
            p->pid = pid;
            TAILQ_INSERT_TAIL(&pwi->procs, p, list);
            if (fork) {
                    p->state = NEW_FORKED;
            } else {
                    p->state = NEW_STOPPED;
            }
    } else {
            assert((fork && p->state == NEW_STOPPED) || (!fork && p->state == NEW_FORKED));
            p->state = TRACED;
            int flags = PTRACE_O_TRACEEXEC|PTRACE_O_TRACEEXIT|PTRACE_O_TRACEFORK|PTRACE_O_TRACEVFORK;

            if (ptrace(PTRACE_SETOPTIONS, pid, NULL, flags))
                    err(1, "ptrace(SETOPTIONS, %d)", pid);
            if (ptrace(PTRACE_CONT, pid, NULL, signal) == -1)
                    err(1, "ptrace(CONT, %d, %d)", pid, signal);
    }
}
[...]
    pid = waitpid(-1, &status, __WALL);
    if (WIFSTOPPED(status) && (WSTOPSIG(status) & 0xff == SIGSTOP)) {
            proc_register(magic, pid, false);
    } else if (WIFSTOPPED(status) && (WSTOPSIG(status) & 0xff == 0) && ((status >> 16) == PTRACE_EVENT_FORK)) {
            proc_register(magic, pid, true);
    } else {
            /* ... */
    }
这项工作的关键是在我们收到两个事件之前不要发送
PTRACE\u CONT
。在弄清楚这是如何工作的时候,我发送了太多的
PTRACE\u CONT
,内核很高兴地接受了它们,这有时甚至导致我的进程在
PTRACE\u EVENT\u FORK
到来之前就退出了。这使得调试非常困难


注意,我没有找到任何关于这方面的文件,也没有任何文件表明这是应该的。我刚刚发现这让事情像今天一样运转。YMMV.

我已经多次(出于不同的原因)碰到这个页面。如果跟踪程序跟踪大量跟踪对象,并且存在大量事件(例如当
SECCOMP
设置为
RET_TRACE
时)
waitpid(-1,…)
可能不是等待任何跟踪对象的最佳选择,因为可能会有很多跟踪对象改变状态,特别是在SMP系统中(其他人仍在运行系统),这意味着可能会有大量事件在很短的时间内到达,OP是对的,事件可能是无序的:一些事件或信号甚至可以在
PTRACE\u event\u FORK
之前发生


但是,当跟踪器调用
waitpid(特定的\u pid\u大于\u零,…)
时,情况并非如此(没有无序事件):我们只等待特定的
tracee
。假定您的程序模型看起来可能不那么优雅/简单,您甚至可能需要跟踪tracee状态(阻塞或不阻塞),并决定何时/哪一个tracee继续(
PTRACE\u CONT
),但还有一个好处,那就是不用担心处理无序事件的黑客方法(也很难做到正确)。

如果这里没有人能帮忙,尝试询问linux内核邮件列表。(不太可能有帮助,但值得一试。)作为
ptrace
的替代方法,您可以使用来拦截对
open
read
write
close
的调用。祝你好运;这听起来很糟糕。我避免了LD_预加载,因为我希望我的代码能够跟踪静态链接的二进制文件。坦白说,我害怕linux内核!lol:)我同意LD_预加载不是一种明智/有效的方法。不幸的是,我不知道vWork跟踪失败的原因。如果您可以使用seccomp跟踪模式而不是传统的ptrace样式,那么它可能不那么容易出错,而且更易于移植。@Nemo,关于静态链接的二进制文件,使用go编译的任何东西都是主要的反例,这是一个越来越大的漏洞。有机会我会试试你的建议。@davidoundy:ptrace比赛条件是,但我不确定它是否会导致你看到的情况。如果且仅当您的进程是多线程的,即两个不同的任务导致同一进程停止,vWork one失去竞争(停止/继续信号不嵌套或排队),我可以考虑另一种可能性。