1

好的,所以我正在尝试从内核模块向我的 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当我尝试写时内存页面可能仍处于模式...

4

3 回答 3

0

我不明白的是以下行:

set_memory_rw(paddr, 15);

这里应该发生什么?

您不能更改物理地址的属性!

也许下面的代码是正确的:

set_memory_rw(addr, 15);

(在这种情况下,您不需要物理地址“paddr”或页面“p”。)

或者,您可以尝试在内核空间中再次映射物理地址。

您应该在“unload()”函数中恢复原始指针!!

于 2013-09-20T19:56:13.320 回答
0

如果 0xffffffff81801bc0 是您传递给 set_memory_rw() 的实际地址,那么它肯定是错误的值。地址应该四舍五入到PAGE_MASK边界,即页面的起始地址,对于64位系统,通常以4个零结尾。

set_memory_rw() 使用内存页表的 U/S 位进行操作。但是 x86/amd64 CPU 还有另一个属性:WP 位(在 cr0 内)。根据 Intel 手册,WP 位会覆盖内存页表属性,即无论内存是否为只读,启用/禁用 WP 位仍然有效。但是WP位是per-cpu的,所以要小心同步你的内存访问,这样在改变内存内容的同时,另一个CPU不会读取它。(对于您未使用的系统调用号,这应该没问题)。

http://vulnfactory.org/blog/2011/08/12/wp-safe-or-not/

于 2014-03-19T01:12:24.267 回答
-1

看起来你在系统调用的实现中遗漏了一些东西。只需看看http://arvindsraj.wordpress.com/2012/10/05/adding-hello-world-system-call-to-linux/它解释了实现系统调用的逐步过程并检查您是否有是否正确执行了所有步骤。

于 2013-09-20T14:26:47.453 回答