ランタイムエラーの原因となる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("[email protected]");
これは、コードのどこかに、アクセスしようとしている無効なポインタがあることを意味します。オンザフライでコードをデバッグすることはできませんが、いくつか提案があります。
printk("%p", pointer)
を挿入するだけで、変数の内容を確認できます。 または、 systemtap または同様のツールを使用できます。