【问题标题】:In a Linux system call, are system call parameters preserved in registers after the syscall finished (at the sys_exit tracepoint)?在 Linux 系统调用中,系统调用完成后(在 sys_exit 跟踪点处),系统调用参数是否保存在寄存器中?
【发布时间】:2021-04-27 17:55:14
【问题描述】:

是否保证能够读取sys_exittracepoint处的所有系统调用参数?

sysdig driver 是一个使用内核静态跟踪点捕获系统调用的内核模块。在这个项目中,一些系统调用参数在sys_entertracepoint 处读取,其他一些参数在sys_exit 处读取(当然是返回值,以及用户空间中的内容以避免页面错误)。

为什么不读取sys_exit 的所有参数?是不是因为sys_exit有些参数可能不可用?

【问题讨论】:

    标签: linux-kernel system-calls tracepoint


    【解决方案1】:

    是否保证能够读取sys_exittracepoint处的所有系统调用参数?

    是的...不,我们需要将参数与寄存器区分开来。 Linux 系统调用应该保留所有通用用户空间寄存器,除了用于返回值的寄存器(在某些架构上还有第二个寄存器来指示是否发生错误)。然而,这并不意味着系统调用的输入参数不能在进入和退出之间改变:如果一个寄存器保存了指向某些数据的指针的值,而寄存器本身没有改变,则数据它指出可能会发生很大的变化。

    查看静态跟踪点sys_exitthe code,您可以看到仅跟踪系统调用号(id)及其返回值(ret)。有关更多信息,请参阅我的答案底部的注释。

    为什么不读取sys_exit 的所有参数?是不是因为sys_exit有些参数可能不可用?

    是的,我会说确保跟踪参数的正确性是为什么只在出口处跟踪是一个坏主意的主要原因。即使你得到了寄存器的值,你也无法知道系统调用退出时的真实参数。即使系统调用本身保证保存和恢复用户寄存器的状态,系统调用本身也可以改变作为参数传递的数据。例如,recvmsg 系统调用将指针指向内存中的struct msghdr,该指针既用作输入参数,也用作输出参数; poll 系统调用对指向struct pollfd 的指针执行相同的操作。此外,另一个线程或程序可能在进行系统调用时很好地修改了程序的内存,从而改变了数据。

    在特定情况下,系统调用也可能需要很长时间才能返回(例如,考虑sleep,或终端上的阻塞read,侦听套接字上的accept,等等)。如果仅在出口处进行跟踪,您将获得非常不正确的时间信息,最重要的是,您必须等待很长时间才能捕获任何有意义的信息,即使该信息已经在入口点可用。


    注意sys_exittracepoint

    尽管您可以从计算机上提取当前任务的已保存寄存器的值,但我并不完全确定在 sys_exit 跟踪点中这样做的语义。我搜索了一些关于这个特定案例的文档,但没有运气,内核代码很好......很复杂。

    到达退出钩子的调用链应该是:

    如果在系统调用期间向进程传递了致命信号,而实际进程永远不会到达系统调用的出口(即没有任何值返回到用户空间),跟踪点仍然会被命中。当发生这种类型的信号传递时,会使用一个特殊的内部返回值,例如-ERESTARTSYS (see here)。这个值不是一个实际的系统调用返回值(它不返回到用户空间),而是只打算被内核使用。因此,如果进程接收到致命信号,则看起来sys_exit 跟踪点正在被特殊的-ERESTARTSYS 命中。例如在SIGSTOP + SIGCONT 的情况下不会发生这种情况。不过,对此持保留态度,因为我找不到合适的文档。

    【讨论】:

    • 感谢您的出色回答。我基本明白这背后的原因了。但是我只想确认一件事,我尝试了您提到的关于发出带有无效缓冲区的read 的示例,但是通过返回值EFAULT 到达sys_exit。是否有其他示例可以证明系统调用可能被终止并且无法到达sys_exit?再次感谢!
    • @user2828102 是的,你说得对,这可能不是最好的例子,我忘了read 检查参数,如果缓冲区指针无效,它会返回EFAULT 而不会终止进程。在任何情况下,如果您在一个终端中运行strace -f cat(它会阻止在read 上等待)然后打开另一个终端并发出ps aux | grep cat 来查找cat 进程的PID,那么您可以很容易地进行测试。然后kill -9 PID 杀死它。 Example.
    • 虽然 strace 显示一个 '?'作为read的返回值,我编写了一个演示LKM来在sys_exit跟踪点打印一条消息,结果read仍然到达sys_exit,返回码-512表示ERESTARTSYS
    • @user2828102 是的,对不起,我删除了那部分,检查我编辑的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-02
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多