有没有办法让内核模块找到另一个加载模块的节地址?
在 x86 系统上,我有一个 Linux 内核模块(“观察程序模块”),每次加载特定内核模块(“目标”)时都会收到内核通知。几乎任何内核模块都可以成为目标。我在我正在开发的仪表系统中使用了它。
当观察者模块处理此类通知时,如果观察者知道加载的目标模块的 ELF 部分的地址,则出于某种原因可能会很方便。有什么想法可以在内核空间中获取这些信息吗?
当然,一旦加载目标,我就可以在用户空间中获取 /sys/module/
中相应文件的内容,然后以某种方式将此数据传递给观察者模块但这太笨拙了。我想找到一种方法可以直接在内核空间获取这些信息。
据我在模块加载器的源代码中看到的,它不会在 struct module 中存储节地址,只是为节创建 sysfs 文件。也许有可能以某种方式找到与这些文件相对应的内核对象并从这些对象中读取所需的数据?或者可能使用其他方法?
On an x86 system, I have a Linux kernel module ("watcher module") that gets notified by the kernel each time a particular kernel module ("target") is loaded. Almost any kernel module can be a target. I use this in an instrumentation system I am working on.
When the watcher module handles such notification, it could be convenient for some reason, if the watcher knew the addresses of ELF sections of the loaded target module. Any ideas how this information could be obtained in kernel space?
Of course I could probably get the contents of the appropriate files in /sys/module/<target_name>/sections/
in user space as soon as the target is loaded and then somehow pass this data to the watcher module but this is too clumsy. I would like to find a way to obtain this information directly in the kernel space.
As far as I have seen in the sources of the module loader, it does not store section addresses in struct module
, just creates sysfs files for the sections. May be it is possible to somehow find the kernel objects corresponding to those files and read the needed data from these objects? Or probably use some other approach?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在深入研究有关模块各部分的信息如何进入 sysfs 后,我发现如果不使用内核内部的结构定义,就无法检索它。在我的项目中,使用这些东西不是一个选择,所以我最终实现了另一种方法,希望这种方法更可靠。
简而言之,想法如下。我的内核模块使用用户模式帮助程序 API 来启动用户空间进程(实际上是执行我的脚本的 shell)。该进程获取“目标”内核模块的名称作为参数,并从 sysfs (
/sys/module//sections/
) 收集有关其部分的信息。从用户空间,可以轻松获得此信息。之后,它通过 debugfs 中的文件将收集到的数据作为字符串传递到我的内核模块。该模块解析字符串并验证其内容。如果一切正常,ELF 节的名称和起始地址将可用。我承认,用户模式助手的技巧相当笨拙,但它可以完成工作。
我已经准备了上述方法的示例实现 - 请参阅 "Sections “示例。
有关用户模式帮助程序 API 的详细信息,请参阅内核源代码中
和
中的代码,即call_usermodehelper()
的定义。这些示例以及 API 典型用法的说明可在 这篇文章。请注意该文章中的示例有点不准确:模块的 init 函数返回 call_usermodehelper() 的结果。然而,后者返回 2 字节状态代码(至少在使用
UMH_WAIT_PROC
调用时),而不是 init 函数预期返回的 0 或负错误代码。这可能会导致运行时警告。 这里解释了call_usermodehelper()
实际返回的内容。After digging into how the information about the sections of a module gets into sysfs, I found no way to retrieve it without using the structure definitions internal to the kernel. Using such stuff is not an option in my project, so I have finally implemented another approach, which is, hopefully, more reliable.
In short, the idea is as follows. My kernel module uses the user-mode helper API to start a user-space process (a shell executing my script, actually). That process gets the name of the "target" kernel module as a parameter and collects the information about its sections from sysfs (
/sys/module/<target_name>/sections/
). From the user space, this information can be obtained easily. After that, it passes the collected data to my kernel module as a string via a file in debugfs. The module parses the string and validates its contents. If everything is OK, the names and start addresses of ELF sections will be available.I admit, the trick with the user-mode helper is quite clumsy but it gets the job done.
I have prepared a sample implementation of the approach described above - see "Sections" example.
For details on the user-mode helper API, see the code in
<linux/kmod.c>
and<linux/kmod.h>
in the kernel sources, namely the definition ofcall_usermodehelper()
. The examples as well as the explanation of typical usage of the API are available in this article.Note that the examples from that article are a bit inaccurate: the init function of the module returns the result of
call_usermodehelper()
there. The latter, however, returns 2-byte status code (at least when called withUMH_WAIT_PROC
) rather than 0 or negative error code that init function is expected to return. This may result in runtime warnings. Whatcall_usermodehelper()
actually returns, is explained here.文件 linux/kernel/module.c 有一些非静态函数(但前面没有 EXPORT_SYMBOL),例如 module_address_lookup(),但这些函数使用诸如 preempt_disable() 和 _enable() 之类的东西。我宁愿不使用此功能,并建议使用 sysfs-interface 代替,尽管您的驱动程序已经处于内核模式。
The file linux/kernel/module.c has some non-static functions (but without this EXPORT_SYMBOL in front) like module_address_lookup(), but these functions use things like preempt_disable() and _enable(). I'd rather not use this functions and would suggest to use sysfs-interface instead, altho your driver is already in kernel mode.