Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/62.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
Can';t跟踪子进程';s syscalls,它使用ptrace和seccomp调用execve_C_Linux - Fatal编程技术网

Can';t跟踪子进程';s syscalls,它使用ptrace和seccomp调用execve

Can';t跟踪子进程';s syscalls,它使用ptrace和seccomp调用execve,c,linux,C,Linux,我正在创造一个新的世界。我不改变系统调用中的任何内容,我只是将它记录在我的结构中,当进程完成时,我将这个结构转储到磁盘上 当我像这样运行我的程序时(它被称为跟踪器): 示踪环境 一切正常,我在文件中看到了日志。 但是,如果我试图跟踪一个在内部调用execve的程序,它会失败: 追踪观察-n1环境 或 示踪剂带-o/tmp/log env 使用标准输出失败 环境:加载共享库时出错:无法为搜索路径创建缓存:无法分配内存 和日志: $ cat /tmp/log execve("/usr/bin/env

我正在创造一个新的世界。我不改变系统调用中的任何内容,我只是将它记录在我的结构中,当进程完成时,我将这个结构转储到磁盘上

当我像这样运行我的程序时(它被称为跟踪器):

示踪环境

一切正常,我在文件中看到了日志。 但是,如果我试图跟踪一个在内部调用
execve
的程序,它会失败:

追踪观察-n1环境

示踪剂带-o/tmp/log env

使用标准输出失败

环境:加载共享库时出错:无法为搜索路径创建缓存:无法分配内存

和日志:

$ cat /tmp/log
execve("/usr/bin/env", ["env"], [/* 19 vars */]) = 0
brk(NULL)                               = 0x415000
mmap(0xffffffffffffffda, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x2
writev(103, [{iov_base="env", iov_len=3}, {iov_base=": ", iov_len=2}, {iov_base="error while loading shared libraries", iov_len=36}, {iov_base=": ", iov_len=2}, {iov_base="", iov_len=0}, {iov_base="", iov_len=0}, {iov_base="cannot create cache for search path", iov_len=35}, {iov_base=": ", iov_len=2}, {iov_base="Cannot allocate memory", iov_len=22}, {iov_base="\n", iov_len=1}], 10) = 127
+++ exited with 127 +++
请注意奇怪的
mmap
地址及其返回值。我不明白是什么错了,为什么会这样。任何其他程序都可以正常工作,因此我想问题在于将
seccomp
过滤器复制到调用
execve
的分叉进程

以下是我的
seccomp
规则:

struct sock_filter filter[] = {
    BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct seccomp_data, nr)),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_openat, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_write, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_mmap, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_mprotect, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_close, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
};
我没有列出全部代码,因为这是显而易见的,并且只能以一种方式编写,而且它是在我上面提到的文章中编写的。这个问题也是众所周知的,但我没有找到任何解决办法。如果您仍然坚持完整的代码(我对此表示怀疑)或MCVE,我可以提供它

另外,当我添加
execve
跟踪时,我有不同的行为:

struct sock_filter filter[] = {
    BPF_STMT(BPF_LD + BPF_W + BPF_ABS, offsetof(struct seccomp_data, nr)),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_openat, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_write, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_mmap, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_mprotect, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_close, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, __NR_execve, 0, 1),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_TRACE),
    BPF_STMT(BPF_RET + BPF_K, SECCOMP_RET_ALLOW),
};
日志变为:

$ cat /tmp/log
execve(0xffffffffffffffda, ["env"], [/* 19 vars */]) = -1 ENOSYS (Function not implemented)
getpid()                                = 15535
exit_group(1)                           = ?
+++ exited with 1 +++
Linux 4.4 aarch64、Linux 4.15 x86-64


我花在这个问题上的时间越多,我就越意识到这个问题实际上存在于内核的源代码中,但是他们不复制实现,所以所有的
SECCOMP\u RET\u TRACE
规则都被复制,并且子孩子中没有跟踪器,所以子孩子中的每个系统调用都返回
-ENOSYS
,因为那里没有跟踪器,但是,规则被复制了。

我找到了解决这个问题的方法。要为子进程设置跟踪程序,或者至少避免子进程的
ENOSYS
问题,我们可以在设置PTRACE选项时指定
PTRACE\u O\u TRACEFORK
PTRACE\u O\u TRACECLONE
标志,如下所示:

ptrace(PTRACE_SETOPTIONS, child, 0, PTRACE_O_TRACESECCOMP | PTRACE_O_TRACEFORK | PTRACE_O_TRACECLONE);
我们需要同时添加这两个选项的原因很难简单解释。首先,系统中存在哪些系统调用以及程序使用哪些系统调用取决于体系结构和libc(通常通过libc实现)。也许,即使这个列表也不完整:我们可能还必须跟踪
vWork
以及与克隆(或繁殖)线程或进程相关的其他方式(记住,线程在Linux中是轻量级进程)。因此,这些选项的作用在以下文件中指定:

PTRACE\u O\u TRACECLONE
(从Linux 2.5.46开始) 在下一个克隆(2)处停止tracee并自动 开始跟踪新克隆的进程,该进程将 从
SIGSTOP
开始,或
PTRACE\u事件\u STOP
开始,如果 使用了
PTRACE\u-take
。跟踪器的等待PID(2)将 返回一个状态值,以便

status>>8 == (SIGTRAP | (PTRACE_EVENT_CLONE<<8))

这可能是导致问题的原因。@Ryker感谢您的帮助,但我不确定这两个问题是如何联系在一起的?请你澄清一下好吗?可能不是。这是在黑暗中拍摄的。鉴于你的环境和条件不太可能轻易重现,剩下的就是试图从描述问题的词语中推断出因果关系,例如:然而。。。对于Exeve,它在文章的第一部分失败。我看到你编辑了一篇关于问题本质的伪结论?
const pid_t childWaited = waitpid(-1, &status, 0);
// but not const pid_t result = waitpid(myChildPid, &status, 0);