我写了一些Linux内核代码,导致运行时出错,并报告linux unable to handle kernel paging request at ffffffff00000010
。
这只是一个在Linux内核编程中挂钩open
系统调用的代码。
以下是该代码:
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <asm/uaccess.h>
#include <asm/fcntl.h>
#include <asm/unistd.h>
#include <asm/ia32_unistd.h>
#include <asm/msr.h>
unsigned long *sys_table = NULL;
asmlinkage long (*old_open) (const char __user *filename, int flags, umode_t mode);
static void *memmem(const void *haystack, size_t haystack_len,
const void *needle, size_t needle_len);
#define dbg(format,args...) \
printk("intercept: function:%s-L%d: "format, __FUNCTION__, __LINE__, ##args);
asmlinkage long new_open(char *filename, int flags, int mode)
{
printk("call open()\n");
return old_open (filename, flags, mode);
}
unsigned int clear_and_return_cr0(void)
{
unsigned long cr0 = 0;
unsigned long ret;
asm volatile ("movq %%cr0, %%rax"
: "=a"(cr0)
);
ret = cr0;
/* clear the 20 bit of CR0, a.k.a WP bit */
cr0 &= 0xfffffffffffeffff;
asm volatile ("movq %%rax, %%cr0"
:
: "a"(cr0)
);
return ret;
}
void setback_cr0(unsigned long val)
{
asm volatile ("movq %%rax, %%cr0"
:
: "a"(val)
);
}
static unsigned long get_syscall_table_long(void)
{
#define OFFSET_SYSCALL 200
unsigned long syscall_long, retval;
char sc_asm[OFFSET_SYSCALL];
rdmsrl(MSR_LSTAR, syscall_long);
memcpy(sc_asm, (char *)syscall_long, OFFSET_SYSCALL);
retval = (unsigned long) memmem(sc_asm, OFFSET_SYSCALL, "/xff/x14/xc5", 3);
if ( retval != 0 ) {
retval = (unsigned long) ( * (unsigned long *)(retval+3) );
} else {
printk("long mode : memmem found nothing, returning NULL:(");
retval = 0;
}
#undef OFFSET_SYSCALL
return retval;
}
static void *memmem(const void *haystack, size_t haystack_len,
const void *needle, size_t needle_len)
{
const char *begin;
const char *const last_possible = (const char *) haystack + haystack_len - needle_len;
if (needle_len == 0){
/* The first occurrence of the empty string is deemed to occur at
the beginning of the string. */
return (void *) haystack;
}
if (__builtin_expect(haystack_len < needle_len, 0)){
return NULL;
}
for (begin = (const char *) haystack; begin <= last_possible; ++begin)
{
if (begin[0] == ((const char *) needle)[0]
&& !memcmp((const void *) &begin[1],
(const void *) ((const char *) needle + 1),
needle_len - 1)){
return (void *) begin;
}
}
return NULL;
}
static int init_sys_call_table(void)
{
printk("init_sys_call_table\n");
unsigned long orig_cr0 = clear_and_return_cr0();
printk("orig_cr0 %lu\n",orig_cr0);
sys_table = (unsigned long *) get_syscall_table_long();
if (sys_table == 0){
dbg("sys_table == 0/n");
return -1;
}
sys_table = (unsigned long)sys_table | 0xffffffff00000000;
#define REPLACE(x) old_##x = sys_table[__NR_##x];\
sys_table[__NR_##x] = new_##x
REPLACE(open);
setback_cr0(orig_cr0);
return 0;
}
static void clean_sys_call_table(void)
{
unsigned long orig_cr0 = clear_and_return_cr0();
#define RESTORE(x) sys_table[__NR_##x] = old_##x
RESTORE(open);
setback_cr0(orig_cr0);
return ;
}
static int __init init_64mod(void)
{
init_sys_call_table();
return 0;
}
static void __exit exit_64mod(void)
{
clean_sys_call_table();
}
module_init(init_64mod);
module_exit(exit_64mod);
MODULE_AUTHOR("xxx@yyy.com");