c - "linux unable to handle kernel paging request at ffffffff00000010"的错误是什么?

标签 c linux linux-kernel kernel kernel-module

我写了一些 Linux 内核代码,导致运行时错误,并报告 linux unable to handle kernel paging request at ffffffff00000010

这只是Linux内核编程中hookopen系统调用的代码。

代码如下:

#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");

最佳答案

这意味着您的代码中某处有一个您试图访问的无效指针。我无法即时调试您的代码,但我可以给您一些建议:

  • 尽量避免强制转换,直到绝对必要为止
  • 当你转换为一个指针时,仔细检查它是否是你想要做的
  • 报错信息中也有栈,看一下可以判断哪里出错了
  • 您可以简单地在代码中放置一些printk("%p", pointer) 来检查变量的内容。 或者,您可以使用systemtap或类似工具。

关于c - "linux unable to handle kernel paging request at ffffffff00000010"的错误是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26925114/

相关文章:

linux - 如何在用户级别获取套接字描述符的引用计数?

c - 组播监听和接口(interface)IP地址变化

c - 为什么将指向数组的指针传递给需要指向 int 的指针的函数可以正常工作而不会出现错误

c - 将数据从 iphdr 传递到结构

c - 为什么在等待条件变量时需要 while 循环

c++ - 我怎样才能确定 dlopen 正常工作

c - 死亡循环,也许是 scanf

c - typedef 一个函数指针

linux - 'perf stat' 结果中的停滞周期前端和停滞周期后端是什么?

linux - Linux 用户空间上的 USB 插件检测