访问未通过 EXPORT_SYMBOL* 导出的 Linux 内核符号

Posted

技术标签:

【中文标题】访问未通过 EXPORT_SYMBOL* 导出的 Linux 内核符号【英文标题】:Access Linux kernel symbols that are not exported via EXPORT_SYMBOL* 【发布时间】:2012-04-14 15:25:39 【问题描述】:

我们需要访问 net/ipv4/af_inet.c 中未从可加载内核模块显式导出的内核全局变量。我们目前使用的是 2.6.18 内核。

kallsyms_lookup_name 似乎不再可用(未导出)

__symbol_get 返回 NULL(进一步阅读,symbol_get/__symbol_get 会查看内核和现有模块的符号表,其中仅包含导出的符号,并确保导出符号的模块被实际加载)

是否可以访问不是从内核模块导出的符号?

在大量阅读和查看人们提供的答案后,似乎很难在多个内核版本中找到一种方法,因为 kAPI 会随着时间发生显着变化。

【问题讨论】:

objdump path/to/modulename.ko 会满足您的需求吗?您必须解码输出以确定模块中的相应偏移量,然后应用它。获取未导出的符号的目的是什么? 是的,我们实际上可以通过用户空间中的 /proc/kallsyms 获取地址,并可能将其传递给模块,但这似乎有点骇人听闻,所以我想知道是否有更好的东西。我们正在尝试提取部分网络代码并使其成为一个模块,以便我们可以在无需重新启动内核的情况下进行错误修复。 【参考方案1】:

您可以通过从 /proc/kallsyms 获取它来使用您之前提到的方法,或者只使用 System.map 中给出的地址(这是同一件事),这可能看起来很hackish,但这就是我所看到的它以前做过(从来没有真正自己做过)。要么这样,要么您可以构建自己的自定义内核,在其中您实际上对要导出的任何内容执行 EXPORT_SYMBOL 但这不是可移植的。

【讨论】:

耶稣,你在哪里见过 /proc/kallsyms 方法?是在生产环境中吗?您说得对,我们希望使用标准内核而无需重新编译它。 @softwareengineer 通常在测试我们想要添加到内核中的一些功能而不必重新编译它或者只是将其作为可移动的模块化功能。我可能见过一次或两次。在此之前,我看到了 System.map ,他们只是将地址硬编码到模块中。 谢谢,我会等几天看看是否有其他人可以提出任何建议,但如果没有,我很乐意接受您的建议。 @softwareengineer 我很想看看是否还有其他方法。虽然通常当我想访问非导出函数时,我直接在内核本身中工作。 我接受了耶稣的回答,因为归根结底,它确实让我有信心,我不是疯了才想到这样做。 :) 如果我发现更好的东西,我会发布后续内容。【参考方案2】:

如果性能不是一个大问题,您可以使用kallsyms_on_each_symbol()(由内核为 GPL 模块导出)遍历整个符号列表并检查名称以获得您需要的名称。我不建议这样做,除非没有其他选择。

如果您想走这条路,这里是我们的一个项目中的an example。见kallsyms_on_each_symbol()的用法以及symbol_walk_callback()的代码,其他部分与本题无关。

【讨论】:

谢谢,尤金。但是,此功能似乎仅在较新的内核中可用。它不在 2.6.18 或 2.6.25 中,但在 2.6.30 中。不过,我应该在我原来的问题中指定 2.6.18 内核。

以上是关于访问未通过 EXPORT_SYMBOL* 导出的 Linux 内核符号的主要内容,如果未能解决你的问题,请参考以下文章

设备驱动程序入口点访问

EXPORT_SYMBOL使用

谈EXPORT_SYMBOL使用

加载驱动的传参和符号导出(EXPORT_SYMBOL & module_param)

Println如何访问golang中未导出的字段?

同一实体的两个存储库,一个已导出,一个未导出