LCOV - code coverage report
Current view: top level - arch/x86/mm - extable.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 28 68 41.2 %
Date: 2022-03-28 15:32:58 Functions: 5 11 45.5 %
Branches: 8 33 24.2 %

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

Generated by: LCOV version 1.14