这是不可能的,因为系统调用表(称为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.c
为sizeof(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的偏移量,因此可以计算表的起始地址。