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

Generated by: LCOV version 1.14