安装内核模块时,如果里面有更改系统调用等情况,有时会崩溃,出现如下错误:
<1>BUG:unable to handle kernel paging request at virtual address c06357b4
printing eip:d0aac056 *pde = 0e9dd163 *pte = 00635161
Oops: 0003 [#1] SMP
Modules linked in: test2(U) addsym(U) nls_utf8autofs4 fuse rfcomm l2cap bluetooth sunrpc nf_conntrack_ftp nf_conntrack_ipv4xt_state nf_conntrack xt_tcpudp ipt_REJECT ip
原因:由于控制寄存器CR0的第16位若置位,则表示禁止系统进程写只有只读权限的页面(sys_call_table),
所以我们给sys_call_table添加内容的话就必须将CR0的第16位清零,在模块卸载的时候给还原
示例代码如下:
清除标志位:
static int clear_cr0(void)
{
unsigned int cr0 = 0;
unsigned int ret;
asm volatile ("movq %%cr0, %%rax":"=a"(cr0));
ret = cr0;
cr0 &=0xfffeffff;
asm volatile ("movq %%rax, %%cr0": :"a"(cr0));
return ret;
}
恢复标志位:
static void setback_cr0(int val)
{
asm volatile ("movq %%rax, %%cr0": :"a"(val));
}
注意:
在32位和64位的系统下汇编指令是有区别的,上面是32位系统下的代码,
从32位扩充到了64位,名字也发生了变化。8个通用寄存器(eax, ebx,ecx, edx, ebp, esp, esi, edi)在新的结构中被命名为rax,rbx, rcx, rdx, rbp, rsp, rsi, rdi。movl命令也需相应改成movq。
使用示例:
orig_cr0= clear_cr0();//保留标志位
sys_call_table[__NR_connect]= (unsigned long )test;//更改系统调用
setback_cr0(orig_cr0);//恢复标志位
当卸载模块,需要恢复系统调用时,同理。