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

Generated by: LCOV version 1.14