LCOV - code coverage report
Current view: top level - arch/x86/mm - extable.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 23 74 31.1 %
Date: 2021-04-22 12:43:58 Functions: 4 11 36.4 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0-only
       2             : #include <linux/extable.h>
       3             : #include <linux/uaccess.h>
       4             : #include <linux/sched/debug.h>
       5             : #include <xen/xen.h>
       6             : 
       7             : #include <asm/fpu/internal.h>
       8             : #include <asm/sev-es.h>
       9             : #include <asm/traps.h>
      10             : #include <asm/kdebug.h>
      11             : 
      12             : typedef bool (*ex_handler_t)(const struct exception_table_entry *,
      13             :                             struct pt_regs *, int, unsigned long,
      14             :                             unsigned long);
      15             : 
      16             : static inline unsigned long
      17         721 : ex_fixup_addr(const struct exception_table_entry *x)
      18             : {
      19         721 :         return (unsigned long)&x->fixup + x->fixup;
      20             : }
      21             : static inline ex_handler_t
      22         721 : ex_fixup_handler(const struct exception_table_entry *x)
      23             : {
      24         721 :         return (ex_handler_t)((unsigned long)&x->handler + x->handler);
      25             : }
      26             : 
      27         202 : __visible bool ex_handler_default(const struct exception_table_entry *fixup,
      28             :                                   struct pt_regs *regs, int trapnr,
      29             :                                   unsigned long error_code,
      30             :                                   unsigned long fault_addr)
      31             : {
      32         202 :         regs->ip = ex_fixup_addr(fixup);
      33         202 :         return true;
      34             : }
      35             : EXPORT_SYMBOL(ex_handler_default);
      36             : 
      37           0 : __visible bool ex_handler_fault(const struct exception_table_entry *fixup,
      38             :                                 struct pt_regs *regs, int trapnr,
      39             :                                 unsigned long error_code,
      40             :                                 unsigned long fault_addr)
      41             : {
      42           0 :         regs->ip = ex_fixup_addr(fixup);
      43           0 :         regs->ax = trapnr;
      44           0 :         return true;
      45             : }
      46             : EXPORT_SYMBOL_GPL(ex_handler_fault);
      47             : 
      48             : /*
      49             :  * Handler for when we fail to restore a task's FPU state.  We should never get
      50             :  * here because the FPU state of a task using the FPU (task->thread.fpu.state)
      51             :  * should always be valid.  However, past bugs have allowed userspace to set
      52             :  * reserved bits in the XSAVE area using PTRACE_SETREGSET or sys_rt_sigreturn().
      53             :  * These caused XRSTOR to fail when switching to the task, leaking the FPU
      54             :  * registers of the task previously executing on the CPU.  Mitigate this class
      55             :  * of vulnerability by restoring from the initial state (essentially, zeroing
      56             :  * out all the FPU registers) if we can't restore from the task's FPU state.
      57             :  */
      58           0 : __visible bool ex_handler_fprestore(const struct exception_table_entry *fixup,
      59             :                                     struct pt_regs *regs, int trapnr,
      60             :                                     unsigned long error_code,
      61             :                                     unsigned long fault_addr)
      62             : {
      63           0 :         regs->ip = ex_fixup_addr(fixup);
      64             : 
      65           0 :         WARN_ONCE(1, "Bad FPU state detected at %pB, reinitializing FPU registers.",
      66             :                   (void *)instruction_pointer(regs));
      67             : 
      68           0 :         __copy_kernel_to_fpregs(&init_fpstate, -1);
      69           0 :         return true;
      70             : }
      71             : EXPORT_SYMBOL_GPL(ex_handler_fprestore);
      72             : 
      73         517 : __visible bool ex_handler_uaccess(const struct exception_table_entry *fixup,
      74             :                                   struct pt_regs *regs, int trapnr,
      75             :                                   unsigned long error_code,
      76             :                                   unsigned long fault_addr)
      77             : {
      78         517 :         WARN_ONCE(trapnr == X86_TRAP_GP, "General protection fault in user access. Non-canonical address?");
      79         517 :         regs->ip = ex_fixup_addr(fixup);
      80         517 :         return true;
      81             : }
      82             : EXPORT_SYMBOL(ex_handler_uaccess);
      83             : 
      84           2 : __visible bool ex_handler_copy(const struct exception_table_entry *fixup,
      85             :                                struct pt_regs *regs, int trapnr,
      86             :                                unsigned long error_code,
      87             :                                unsigned long fault_addr)
      88             : {
      89           2 :         WARN_ONCE(trapnr == X86_TRAP_GP, "General protection fault in user access. Non-canonical address?");
      90           2 :         regs->ip = ex_fixup_addr(fixup);
      91           2 :         regs->ax = trapnr;
      92           2 :         return true;
      93             : }
      94             : EXPORT_SYMBOL(ex_handler_copy);
      95             : 
      96           0 : __visible bool ex_handler_rdmsr_unsafe(const struct exception_table_entry *fixup,
      97             :                                        struct pt_regs *regs, int trapnr,
      98             :                                        unsigned long error_code,
      99             :                                        unsigned long fault_addr)
     100             : {
     101           0 :         if (pr_warn_once("unchecked MSR access error: RDMSR from 0x%x at rIP: 0x%lx (%pS)\n",
     102             :                          (unsigned int)regs->cx, regs->ip, (void *)regs->ip))
     103           0 :                 show_stack_regs(regs);
     104             : 
     105             :         /* Pretend that the read succeeded and returned 0. */
     106           0 :         regs->ip = ex_fixup_addr(fixup);
     107           0 :         regs->ax = 0;
     108           0 :         regs->dx = 0;
     109           0 :         return true;
     110             : }
     111             : EXPORT_SYMBOL(ex_handler_rdmsr_unsafe);
     112             : 
     113           0 : __visible bool ex_handler_wrmsr_unsafe(const struct exception_table_entry *fixup,
     114             :                                        struct pt_regs *regs, int trapnr,
     115             :                                        unsigned long error_code,
     116             :                                        unsigned long fault_addr)
     117             : {
     118           0 :         if (pr_warn_once("unchecked MSR access error: WRMSR to 0x%x (tried to write 0x%08x%08x) at rIP: 0x%lx (%pS)\n",
     119             :                          (unsigned int)regs->cx, (unsigned int)regs->dx,
     120             :                          (unsigned int)regs->ax,  regs->ip, (void *)regs->ip))
     121           0 :                 show_stack_regs(regs);
     122             : 
     123             :         /* Pretend that the write succeeded. */
     124           0 :         regs->ip = ex_fixup_addr(fixup);
     125           0 :         return true;
     126             : }
     127             : EXPORT_SYMBOL(ex_handler_wrmsr_unsafe);
     128             : 
     129           0 : __visible bool ex_handler_clear_fs(const struct exception_table_entry *fixup,
     130             :                                    struct pt_regs *regs, int trapnr,
     131             :                                    unsigned long error_code,
     132             :                                    unsigned long fault_addr)
     133             : {
     134           0 :         if (static_cpu_has(X86_BUG_NULL_SEG))
     135           0 :                 asm volatile ("mov %0, %%fs" : : "rm" (__USER_DS));
     136           0 :         asm volatile ("mov %0, %%fs" : : "rm" (0));
     137           0 :         return ex_handler_default(fixup, regs, trapnr, error_code, fault_addr);
     138             : }
     139             : EXPORT_SYMBOL(ex_handler_clear_fs);
     140             : 
     141           0 : enum handler_type ex_get_fault_handler_type(unsigned long ip)
     142             : {
     143           0 :         const struct exception_table_entry *e;
     144           0 :         ex_handler_t handler;
     145             : 
     146           0 :         e = search_exception_tables(ip);
     147           0 :         if (!e)
     148             :                 return EX_HANDLER_NONE;
     149           0 :         handler = ex_fixup_handler(e);
     150           0 :         if (handler == ex_handler_fault)
     151             :                 return EX_HANDLER_FAULT;
     152           0 :         else if (handler == ex_handler_uaccess || handler == ex_handler_copy)
     153             :                 return EX_HANDLER_UACCESS;
     154             :         else
     155           0 :                 return EX_HANDLER_OTHER;
     156             : }
     157             : 
     158         721 : int fixup_exception(struct pt_regs *regs, int trapnr, unsigned long error_code,
     159             :                     unsigned long fault_addr)
     160             : {
     161         721 :         const struct exception_table_entry *e;
     162         721 :         ex_handler_t handler;
     163             : 
     164             : #ifdef CONFIG_PNPBIOS
     165             :         if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) {
     166             :                 extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp;
     167             :                 extern u32 pnp_bios_is_utter_crap;
     168             :                 pnp_bios_is_utter_crap = 1;
     169             :                 printk(KERN_CRIT "PNPBIOS fault.. attempting recovery.\n");
     170             :                 __asm__ volatile(
     171             :                         "movl %0, %%esp\n\t"
     172             :                         "jmp *%1\n\t"
     173             :                         : : "g" (pnp_bios_fault_esp), "g" (pnp_bios_fault_eip));
     174             :                 panic("do_trap: can't hit this");
     175             :         }
     176             : #endif
     177             : 
     178         721 :         e = search_exception_tables(regs->ip);
     179         721 :         if (!e)
     180             :                 return 0;
     181             : 
     182         721 :         handler = ex_fixup_handler(e);
     183         721 :         return handler(e, regs, trapnr, error_code, fault_addr);
     184             : }
     185             : 
     186             : extern unsigned int early_recursion_flag;
     187             : 
     188             : /* Restricted version used during very early boot */
     189           0 : void __init early_fixup_exception(struct pt_regs *regs, int trapnr)
     190             : {
     191             :         /* Ignore early NMIs. */
     192           0 :         if (trapnr == X86_TRAP_NMI)
     193             :                 return;
     194             : 
     195           0 :         if (early_recursion_flag > 2)
     196           0 :                 goto halt_loop;
     197             : 
     198             :         /*
     199             :          * Old CPUs leave the high bits of CS on the stack
     200             :          * undefined.  I'm not sure which CPUs do this, but at least
     201             :          * the 486 DX works this way.
     202             :          * Xen pv domains are not using the default __KERNEL_CS.
     203             :          */
     204           0 :         if (!xen_pv_domain() && regs->cs != __KERNEL_CS)
     205           0 :                 goto fail;
     206             : 
     207             :         /*
     208             :          * The full exception fixup machinery is available as soon as
     209             :          * the early IDT is loaded.  This means that it is the
     210             :          * responsibility of extable users to either function correctly
     211             :          * when handlers are invoked early or to simply avoid causing
     212             :          * exceptions before they're ready to handle them.
     213             :          *
     214             :          * This is better than filtering which handlers can be used,
     215             :          * because refusing to call a handler here is guaranteed to
     216             :          * result in a hard-to-debug panic.
     217             :          *
     218             :          * Keep in mind that not all vectors actually get here.  Early
     219             :          * page faults, for example, are special.
     220             :          */
     221           0 :         if (fixup_exception(regs, trapnr, regs->orig_ax, 0))
     222             :                 return;
     223             : 
     224           0 :         if (trapnr == X86_TRAP_UD) {
     225           0 :                 if (report_bug(regs->ip, regs) == BUG_TRAP_TYPE_WARN) {
     226             :                         /* Skip the ud2. */
     227           0 :                         regs->ip += LEN_UD2;
     228           0 :                         return;
     229             :                 }
     230             : 
     231             :                 /*
     232             :                  * If this was a BUG and report_bug returns or if this
     233             :                  * was just a normal #UD, we want to continue onward and
     234             :                  * crash.
     235             :                  */
     236             :         }
     237             : 
     238           0 : fail:
     239           0 :         early_printk("PANIC: early exception 0x%02x IP %lx:%lx error %lx cr2 0x%lx\n",
     240             :                      (unsigned)trapnr, (unsigned long)regs->cs, regs->ip,
     241             :                      regs->orig_ax, read_cr2());
     242             : 
     243           0 :         show_regs(regs);
     244             : 
     245             : halt_loop:
     246           0 :         while (true)
     247           0 :                 halt();
     248             : }

Generated by: LCOV version 1.14