为什么 _do_fork() 的 kretprobe 只返回一次?

Geo*_*lly 4 c linux kernel systemtap kprobe

当我用 fork 编写一个小脚本时,系统调用返回两次进程(每个进程一次):

#include <stdio.h>
#include <unistd.h>

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

    if (pid == 0) {
        // child
    } else if (pid > 0) {
        // parent
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我使用 systemtap 进行检测,我只会找到一个返回值:

// fork() in libc calls clone on Linux
probe syscall.clone.return {
    printf("Return from clone\n")
}
Run Code Online (Sandbox Code Playgroud)

SystemTap 安装探针_do_fork而不是克隆,但这不应该改变任何东西。)

这让我很困惑。几个相关的问题:

  • 为什么系统调用只返回一次?
  • 如果我正确理解了_do_fork代码,则该过程将在函数中间被克隆。(copy_processwake_up_new_task)。后面的代码不应该在两个进程中都运行吗?
  • 系统调用后的内核代码是否与系统调用前的用户代码在同一线程/进程中运行?

emp*_*nth 5

  1. 孩子的创建可能会失败,因此必须检测和处理错误
  2. 孩子有不同的返回值,这也必须处理
  3. 可能是父母有清理/额外的行动要做

因此,代码必须区分作为父级和子级执行。但是没有对排序进行检查,这已经是一个强烈的暗示,表明孩子一开始就没有执行这段代码。因此,人们应该寻找一个新的孩子返回的专用地方。

由于代码相当大而且多毛,人们可以尝试作弊并在特定于 arch 的代码中寻找“fork”,这很快就会显示 ret_from_fork。

它通过 -> do_fork -> copy_process -> copy_thread_tls http://lxr.free-electrons.com/source/arch/x86/kernel/process_64.c#L158设置起点

因此

为什么系统调用只返回一次?

它不会返回一次。有 2 个返回线程,除了另一个使用不同的代码路径。由于探头仅安装在第一个上,因此您看不到另一个。另见下文。

如果我正确理解 _do_fork 代码,则该过程将在函数中间克隆。(copy_process 和wake_up_new_task)。后面的代码不应该在两个进程中都运行吗?

我之前注意到这是错误的。真正的问题是让孩子和父母回到同一个地方有什么好处。我没有看到任何,而且会很麻烦(额外的特殊外壳,如上所述)。重申一下:让孩子返回elsehwere让调用者不必处理返回的孩子。他们只需要检查错误。

系统调用后的内核代码是否与系统调用前的用户代码在同一线程/进程中运行?

什么是“系统调用后的内核代码”?如果你是线程X并进入内核,你仍然是线程X。