LCOV - code coverage report
Current view: top level - arch/um/kernel - trap.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 122 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 9 0.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : /*
       3             :  * Copyright (C) 2000 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
       4             :  */
       5             : 
       6             : #include <linux/mm.h>
       7             : #include <linux/sched/signal.h>
       8             : #include <linux/hardirq.h>
       9             : #include <linux/module.h>
      10             : #include <linux/uaccess.h>
      11             : #include <linux/sched/debug.h>
      12             : #include <asm/current.h>
      13             : #include <asm/tlbflush.h>
      14             : #include <arch.h>
      15             : #include <as-layout.h>
      16             : #include <kern_util.h>
      17             : #include <os.h>
      18             : #include <skas.h>
      19             : 
      20             : /*
      21             :  * Note this is constrained to return 0, -EFAULT, -EACCES, -ENOMEM by
      22             :  * segv().
      23             :  */
      24           0 : int handle_page_fault(unsigned long address, unsigned long ip,
      25             :                       int is_write, int is_user, int *code_out)
      26             : {
      27           0 :         struct mm_struct *mm = current->mm;
      28             :         struct vm_area_struct *vma;
      29             :         pmd_t *pmd;
      30             :         pte_t *pte;
      31           0 :         int err = -EFAULT;
      32           0 :         unsigned int flags = FAULT_FLAG_DEFAULT;
      33             : 
      34           0 :         *code_out = SEGV_MAPERR;
      35             : 
      36             :         /*
      37             :          * If the fault was with pagefaults disabled, don't take the fault, just
      38             :          * fail.
      39             :          */
      40           0 :         if (faulthandler_disabled())
      41             :                 goto out_nosemaphore;
      42             : 
      43           0 :         if (is_user)
      44           0 :                 flags |= FAULT_FLAG_USER;
      45             : retry:
      46           0 :         mmap_read_lock(mm);
      47           0 :         vma = find_vma(mm, address);
      48           0 :         if (!vma)
      49             :                 goto out;
      50           0 :         else if (vma->vm_start <= address)
      51             :                 goto good_area;
      52           0 :         else if (!(vma->vm_flags & VM_GROWSDOWN))
      53             :                 goto out;
      54           0 :         else if (is_user && !ARCH_IS_STACKGROW(address))
      55             :                 goto out;
      56           0 :         else if (expand_stack(vma, address))
      57             :                 goto out;
      58             : 
      59             : good_area:
      60           0 :         *code_out = SEGV_ACCERR;
      61           0 :         if (is_write) {
      62           0 :                 if (!(vma->vm_flags & VM_WRITE))
      63             :                         goto out;
      64           0 :                 flags |= FAULT_FLAG_WRITE;
      65             :         } else {
      66             :                 /* Don't require VM_READ|VM_EXEC for write faults! */
      67           0 :                 if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
      68             :                         goto out;
      69             :         }
      70             : 
      71             :         do {
      72             :                 vm_fault_t fault;
      73             : 
      74           0 :                 fault = handle_mm_fault(vma, address, flags, NULL);
      75             : 
      76           0 :                 if ((fault & VM_FAULT_RETRY) && fatal_signal_pending(current))
      77             :                         goto out_nosemaphore;
      78             : 
      79           0 :                 if (unlikely(fault & VM_FAULT_ERROR)) {
      80           0 :                         if (fault & VM_FAULT_OOM) {
      81             :                                 goto out_of_memory;
      82           0 :                         } else if (fault & VM_FAULT_SIGSEGV) {
      83             :                                 goto out;
      84           0 :                         } else if (fault & VM_FAULT_SIGBUS) {
      85             :                                 err = -EACCES;
      86             :                                 goto out;
      87             :                         }
      88           0 :                         BUG();
      89             :                 }
      90           0 :                 if (fault & VM_FAULT_RETRY) {
      91           0 :                         flags |= FAULT_FLAG_TRIED;
      92             : 
      93           0 :                         goto retry;
      94             :                 }
      95             : 
      96           0 :                 pmd = pmd_off(mm, address);
      97           0 :                 pte = pte_offset_kernel(pmd, address);
      98           0 :         } while (!pte_present(*pte));
      99           0 :         err = 0;
     100             :         /*
     101             :          * The below warning was added in place of
     102             :          *      pte_mkyoung(); if (is_write) pte_mkdirty();
     103             :          * If it's triggered, we'd see normally a hang here (a clean pte is
     104             :          * marked read-only to emulate the dirty bit).
     105             :          * However, the generic code can mark a PTE writable but clean on a
     106             :          * concurrent read fault, triggering this harmlessly. So comment it out.
     107             :          */
     108             : #if 0
     109             :         WARN_ON(!pte_young(*pte) || (is_write && !pte_dirty(*pte)));
     110             : #endif
     111           0 :         flush_tlb_page(vma, address);
     112             : out:
     113             :         mmap_read_unlock(mm);
     114             : out_nosemaphore:
     115             :         return err;
     116             : 
     117             : out_of_memory:
     118             :         /*
     119             :          * We ran out of memory, call the OOM killer, and return the userspace
     120             :          * (which will retry the fault, or kill us if we got oom-killed).
     121             :          */
     122           0 :         mmap_read_unlock(mm);
     123           0 :         if (!is_user)
     124             :                 goto out_nosemaphore;
     125           0 :         pagefault_out_of_memory();
     126           0 :         return 0;
     127             : }
     128             : 
     129           0 : static void show_segv_info(struct uml_pt_regs *regs)
     130             : {
     131           0 :         struct task_struct *tsk = current;
     132           0 :         struct faultinfo *fi = UPT_FAULTINFO(regs);
     133             : 
     134           0 :         if (!unhandled_signal(tsk, SIGSEGV))
     135             :                 return;
     136             : 
     137           0 :         if (!printk_ratelimit())
     138             :                 return;
     139             : 
     140           0 :         printk("%s%s[%d]: segfault at %lx ip %px sp %px error %x",
     141             :                 task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG,
     142             :                 tsk->comm, task_pid_nr(tsk), FAULT_ADDRESS(*fi),
     143             :                 (void *)UPT_IP(regs), (void *)UPT_SP(regs),
     144             :                 fi->error_code);
     145             : 
     146           0 :         print_vma_addr(KERN_CONT " in ", UPT_IP(regs));
     147           0 :         printk(KERN_CONT "\n");
     148             : }
     149             : 
     150           0 : static void bad_segv(struct faultinfo fi, unsigned long ip)
     151             : {
     152           0 :         current->thread.arch.faultinfo = fi;
     153           0 :         force_sig_fault(SIGSEGV, SEGV_ACCERR, (void __user *) FAULT_ADDRESS(fi));
     154           0 : }
     155             : 
     156           0 : void fatal_sigsegv(void)
     157             : {
     158           0 :         force_fatal_sig(SIGSEGV);
     159           0 :         do_signal(&current->thread.regs);
     160             :         /*
     161             :          * This is to tell gcc that we're not returning - do_signal
     162             :          * can, in general, return, but in this case, it's not, since
     163             :          * we just got a fatal SIGSEGV queued.
     164             :          */
     165           0 :         os_dump_core();
     166             : }
     167             : 
     168             : /**
     169             :  * segv_handler() - the SIGSEGV handler
     170             :  * @sig:        the signal number
     171             :  * @unused_si:  the signal info struct; unused in this handler
     172             :  * @regs:       the ptrace register information
     173             :  *
     174             :  * The handler first extracts the faultinfo from the UML ptrace regs struct.
     175             :  * If the userfault did not happen in an UML userspace process, bad_segv is called.
     176             :  * Otherwise the signal did happen in a cloned userspace process, handle it.
     177             :  */
     178           0 : void segv_handler(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
     179             : {
     180           0 :         struct faultinfo * fi = UPT_FAULTINFO(regs);
     181             : 
     182           0 :         if (UPT_IS_USER(regs) && !SEGV_IS_FIXABLE(fi)) {
     183           0 :                 show_segv_info(regs);
     184           0 :                 bad_segv(*fi, UPT_IP(regs));
     185           0 :                 return;
     186             :         }
     187           0 :         segv(*fi, UPT_IP(regs), UPT_IS_USER(regs), regs);
     188             : }
     189             : 
     190             : /*
     191             :  * We give a *copy* of the faultinfo in the regs to segv.
     192             :  * This must be done, since nesting SEGVs could overwrite
     193             :  * the info in the regs. A pointer to the info then would
     194             :  * give us bad data!
     195             :  */
     196           0 : unsigned long segv(struct faultinfo fi, unsigned long ip, int is_user,
     197             :                    struct uml_pt_regs *regs)
     198             : {
     199             :         jmp_buf *catcher;
     200             :         int si_code;
     201             :         int err;
     202           0 :         int is_write = FAULT_WRITE(fi);
     203           0 :         unsigned long address = FAULT_ADDRESS(fi);
     204             : 
     205           0 :         if (!is_user && regs)
     206           0 :                 current->thread.segv_regs = container_of(regs, struct pt_regs, regs);
     207             : 
     208           0 :         if (!is_user && (address >= start_vm) && (address < end_vm)) {
     209           0 :                 flush_tlb_kernel_vm();
     210           0 :                 goto out;
     211             :         }
     212           0 :         else if (current->mm == NULL) {
     213           0 :                 show_regs(container_of(regs, struct pt_regs, regs));
     214           0 :                 panic("Segfault with no mm");
     215             :         }
     216           0 :         else if (!is_user && address > PAGE_SIZE && address < TASK_SIZE) {
     217           0 :                 show_regs(container_of(regs, struct pt_regs, regs));
     218           0 :                 panic("Kernel tried to access user memory at addr 0x%lx, ip 0x%lx",
     219             :                        address, ip);
     220             :         }
     221             : 
     222           0 :         if (SEGV_IS_FIXABLE(&fi))
     223           0 :                 err = handle_page_fault(address, ip, is_write, is_user,
     224             :                                         &si_code);
     225             :         else {
     226             :                 err = -EFAULT;
     227             :                 /*
     228             :                  * A thread accessed NULL, we get a fault, but CR2 is invalid.
     229             :                  * This code is used in __do_copy_from_user() of TT mode.
     230             :                  * XXX tt mode is gone, so maybe this isn't needed any more
     231             :                  */
     232             :                 address = 0;
     233             :         }
     234             : 
     235           0 :         catcher = current->thread.fault_catcher;
     236           0 :         if (!err)
     237             :                 goto out;
     238           0 :         else if (catcher != NULL) {
     239           0 :                 current->thread.fault_addr = (void *) address;
     240           0 :                 UML_LONGJMP(catcher, 1);
     241             :         }
     242           0 :         else if (current->thread.fault_addr != NULL)
     243           0 :                 panic("fault_addr set but no fault catcher");
     244           0 :         else if (!is_user && arch_fixup(ip, regs))
     245             :                 goto out;
     246             : 
     247           0 :         if (!is_user) {
     248           0 :                 show_regs(container_of(regs, struct pt_regs, regs));
     249           0 :                 panic("Kernel mode fault at addr 0x%lx, ip 0x%lx",
     250             :                       address, ip);
     251             :         }
     252             : 
     253           0 :         show_segv_info(regs);
     254             : 
     255           0 :         if (err == -EACCES) {
     256           0 :                 current->thread.arch.faultinfo = fi;
     257           0 :                 force_sig_fault(SIGBUS, BUS_ADRERR, (void __user *)address);
     258             :         } else {
     259           0 :                 BUG_ON(err != -EFAULT);
     260           0 :                 current->thread.arch.faultinfo = fi;
     261           0 :                 force_sig_fault(SIGSEGV, si_code, (void __user *) address);
     262             :         }
     263             : 
     264             : out:
     265           0 :         if (regs)
     266           0 :                 current->thread.segv_regs = NULL;
     267             : 
     268           0 :         return 0;
     269             : }
     270             : 
     271           0 : void relay_signal(int sig, struct siginfo *si, struct uml_pt_regs *regs)
     272             : {
     273             :         int code, err;
     274           0 :         if (!UPT_IS_USER(regs)) {
     275           0 :                 if (sig == SIGBUS)
     276           0 :                         printk(KERN_ERR "Bus error - the host /dev/shm or /tmp "
     277             :                                "mount likely just ran out of space\n");
     278           0 :                 panic("Kernel mode signal %d", sig);
     279             :         }
     280             : 
     281           0 :         arch_examine_signal(sig, regs);
     282             : 
     283             :         /* Is the signal layout for the signal known?
     284             :          * Signal data must be scrubbed to prevent information leaks.
     285             :          */
     286           0 :         code = si->si_code;
     287           0 :         err = si->si_errno;
     288           0 :         if ((err == 0) && (siginfo_layout(sig, code) == SIL_FAULT)) {
     289           0 :                 struct faultinfo *fi = UPT_FAULTINFO(regs);
     290           0 :                 current->thread.arch.faultinfo = *fi;
     291           0 :                 force_sig_fault(sig, code, (void __user *)FAULT_ADDRESS(*fi));
     292             :         } else {
     293           0 :                 printk(KERN_ERR "Attempted to relay unknown signal %d (si_code = %d) with errno %d\n",
     294             :                        sig, code, err);
     295           0 :                 force_sig(sig);
     296             :         }
     297           0 : }
     298             : 
     299           0 : void bus_handler(int sig, struct siginfo *si, struct uml_pt_regs *regs)
     300             : {
     301           0 :         if (current->thread.fault_catcher != NULL)
     302           0 :                 UML_LONGJMP(current->thread.fault_catcher, 1);
     303             :         else
     304           0 :                 relay_signal(sig, si, regs);
     305           0 : }
     306             : 
     307           0 : void winch(int sig, struct siginfo *unused_si, struct uml_pt_regs *regs)
     308             : {
     309           0 :         do_IRQ(WINCH_IRQ, regs);
     310           0 : }

Generated by: LCOV version 1.14