extable.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. #include <linux/extable.h>
  2. #include <asm/uaccess.h>
  3. #include <asm/traps.h>
  4. #include <asm/kdebug.h>
  5. typedef bool (*ex_handler_t)(const struct exception_table_entry *,
  6. struct pt_regs *, int);
  7. static inline unsigned long
  8. ex_fixup_addr(const struct exception_table_entry *x)
  9. {
  10. return (unsigned long)&x->fixup + x->fixup;
  11. }
  12. static inline ex_handler_t
  13. ex_fixup_handler(const struct exception_table_entry *x)
  14. {
  15. return (ex_handler_t)((unsigned long)&x->handler + x->handler);
  16. }
  17. bool ex_handler_default(const struct exception_table_entry *fixup,
  18. struct pt_regs *regs, int trapnr)
  19. {
  20. regs->ip = ex_fixup_addr(fixup);
  21. return true;
  22. }
  23. EXPORT_SYMBOL(ex_handler_default);
  24. bool ex_handler_fault(const struct exception_table_entry *fixup,
  25. struct pt_regs *regs, int trapnr)
  26. {
  27. regs->ip = ex_fixup_addr(fixup);
  28. regs->ax = trapnr;
  29. return true;
  30. }
  31. EXPORT_SYMBOL_GPL(ex_handler_fault);
  32. bool ex_handler_ext(const struct exception_table_entry *fixup,
  33. struct pt_regs *regs, int trapnr)
  34. {
  35. /* Special hack for uaccess_err */
  36. current->thread.uaccess_err = 1;
  37. regs->ip = ex_fixup_addr(fixup);
  38. return true;
  39. }
  40. EXPORT_SYMBOL(ex_handler_ext);
  41. bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
  42. struct pt_regs *regs, int trapnr)
  43. {
  44. if (pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pF)\n",
  45. (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
  46. show_stack_regs(regs);
  47. /* Pretend that the read succeeded and returned 0. */
  48. regs->ip = ex_fixup_addr(fixup);
  49. regs->ax = 0;
  50. regs->dx = 0;
  51. return true;
  52. }
  53. EXPORT_SYMBOL(ex_handler_rdmsr_unsafe);
  54. bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup,
  55. struct pt_regs *regs, int trapnr)
  56. {
  57. if (pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pF)\n",
  58. (unsigned int)regs->cx, (unsigned int)regs->dx,
  59. (unsigned int)regs->ax, regs->ip, (void *)regs->ip))
  60. show_stack_regs(regs);
  61. /* Pretend that the write succeeded. */
  62. regs->ip = ex_fixup_addr(fixup);
  63. return true;
  64. }
  65. EXPORT_SYMBOL(ex_handler_wrmsr_unsafe);
  66. bool ex_handler_clear_fs(const struct exception_table_entry *fixup,
  67. struct pt_regs *regs, int trapnr)
  68. {
  69. if (static_cpu_has(X86_BUG_NULL_SEG))
  70. asm volatile ("mov %0, %%fs" : : "rm" (__USER_DS));
  71. asm volatile ("mov %0, %%fs" : : "rm" (0));
  72. return ex_handler_default(fixup, regs, trapnr);
  73. }
  74. EXPORT_SYMBOL(ex_handler_clear_fs);
  75. bool ex_has_fault_handler(unsigned long ip)
  76. {
  77. const struct exception_table_entry *e;
  78. ex_handler_t handler;
  79. e = search_exception_tables(ip);
  80. if (!e)
  81. return false;
  82. handler = ex_fixup_handler(e);
  83. return handler == ex_handler_fault;
  84. }
  85. int fixup_exception(struct pt_regs *regs, int trapnr)
  86. {
  87. const struct exception_table_entry *e;
  88. ex_handler_t handler;
  89. #ifdef CONFIG_PNPBIOS
  90. if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
  91. extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
  92. extern u32 pnp_bios_is_utter_crap;
  93. pnp_bios_is_utter_crap = 1;
  94. printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
  95. __asm__ volatile(
  96. "movl %0, %%esp\n\t"
  97. "jmp *%1\n\t"
  98. : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
  99. panic("do_trap: can't hit this");
  100. }
  101. #endif
  102. e = search_exception_tables(regs->ip);
  103. if (!e)
  104. return 0;
  105. handler = ex_fixup_handler(e);
  106. return handler(e, regs, trapnr);
  107. }
  108. extern unsigned int early_recursion_flag;
  109. /* Restricted version used during very early boot */
  110. void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
  111. {
  112. /* Ignore early NMIs. */
  113. if (trapnr == X86_TRAP_NMI)
  114. return;
  115. if (early_recursion_flag > 2)
  116. goto halt_loop;
  117. /*
  118. * Old CPUs leave the high bits of CS on the stack
  119. * undefined. I'm not sure which CPUs do this, but at least
  120. * the 486 DX works this way.
  121. */
  122. if ((regs->cs & 0xFFFF) != __KERNEL_CS)
  123. goto fail;
  124. /*
  125. * The full exception fixup machinery is available as soon as
  126. * the early IDT is loaded. This means that it is the
  127. * responsibility of extable users to either function correctly
  128. * when handlers are invoked early or to simply avoid causing
  129. * exceptions before they're ready to handle them.
  130. *
  131. * This is better than filtering which handlers can be used,
  132. * because refusing to call a handler here is guaranteed to
  133. * result in a hard-to-debug panic.
  134. *
  135. * Keep in mind that not all vectors actually get here. Early
  136. * fage faults, for example, are special.
  137. */
  138. if (fixup_exception(regs, trapnr))
  139. return;
  140. fail:
  141. early_printk("PANIC: early exception 0x%02x IP %lx:%lx error %lx cr2 0x%lx\n",
  142. (unsigned)trapnr, (unsigned long)regs->cs, regs->ip,
  143. regs->orig_ax, read_cr2());
  144. show_regs(regs);
  145. halt_loop:
  146. while (true)
  147. halt();
  148. }