我试图用我自己的函数替换open系统的linux系统调用。在内核版本2.6之后,不会导出Sys_call_table sysmbol。我从system.map文件硬编码sys_call_table的虚拟地址。
我保存了原始系统调用[NR_OPEN],然后尝试使用system_map中的set_memory_rw函数,因为它不适用于arm linux。我正在为beaglebone编写内核模块。如果我尝试通过函数指针使用system.map文件中给出的虚拟地址来使用该函数,我会得到无法处理内核分页请求的内核oops。
System_call_table是只读的,如果我尝试写入它,它会在str指令中给出内核oops。
我使用以下代码:
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/unistd.h>
#include <asm/memory.h>
MODULE_LICENSE("GPL"); ///< The license type -- this
affects runtime behavior MODULE_AUTHOR("Zohaib"); ///< The author
-- visible when you use modinfo
unsigned long *sys_call_table = (unsigned long *) 0xc0107a28; int a;
unsigned long phy_addr_sys_call_table,x;
asmlinkage unsigned long int (*vir_to_phy) (unsigned long int x);
static asmlinkage int (*set_mem_rw) (unsigned long int, int); static
asmlinkage int (**write) (unsigned long int, int); static asmlinkage
int (*original_call) (const char*, int, int); int ret;
static asmlinkage int our_sys_open(const char* file, int flags, int
mode) { printk("A file was opened\n"); return
original_call(file, flags, mode); }
static int __init hello_module(void) {
// sys_call_table address in System.map
printk("NEW \n");
x= virt_to_phys((void*)0xc0115fe0);
printk(" %p", (void*)(x));
printk(" \n \n \n DEBUG POINT 1:");
write=(int (**) (unsigned long int, int))(virt_to_phys((void*)0xc0115fe0));
printk("\n \n \n DEBUG POINT 2");
set_mem_rw= *write;
printk("HI \n");
printk(" \n \n \n : %p", set_mem_rw);
a=__NR_open;
printk(" \n \n \n %i",a);
original_call = (void*)*(sys_call_table + __NR_open);
printk("\n \n \n vir_to_phys test \n");
phy_addr_sys_call_table= virt_to_phys((void*)0xc0107a28);
printk("\n \n \n vir_to_phys test succeeded: %p", (void*)phy_addr_sys_call_table);
printk("\n CRASHINNNNNNNNN..... ");
// this is where it crashes.
ret=(*set_mem_rw)((unsigned long)phy_addr_sys_call_table,20);
printk("\n CRASH point no.1 ");
printk( "\n %lu ", sys_call_table[__NR_open]);
printk( "\n %p ", original_call);
printk(" \n DIDN'T CRASH at point no.1 \n");
printk("CRASH point no.2 \n");
printk("%p", sys_call_table);
printk(" \n DIDN'T CRASH at point no.2 \n");
// read only sys_call_table, cannot write to it if readwrite privilege is not given, gives kernel oops otherwise
printk(" \n \n %p \n", (our_sys_open));
*(sys_call_table + __NR_open) = (unsigned long)our_sys_open;
printk(" \n SUCCEEDED ");
return 0; }
static void __exit bye_module(void) { // Restore the original call
sys_call_table[__NR_open] = original_call;
printk("BYE"); }
module_init(hello_module); module_exit(bye_module);