處理地址空間以外的錯誤地址

來源:互聯網
上載者:User

前面博文提到了,如果address不屬於進程的地址空間,那麼do_page_fault()函數繼續執行bad_area標記處的語句。如果錯誤發生在使用者態,則發送一個SIGSEGV訊號給current進程並結束函數:

/*
 * Something tried to access memory that isn't in our memory map..
 * Fix it, but check if it's kernel or user first..
 */
bad_area:
 up_read(&mm->mmap_sem);

bad_area_nosemaphore:
 /* User mode accesses just cause a SIGSEGV */
 if (error_code & 4) {
  /*
   * Valid to do another page fault here because this one came
   * from user space.
   */
  if (is_prefetch(regs, address, error_code))
   return;

  tsk->thread.cr2 = address;
  /* Kernel addresses are always protection faults */
  tsk->thread.error_code = error_code | (address >= TASK_SIZE);
  tsk->thread.trap_no = 14;
  force_sig_info_fault(SIGSEGV, si_code, address, tsk);
  return;
 }

#ifdef CONFIG_X86_F00F_BUG
 /*
  * Pentium F0 0F C7 C8 bug workaround.
  */
 if (boot_cpu_data.f00f_bug) {
  unsigned long nr;
  
  nr = (address - idt_descr.address) >> 3;

  if (nr == 6) {
   do_invalid_op(regs, 0);
   return;
  }
 }
#endif

 

force_sig_info_fault()函數確信進程不忽略或阻塞SIGSEGV訊號,並通過si_code局部變數傳遞附加資訊的同時把該訊號發送給使用者態進程。si_code變數已被置為SEGV_MAPERR(如果異常是由於一個不存在的頁框引起,上篇博文剛開始的時候),或置為SEGV_ACCERR(如果異常是由於對現有頁框的無效訪問引起)。

 

如果異常發生在核心態(error_code的第2位被清0,即error_code & 4為0),仍然有兩種可選的情況:
(1)異常的引起是由於把某個線性地址作為系統調用的參數傳遞給核心。
(2)異常是因一個真正的核心缺陷所引起的。

 

函數這樣區分這兩種可選的情況:
no_context:
 /* Are we prepared to handle this kernel fault?  */
 if (fixup_exception(regs))
  return;

 /*
  * Valid to do another page fault here, because if this fault
  * had been triggered by is_prefetch fixup_exception would have
  * handled it.
  */
  if (is_prefetch(regs, address, error_code))
   return;

 

在第一種情況中,代碼跳到一段“修正代碼”處,這段代碼的典型操作就是向當前進程發送SIGSEGV訊號,或用一個適當的出錯碼終止系統調用處理常式:
int fixup_exception(struct pt_regs *regs)
{
 const struct exception_table_entry *fixup;

#ifdef CONFIG_PNPBIOS
 if (unlikely((regs->xcs & ~15) == (GDT_ENTRY_PNPBIOS_BASE << 3)))
 {
  extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
  extern u32 pnp_bios_is_utter_crap;
  pnp_bios_is_utter_crap = 1;
  printk(KERN_CRIT "PNPBIOS fault.. attempting recovery./n");
  __asm__ volatile(
   "movl %0, %%esp/n/t"
   "jmp *%1/n/t"
   : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
  panic("do_trap: can't hit this");
 }
#endif

 fixup = search_exception_tables(regs->eip);
 if (fixup) {
  regs->eip = fixup->fixup;
  return 1;
 }

 return 0;
}
const struct exception_table_entry *search_exception_tables(unsigned long addr)
{
 const struct exception_table_entry *e;

 e = search_extable(__start___ex_table, __stop___ex_table-1, addr);
 if (!e)
  e = search_module_extables(addr);
 return e;
}

 

在第二種情況中,函數把CPU寄存器和核心態堆棧的全部轉儲列印到控制台,並輸出到一個系統訊息緩衝區,然後調用函數do_exit()殺死當前進程。這就是所謂按所顯示的訊息命名的“核心漏洞(Kernel oops)”錯誤。這片代碼我就不多講了,如果你是核心高手,這些輸出值可由核心編程高手用於推測引發此錯誤的條件,進而發現並糾正錯誤:
/*
 * Oops. The kernel tried to access some bad page. We'll have to
 * terminate things with extreme prejudice.
 */

 bust_spinlocks(1);

 if (oops_may_print()) {
 #ifdef CONFIG_X86_PAE
  if (error_code & 16) {
   pte_t *pte = lookup_address(address);

   if (pte && pte_present(*pte) && !pte_exec_kernel(*pte))
    printk(KERN_CRIT "kernel tried to execute "
     "NX-protected page - exploit attempt? "
     "(uid: %d)/n", current->uid);
  }
 #endif
  if (address < PAGE_SIZE)
   printk(KERN_ALERT "BUG: unable to handle kernel NULL "
     "pointer dereference");
  else
   printk(KERN_ALERT "BUG: unable to handle kernel paging"
     " request");
  printk(" at virtual address %08lx/n",address);
  printk(KERN_ALERT " printing eip:/n");
  printk("%08lx/n", regs->eip);
 }
 page = read_cr3();
 page = ((unsigned long *) __va(page))[address >> 22];
 if (oops_may_print())
  printk(KERN_ALERT "*pde = %08lx/n", page);
 /*
  * We must not directly access the pte in the highpte
  * case, the page table might be allocated in highmem.
  * And lets rather not kmap-atomic the pte, just in case
  * it's allocated already.
  */
#ifndef CONFIG_HIGHPTE
 if ((page & 1) && oops_may_print()) {
  page &= PAGE_MASK;
  address &= 0x003ff000;
  page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT];
  printk(KERN_ALERT "*pte = %08lx/n", page);
 }
#endif
 tsk->thread.cr2 = address;
 tsk->thread.trap_no = 14;
 tsk->thread.error_code = error_code;
 die("Oops", regs, error_code);
 bust_spinlocks(0);
 do_exit(SIGKILL);

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.