当前位置: 首页 > 面试题库 >

我可以用模块替换Linux内核功能吗?

薛高澹
2023-03-14
问题内容

我在暑期研究中从事内核工作。我们希望在特定的RTT计算中对TCP进行修改。我想做的是将tcp_input.c中的功能之一的分辨率替换为由动态加载的内核模块提供的功能。我认为这将改善我们开发和分发修改的速度。

我感兴趣的函数被声明为静态的,但是我用非静态函数重新编译了内核,并由EXPORT_SYMBOL导出。这意味着该功能现在可供内核的其他模块/部分访问。我已经通过“
cat / proc / kallsyms”验证了这一点。

现在,我希望能够加载一个模块,该模块可以将符号地址从初始重写为动态加载的函数。同样,当要卸载模块时,它将恢复原始地址。这是可行的方法吗?大家都有建议如何更好地实施吗?

谢谢!

Linux内核中的模块的覆盖功能 相同

编辑:
这是我最终的方法。
给定以下功能(我想覆盖它,但不导出):

static void internal_function(void) 
{
  // do something interesting
  return;
}

像这样修改:

static void internal_function_original(void)
{
  // do something interesting
  return;
}

static void (*internal_function)(void) = &internal_function_original;
EXPORT_SYMBOL(internal_function);

这将预期的函数标识符重新定义为指向原始实现的函数指针(可以以类似方式调用)。EXPORT_SYMBOL()使地址可全局访问,因此我们可以从模块(或其他内核位置)对其进行修改。

现在,您可以使用以下形式编写内核模块:

static void (*original_function_reference)(void);
extern void (*internal_function)(void);

static void new_function_implementation(void)
{
  // do something new and interesting
  // return
}

int init_module(void)
{
  original_function_reference = internal_function;
  internal_function           = &new_function_implementation;
  return 0;
}

void cleanup_module(void)
{
  internal_function = original_function_reference;
}

该模块将原来的实现替换为动态加载的版本。卸载后,将还原原始参考(和实现)。在我的特定情况下,我为TCP中的RTT提供了一个新的估算器。通过使用模块,我可以进行细微调整并重新开始测试,而无需重新编译和重新启动内核。


问题答案:

我不确定是否可以正常工作-我相信要在模块加载时已经完成了对要替换的函数的内部调用的符号解析。

相反,您可以通过重命名现有函数,然后使用该函数的原始名称创建一个全局函数指针来更改代码。将函数指针初始化为内部函数的地址,因此现有代码将保持不变。导出全局函数指针的符号,然后您的模块就可以通过在模块加载和卸载时进行赋值来更改其值。



 类似资料:
  • 问题内容: 在不深入了解 为什么 的细节的情况下,我正在寻找一种干净的(尽可能)的方法来替换可加载模块中的内核函数和系统调用。我最初的想法是编写一些代码来覆盖某些功能,这些功能将采用原始功能(可能的话, 调用 该功能),然后添加一些自己的代码。关键是我编写的函数必须具有原始函数的名称,因此其他代码在尝试访问它时将改为访问我的函数。 通过将代码放入适当的函数中,我可以轻松地(相对地)直接在内核中执行

  • 问题内容: 我正在测试内核异步io函数(不是posix aio),并试图弄清楚它是如何工作的。下面的代码是一个完整的程序,其中我简单地将一个数组重复写入使用O_DIRECT打开的文件中。我在回调函数中收到一个错误“写错的字节期望1024得到0”(请参阅​​work_done()中的fprintf语句)。 对于不熟悉内核aio的用户,以下代码将执行以下操作: 初始化一些结构 准备AIO(io_pre

  • MANAGING THE LINUX KERNEL AND LOADABLE KERNEL MODULES 所有操作系统至少由两个主要组件组成。其中第一个也是最重要的是内核。 内核位于操作系统的中心,控制着操作系统所做的一切,包括管理内存,控制 CPU,甚至控制用户在屏幕上看到的内容。操作系统的第二个元素通常被称为用户区域,几乎包括其他所有元素。 内核被设计成一个受保护或特权的区域,只能由 roo

  • 主要内容:initramfe虚拟文件系统GRUB 加载了内核之后,内核首先会再进行二次系统的自检,而不一定使用 BIOS 检测的硬件信息。这时内核终于开始替代 BIOS 接管 Linux 的启动过程了。 内核完成再次系统自检之后,开始采用动态的方式加载每个硬件的模块,这个动态模块大家可以想象成硬件的驱动(默认 Linux 硬件的驱动是不需要手工安装的,如果是重要的功能,则会直接编译到内核当中;如果是非重要的功能,比如硬件驱动会编译为模块

  • 主要内容:内核模块保存位置与模块保存文件,内核模块的查看,内核模块的添加与删除Linux 的内核会在启动过程中自动检验和加载硬件与文件系统的驱动。一般这些驱动都是用模块的形式加载的,使用模块的形式保存驱动,可以不直接把驱动放入内核,有利于控制内核大小。 模块的全称是 动态可加载内核模块,它是具有独立功能的程序,可以被单独编译,但不能独立运行。模块是为内核或其他模块提供功能的代码集合。这些模块可以是 Linux 源码中自带的,也可以是由硬件厂商开发的(可以想象成驱动)。不过内

  • 问题内容: 我正在学习和编程。根据Jonathan Corbet的书,我们没有设备驱动程序中的功能。 在这里我有两个问题: 为什么我们不需要设备驱动程序中的功能? 内核有功能吗? 问题答案: 从根本上讲,例程的命名没有什么特别的。如上所述,它充当可执行加载模块的入口点。但是,您可以为装入模块定义不同的入口点。实际上,您可以定义多个入口点,例如,引用您喜欢的dll。 从操作系统(OS)的角度来看,它