使用可加载的内核模块向Linux 3.2.x添加新的系统调用


11

我想在Linux内核3.2.x中添加一个特定的新系统调用,但作为可加载的内核模块(因为我不想一次又一次地重新编译内核)

我通读了Internet和SO上的许多文章,有些地方声称不可能将系统调用实现为可加载模块,而另一些地方则认为可以实现。

哪有 如果有可能怎么办?


这个问题不在这里了:Unix&Linux是关于使用和管理的,而不是编程的。你应该问堆栈溢出。不要那么含糊:链接到您在Stack Overflow上找到的帖子,并解释您发现的结论性或矛盾性的内容。
吉尔(Gilles)“所以,别再邪恶了”

2
我相信这个问题与作为操作系统的Linux有关,而不是与编程本身有关。了解扩展我们系统能力的可能性以及其局限性也非常重要。例如,这使您了解了为什么某些功能无法实现为可加载模块并需要内核修补的原因。知道为什么会这样,可能还会给您一些内核开发人员必须做出的安全性与可用性的想法。如果OP仅询问是否可能,为什么不问如何实现这一点,是否会更多地围绕这个问题进行讨论?
Krzysztof Adamski 2012年

1
Linux内核邮件列表上有许多<stroke> flames </ stroke>讨论,例如reiserfs使用自己的syscall,而Linus等一些核心开发人员并没有真正喜欢它。在您的情况下,我将简单地使用ioctl()s来完成任务,它们很容易模块化。Afaik使得此操作尽可能困难的主要原因是,系统调用的数量可能是高度硬编码的,并且没有人希望混乱它会进入画面。但是有许多内核接口可以达到相同的功能,例如sysfs,ioctls等。
peterh-恢复莫妮卡2015年

Answers:


14

这是不可能的,因为系统调用表(称为sys_call_table)是静态大小数组。其大小在编译时由注册的系统调用数确定。这意味着没有空间可容纳另一个。

您可以检查在arch/x86/kernel/syscall_64.c文件中sys_call_table定义了x86体系结构的实现。它的大小正好是__NR_syscall_max+1__NR_syscall_max定义arch/x86/kernel/asm-offsets_64.csizeof(syscalls) - 1(是上一个syscall的数量),其中syscall是包含所有syscall的表。

一种可能的解决方案是与您的系统重用一些现有的(或已弃用的,如果您的体系结构有一个,sys_setaltroot例如参见)系统调用号,因为这将不需要更多的内存空间。某些体系结构在syscall表中可能也有漏洞(例如x86的64位版本),因此您也可以使用它。

如果您正在开发新的syscall,并且只是想避免在实验时重新启动,则可以使用此技术。您将必须定义新的系统调用,在syscall表中找到现有条目,然后从模块中替换它。

从内核模块执行此操作并非易事,sys_call_table因为从2.6版开始,内核不会导出到模块(导出该符号的最后一个内核版本是2.5.41)。

解决此问题的一种方法是更改​​内核以将sys_call_table符号导出到模块。为此,您必须添加以下两行kernel/kallsyms.c不要在生产计算机上执行此操作):

extern void *sys_call_table;
EXPORT_SYMBOL(sys_call_table);

另一种技术是动态查找syscall表。您遍历内核内存,将每个单词与指向已知系统调用函数的指针进行比较。由于您知道表中此已知syscall的偏移量,因此可以计算表的起始地址。


1

不幸的是,您不能将系统调用作为可加载模块添加到内核。每次添加新的系统调用时,您都必须承担编译内核的麻烦。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.