web-dev-qa-db-fra.com

Quelle est l'erreur de "Linux incapable de gérer la demande de pagination du noyau à ffffffff00000010"?

J'ai écrit du code de noyau Linux, ce qui provoque une erreur d'exécution et signale linux unable to handle kernel paging request at ffffffff00000010.

C'est juste un code pour accrocher l'appel système open dans la programmation du noyau Linux.

Le code est répertorié ci-dessous:

#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("[email protected]");
12
Victor

Cela signifie que quelque part dans votre code, vous avez un pointeur non valide auquel vous essayez d'accéder. Je ne peux pas déboguer votre code à la volée mais je peux vous donner quelques suggestions:

  • essayez d'éviter le casting jusqu'à ce qu'il soit strictement nécessaire
  • lorsque vous effectuez un cast vers un pointeur, vérifiez que c'est bien ce que vous voulez faire
  • dans le message d'erreur il y a aussi la pile, jetez un oeil dessus pour identifier où est l'erreur
  • vous pouvez simplement mettre un peu de printk("%p", pointer) dans votre code pour vérifier le contenu de vos variables. Alternativement , vous pouvez utiliser systemtap ou des outils similaires.
8
Federico