extable.c 4.6 KB

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