截获Linux操作系统异常处理

发表于:2013-5-13 09:55

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:RichardUSTC    来源:51Testing软件测试网采编

分享:

  我仿照着写了一个,名为my_page_fault:

  1. asmlinkage void my_page_fault(void); 
  2. asm("   .text"); 
  3. asm("   .type my_page_fault,@function"); 
  4. asm("my_page_fault:"); 
  5. //the first 3 bytes of the routine basically do nothing, 
  6. //but I decide to keep them because kernel may rely on them for some special purpose 
  7. asm("   .byte 0x66"); 
  8. asm("   xchg %ax, %ax"); 
  9. asm("   callq *addr_adjust_exception_frame"); 
  10. asm("   sub $0x78, %rsp"); 
  11. asm("   callq *addr_error_entry"); 
  12. asm("   mov %rsp, %rdi"); 
  13. asm("   mov 0x78(%rsp), %rsi"); 
  14. asm("   movq $0xffffffffffffffff, 0x78(%rsp)"); 
  15. asm("   callq my_do_page_fault"); 
  16. asm("   jmpq *addr_error_exit"); 
  17. asm("   nopl (%rax)");

  其中第9行addr_adjust_exception_frame是(pv_irq_ops+0x30)地址处存储的值;第11行addr_error_entry是error_entry的地址;第16行addr_error_exit是error_exit的地址。这几个值需要从System.map文件中查询,然后用内核模块参数的形式传入。而my_do_page_fault则是我们自己定义的page fault处理函数。

  如果需要截获X86_32的page fault,可以参考这个C文件。不过需要注意的是,新版内核有所变动,这里的代码需要根据自己的情况做一些调整。

  有了自定义的ISR之后,就可以将这个ISR填到IDT中,加载新的IDT表之后,自定义的page fault处理函数就开始发挥作用了。这个过程主要有以下几个步骤:

  用store_idt(&default_idtr)保存现有的IDT寄存器值

  从default_idtr中读出IDT表首地址和表的大小

  申请一个页面

  将原来的idt表拷贝到新申请的页面中

  利用pack_gate将my_page_fault(注意不是my_do_page_fault)填入到对应的IDT项中

  在idtr中填写新的IDT表地址和大小,用load_idt(&idtr)加载新的IDT表到当前CPU

  利用smp_call_function,将新的IDT表加载到其他CPU上。

  如果想恢复原来的IDT表,则用load(&default_idtr)和smp_call_function加载原来的IDT表,释放申请的页面。

  读完文章之后,可以参考我的github中的代码:https://github.com/RichardUSTC/intercept-page-fault-handler

22/2<12
100家互联网大公司java笔试题汇总,填问卷领取~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号