【问题标题】:How do I access any kernel symbol in a kernel module?如何访问内核模块中的任何内核符号?
【发布时间】:2017-03-18 18:58:17
【问题描述】:

我想在我的内核模块中使用函数getname。它不出口。由于我现在遇到了这个问题,我想知道如何访问和使用任何未导出的内核符号。我认为使用一个所需的步骤会有所不同,具体取决于符号是什么,所以我想看看如何为类型(例如,结构)、变量、指针表(如系统调用表)和一个函数。在这两种情况下如何做到这一点:

  • 当我从System.map/proc/kallsyms 知道符号的地址时。
  • 当我知道符号的名称并想使用kallsyms_lookup_name 检索它时。

我目前知道如何劫持系统调用,这需要声明类似

asmlinkage <return_type> (*<name_for_system_call>)(<the types of the its arguments separated by commas>);

会使用类似的东西吗?在this另一个问题的回答中,发帖人给出的例子是

#include <linux/kallsyms.h>

static void (*machine_power_off_p)(void);
machine_power_off = (void*) kallsyms_lookup_name("machine_power_off");

但是如果符号返回一个指针呢?我可以在(*machine_power_off_p) 的左边加一个星号吗?

【问题讨论】:

  • “我要不要在第一组括号的左边加一个星号?”哪个括号?您的问题中有很多括号。那么您是在问如何调用函数指针吗?谷歌应该能够告诉你。例如:How do function pointers in C work?
  • @kaylum 该问题正上方示例中的第一组。
  • But what if the symbol returns a pointer? - 然后将示例中的 left void 替换为返回类型(例如,struct filename *)。正如 kaylum 所注意到的,问题实际上是关于函数指针的使用。

标签: c linux linux-kernel kernel-module


【解决方案1】:

#include &lt;linux/fs.h&gt; 声明 extern struct filename *getname(const char __user *);。指向此函数的指针的类型为 struct filename *(*)(const char __user *)。如果声明该类型的变量,则变量名称在(*) 中的* 之后。所以你可以声明一个该类型的变量并将kallsyms_lookup_name("getname")的返回值分配给它,如下所示:

static struct filename *(*getname_p)(const char __user *);

/* within a function body... */
getname_p = (struct filename *(*)(const char __user *))
            kallsyms_lookup_name("getname");

对于您想要使用数字地址的其他情况,只需将 kallsyms_lookup_name 函数调用替换为实际数字(kallsyms_lookup_name 将符号值作为数字返回)。

编辑 2021-01-19

GCC typeof 扩展可用于将getname 的原型从#include &lt;linux/fs.h&gt; 复制到getname_p 指针,如下所示:

#include <linux/fs.h>

static typeof(&getname) getname_p;

/* within a function body... */
getname_p = (typeof(&getname))kallsyms_lookup_name("getname");

编辑 2021-05-17

从 5.7 内核开始,kallsyms_lookup_namekallsyms_on_each_symbol 不再导出到可加载内核模块。

【讨论】:

  • 有没有将函数定义为getname 而不是getname_p?是否可以以不需要查找原始函数声明的方式完成?
  • @Melab 函数指针变量不能被调用getname,除非它被声明在内部范围内(例如在函数体中),因为它会与声明的getname函数的声明冲突通过#include &lt;linux/fs.h&gt;。但是,您可以通过使用 GCC typeof 扩展名来简化 getname_p 变量的声明和 kallsyms_lookup_name 的返回值的转换,如我上面编辑的答案所示。
【解决方案2】:

访问未导出的函数与访问导出的函数没有区别,只是您无法在内核中解析其地址。你可以这样做:

static void (*your_func)(void);
your_func=0xhex_addr;

或用于结构

strucr your_struct{int i;double j} *stru;
stru=0xhex_addr;

指针的类型只是定义了从指针地址读取或写入多少字节。

对于结构或变量的十六进制地址,甚至可能驻留在内核代码段中,但如果您尝试向该结构或变量写入内容,则会出现分段错误 - 读取将是合法的。还有一件事......当使用结构做这个技巧时,不要忘记结构数据对齐。

【讨论】:

    猜你喜欢
    • 2014-03-01
    • 1970-01-01
    • 2018-05-20
    • 1970-01-01
    • 2016-03-23
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    • 2013-01-21
    相关资源
    最近更新 更多