好的,我正在尝试从内核模块向我的Linux添加一个系统调用。 这是模块代码。
asmlinkage int my_syscall() {
printk(KERN_INFO "AWESOME!\n");
return 0;
}
int load() {
unsigned long ** addr;
unsigned long int i = START;
printk(KERN_INFO "IN\n");
while (i < END) {
addr = (unsigned long **)i;
if (addr[__NR_close] == (unsigned long *)sys_close) {
break;
}
i += sizeof(void *);
}
if (i != END) {
addr += __NR_vserver;
struct page * p = virt_to_page(addr);
unsigned long paddr = (unsigned long)page_address(p);
set_memory_rw(paddr, 15);
*addr = &my_syscall;
set_memory_ro(paddr, 15);
}
return 0;
}
void unload() {
printk(KERN_INFO "OUT\n");
}
module_init(load);
module_exit(unload);
所以我正在寻找sys_call_table
,一旦找到它,我就试图覆盖未实现的系统调用(vserver
)。
当我insmod
得到.ko
时,dmesg
就是这样说的:
BUG: unable to handle kernel paging request at ffffffff81801bc0
0xffffffff81801bc0
实际上是我尝试编写&my_syscall
的地址。
我不确切地知道我做错了什么,但我认为当我尝试编写时,内存页面可能仍处于ro
模式...
答案 0 :(得分:0)
我不明白的是以下几行:
set_memory_rw(paddr, 15);
这里应该发生什么?
您无法更改实际地址的属性!
以下代码可能是正确的:
set_memory_rw(addr, 15);
(在这种情况下,您不需要物理地址“paddr”也不需要页面“p”。)
或者,您可以尝试在内核空间中第二次映射物理地址。
您应该在“unload()”函数中恢复原始指针!!
答案 1 :(得分:0)
如果0xffffffff81801bc0是您传递给set_memory_rw()的实际地址,那么它肯定是错误的值。该地址应该向上舍入到PAGE_MASK边界,即页面的起始地址,对于64位系统,通常以4个零结束。
set_memory_rw()使用内存页表的U / S位进行操作。但是x86 / amd64 CPU有另一个属性:WP位(在cr0内)。根据英特尔手册,WP位覆盖了内存页表属性,即无论内存是否只读,启用/禁用WP位仍然有效。但是WP位是per-cpu,因此要小心地同步你的内存访问,这样在更改内存内容时,另一个CPU不会读取它。 (对于你未使用的系统调用号,这应该没问题。)
答案 2 :(得分:-2)
看起来你在系统调用的实现中遗漏了一些东西。只需看看http://arvindsraj.wordpress.com/2012/10/05/adding-hello-world-system-call-to-linux/,它解释了实施系统调用的逐步程序,并检查您是否正确地执行了所有步骤。