是否保证能够在跟踪点读取所有系统调用参数sys_exit
?
sysdig 驱动程序 是一个内核模块,用于使用内核静态跟踪点捕获系统调用。在这个项目中,一些系统调用参数是在sys_enter
tracepoint处读取的,而其他一些参数则是在sys_exit
(当然是返回值,以及用户空间中的内容以避免页面错误)处读取的。
为什么不读取所有参数sys_exit
?这是因为某些参数可能不可用sys_exit
吗?
是否保证能够在跟踪点读取所有系统调用参数sys_exit
?
sysdig 驱动程序 是一个内核模块,用于使用内核静态跟踪点捕获系统调用。在这个项目中,一些系统调用参数是在sys_enter
tracepoint处读取的,而其他一些参数则是在sys_exit
(当然是返回值,以及用户空间中的内容以避免页面错误)处读取的。
为什么不读取所有参数sys_exit
?这是因为某些参数可能不可用sys_exit
吗?
是否保证能够在跟踪点读取所有系统调用参数
sys_exit
?
是的......不,我们需要将参数与寄存器区分开来。Linux 系统调用应该保留所有通用用户空间寄存器,除了用于返回值的寄存器(在某些架构上还有第二个寄存器来指示是否发生错误)。然而,这并不意味着系统调用的输入参数在进入和退出之间不能改变:如果一个寄存器保存了指向某些数据的指针的值,而寄存器本身没有改变,它指向的数据很可能会改变.
查看静态跟踪点的代码sys_exit
,您可以看到仅跟踪系统调用号 ( id
) 及其返回值 ( ret
)。有关更多信息,请参阅我的答案底部的注释。
为什么不读取所有参数
sys_exit
?这是因为某些参数可能不可用sys_exit
吗?
是的,我会说确保跟踪参数的正确性是仅在出口处跟踪是一个坏主意的主要原因。即使您获得了寄存器的值,您也无法知道系统调用退出时的实际参数。即使系统调用本身可以保证保存和恢复用户寄存器的状态,系统调用本身也可以更改作为参数传递的数据。例如,recvmsg
系统调用将指针指向struct msghdr
内存中的 a,该指针既用作输入参数,也用作输出参数;系统poll
调用对指向struct pollfd
. 此外,另一个线程或程序可能在进行系统调用时很好地修改了程序的内存,从而改变了数据。
在特定情况下,系统调用也可能需要很长时间才能返回(例如,考虑 a或终端上sleep
的阻塞、监听套接字上的 a 等)。如果您只在出口处进行跟踪,您将获得非常不正确的时间信息,最重要的是,您必须等待很长时间才能捕获任何有意义的信息,即使该信息已经在入口点可用。read
accept
sys_exit
关于跟踪点的注意事项
尽管您可以从当前任务的已保存寄存器中提取值,但我并不完全确定在跟踪点中这样做的语义sys_exit
。我搜索了一些关于这个特定案例的文档,但没有运气,内核代码很好......很复杂。
到达退出钩子的调用链应该是:
entry_INT80_32
x86 int 0x80
)
do_int80_syscall_32()
x86 int 0x80
)
如果在系统调用期间将致命信号传递给进程,而实际进程永远不会到达系统调用的出口(即没有任何值返回到用户空间),跟踪点仍然会被命中。当发生这种信号传递时,会使用一个特殊的内部返回值,例如-ERESTARTSYS
(参见此处)。这个值不是一个实际的系统调用返回值(它不会返回到用户空间),而只是为了被内核使用。因此,如果进程接收到致命信号,则看起来sys_exit
跟踪点正在被特殊命中。例如,在+-ERESTARTSYS
的情况下不会发生这种情况。不过,对此持保留态度,因为我无法为此找到适当的文档。SIGSTOP
SIGCONT