运行内核时支持的系统调用

Swa*_*air 11 system-calls linux-kernel

有没有办法获取当前运行的 Linux 内核支持的系统调用的数量或列表?所以我想找到一种方法来“读取”正在运行的内核的系统调用表。

Gil*_*il' 17

该文件/proc/kallsyms列出了正在运行的内核的所有符号。按照惯例,系统调用的名称以sys_. 在 64 位系统上,32 位程序的系统调用的名称以sys32_. 严格来说,这列出了内部内核函数,而不是系统调用,但我认为对应关系确实有效(每个系统调用都会调用一个内部内核函数来完成这项工作,我认为名称始终是系统调用的名称,并带有sys_前置)。

</proc/kallsyms sed -n 's/.* sys_//p'
Run Code Online (Sandbox Code Playgroud)

这通常不是有用的信息,因为系统调用变化非常缓慢。可选组件根据现有系统调用提供功能,使用一般特性,例如设备(使用ioctlreadwrite不切断它)、文件系统、套接字等。确定支持的系统调用列表不会告诉您有关这些特性的任何信息系统支持。其他内部函数名称也无济于事,因为这些更改非常快:在一个内核版本上实现某些功能的函数名称可能会在下一个版本中更改。

  • @JohnWHSmith“可以像任何其他文件一样操作”……需要注意的是,在具有内核 ASLR 的系统上,此文件只能由 root 读取。 (2认同)

Joh*_*ith 8

TL; 博士

在写这个答案时,我一直在寻找新的替代方案,所以我只写了一些关于它们的细节,并做了一些统计。基本上,您可以:

  • 阅读 Gilles 的回答,它提供了一种干净且快速的方法(依赖于/proc)。
  • 使用文档资源。
  • 使用系统的 C 头文件。
  • 使用内核源代码本身。
  • 使用/sys目录。

做完数学运算后,我建议(在我的替代方案中)使用/sys文件系统,因为它似乎在系统调用数量方面给出了最好的结果。如果您不想阅读其他技巧,可以直接跳到该部分。

使用文档资源

虽然您可能会错过其中的一些,但您可以使用apropos列出属于第 2 节(系统调用)的所有联机帮助页:

$ apropos -s2 . | awk '{print $1}' | column
Run Code Online (Sandbox Code Playgroud)

column如果您不想要花哨的列式输出,请删除。

我刚刚找到它,但是有一个关于系统调用的 Linux 手册页,您可以在其中找到大部分。

$ man syscalls
Run Code Online (Sandbox Code Playgroud)

我还发现了这两个可能很有趣的网站:

使用头文件

编辑:现在,当涉及到以编程方式(或至少不依赖于记录的功能)确定哪些系统调用可用时,恐怕内核不会保留其系统调用的表,至少不会以字符串列表(正如您可能期望操作它们的那样)。在这个层面上,我们更多地讨论函数地址和指针,而不是函数名称。

我刚刚浏览了我的/usr/include目录并做grep了一些事情:您可能会发现以下目录很有趣。其中一些在您的机器上可能会有所不同,具体取决于您的架构和发行版,但我相信您能够适应它们。

  • /usr/include/linux
  • /usr/include/x86_64-linux-gnu
  • /usr/include/sys
  • /usr/include/asm-generic

通过在此文件中查找函数定义,您会遇到许多系统调用,即使它们在那里没有完全定义。我grep在这些目录中运行了一些s,我能够找到一些系统调用的提及。下面是一个例子:

$ grep 'sys_exit' /usr/include -R
asm-generic/unistd.h:__SYSCALL(__NR_exit, sys_exit)
Run Code Online (Sandbox Code Playgroud)

所以,我猜另一种找到其中一些的方法是:

$ egrep '^__SYSCALL' /usr/include -Rh | awk '{print $2}' | tr -d ')'
Run Code Online (Sandbox Code Playgroud)

使用内核的源代码及其系统调用表

另一种解决方案是使用内核源代码本身(而不仅仅是头文件!),并找到一种有效搜索它的方法。由于内核提交 303395ac3bf3e2cb488435537d416bc840438fcb,您可能会发现这比以前容易一些。这是 3.13(这是我的内核)的示例:

$ wget https://git.kernel.org/cgit/linux/kernel/git/stable/linux-stable.git/plain/arch/x86/syscalls/syscall_64.tbl?id=refs/tags/v3.13 -O syscall_64.tbl
Run Code Online (Sandbox Code Playgroud)

现在你得到了实际的 syscalls 表,只需浏览它:

$ while read line; do awk '! /#/ {print $3}'; done < syscall_64.tbl
Run Code Online (Sandbox Code Playgroud)

您可以找到一种方法,使用uname和,根据您正在运行的内核版本和架构,直接从git.kernel.orgarch下载tbl文件。

使用/sys文件系统

Gilles 的回答给了我一点启发,你可能会在里面找到那些系统调用/sys/kernel/debug/tracing/events/syscalls。该目录用于监视系统上每个系统调用的使用情况。每个系统调用中有两个目录:

  • sys_enter_[系统调用]
  • sys_exit_[系统调用]

因此,使用ls,grepcut...

$ ls /sys/kernel/debug/tracing/events/syscalls | grep 'sys_enter' | cut -d'_' -f3
Run Code Online (Sandbox Code Playgroud)

统计数据

在我的系统上:

  • 使用手册页显示 440 个系统调用。
  • grep-ing for__SYSCALL在头文件中显示了 212 个系统调用。
  • 从内核源代码中读取 syscalls 表发现了 346 个系统调用。
  • 使用/sys显示的 290 个系统调用。

现在,如果我把所有东西放在一起......

$ apropos -s2 . | awk '{print $1}' > system_calls.txt
$ egrep '^__SYSCALL' /usr/include -Rh | awk '{print $2}' | tr -d ')' >> system_calls.txt
$ while read line; do awk '! /#/ {print $3}'; done < syscall_64.tbl >> system_calls.txt
$ ls /sys/kernel/debug/tracing/events/syscalls | grep 'sys_enter' | cut -d'_' -f3 >> system_calls.txt

$ sort < system_calls.txt | uniq | wc -l
707
Run Code Online (Sandbox Code Playgroud)

好了,707 系统调用!当然,这个数字反映了“系统调用”的一个非常灵活的定义,因为3.13 应该只提供 274 个系统调用(阅读/sys似乎是最接近的解决方案)。