From owner-svn-src-all@freebsd.org Fri Oct 4 12:18:06 2019 Return-Path: Delivered-To: svn-src-all@mailman.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.nyi.freebsd.org (Postfix) with ESMTP id ECE1A12D464; Fri, 4 Oct 2019 12:18:06 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 46l8666kkLz4K5G; Fri, 4 Oct 2019 12:18:06 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id C6DA1241E1; Fri, 4 Oct 2019 12:18:06 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x94CI6JW025856; Fri, 4 Oct 2019 12:18:06 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x94CI4Un025841; Fri, 4 Oct 2019 12:18:04 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201910041218.x94CI4Un025841@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Fri, 4 Oct 2019 12:18:03 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org Subject: svn commit: r353102 - in stable/12/sys: amd64/amd64 amd64/vmm arm/arm arm64/arm64 i386/i386 kern mips/mips powerpc/powerpc riscv/riscv sparc64/sparc64 sys vm X-SVN-Group: stable-12 X-SVN-Commit-Author: kib X-SVN-Commit-Paths: in stable/12/sys: amd64/amd64 amd64/vmm arm/arm arm64/arm64 i386/i386 kern mips/mips powerpc/powerpc riscv/riscv sparc64/sparc64 sys vm X-SVN-Commit-Revision: 353102 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 04 Oct 2019 12:18:07 -0000 Author: kib Date: Fri Oct 4 12:18:03 2019 New Revision: 353102 URL: https://svnweb.freebsd.org/changeset/base/353102 Log: MFC r352807: Improve MD page fault handlers. PR: 211924 Modified: stable/12/sys/amd64/amd64/trap.c stable/12/sys/amd64/vmm/vmm.c stable/12/sys/arm/arm/trap-v4.c stable/12/sys/arm/arm/trap-v6.c stable/12/sys/arm64/arm64/trap.c stable/12/sys/i386/i386/trap.c stable/12/sys/kern/sys_process.c stable/12/sys/mips/mips/trap.c stable/12/sys/powerpc/powerpc/trap.c stable/12/sys/riscv/riscv/trap.c stable/12/sys/sparc64/sparc64/trap.c stable/12/sys/sys/signal.h stable/12/sys/vm/vm_extern.h stable/12/sys/vm/vm_fault.c stable/12/sys/vm/vm_map.c stable/12/sys/vm/vm_param.h Directory Properties: stable/12/ (props changed) Modified: stable/12/sys/amd64/amd64/trap.c ============================================================================== --- stable/12/sys/amd64/amd64/trap.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/amd64/amd64/trap.c Fri Oct 4 12:18:03 2019 (r353102) @@ -111,7 +111,7 @@ void __noinline trap(struct trapframe *frame); void trap_check(struct trapframe *frame); void dblfault_handler(struct trapframe *frame); -static int trap_pfault(struct trapframe *, int); +static int trap_pfault(struct trapframe *, bool, int *, int *); static void trap_fatal(struct trapframe *, vm_offset_t); #ifdef KDTRACE_HOOKS static bool trap_user_dtrace(struct trapframe *, @@ -155,10 +155,6 @@ static const char *const trap_msg[] = { [T_DTRACE_RET] = "DTrace pid return trap", }; -static int prot_fault_translation; -SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RWTUN, - &prot_fault_translation, 0, - "Select signal to deliver on protection fault"); static int uprintf_signal; SYSCTL_INT(_machdep, OID_AUTO, uprintf_signal, CTLFLAG_RWTUN, &uprintf_signal, 0, @@ -192,14 +188,11 @@ trap(struct trapframe *frame) struct thread *td; struct proc *p; register_t addr, dr6; - int signo, ucode; + int pf, signo, ucode; u_int type; td = curthread; p = td->td_proc; - signo = 0; - ucode = 0; - addr = 0; dr6 = 0; VM_CNT_INC(v_trap); @@ -345,47 +338,18 @@ trap(struct trapframe *frame) case T_PAGEFLT: /* page fault */ /* - * Emulator can take care about this trap? + * Can emulator handle this trap? */ if (*p->p_sysent->sv_trap != NULL && (*p->p_sysent->sv_trap)(td) == 0) return; - addr = frame->tf_addr; - signo = trap_pfault(frame, TRUE); - if (signo == -1) + pf = trap_pfault(frame, true, &signo, &ucode); + if (pf == -1) return; - if (signo == 0) + if (pf == 0) goto userret; - if (signo == SIGSEGV) { - ucode = SEGV_MAPERR; - } else if (prot_fault_translation == 0) { - /* - * Autodetect. This check also covers - * the images without the ABI-tag ELF - * note. - */ - if (SV_CURPROC_ABI() == SV_ABI_FREEBSD && - p->p_osrel >= P_OSREL_SIGSEGV) { - signo = SIGSEGV; - ucode = SEGV_ACCERR; - } else { - signo = SIGBUS; - ucode = T_PAGEFLT; - } - } else if (prot_fault_translation == 1) { - /* - * Always compat mode. - */ - signo = SIGBUS; - ucode = T_PAGEFLT; - } else { - /* - * Always SIGSEGV mode. - */ - signo = SIGSEGV; - ucode = SEGV_ACCERR; - } + addr = frame->tf_addr; break; case T_DIVIDE: /* integer divide fault */ @@ -440,7 +404,7 @@ trap(struct trapframe *frame) ("kernel trap doesn't have ucred")); switch (type) { case T_PAGEFLT: /* page fault */ - (void) trap_pfault(frame, FALSE); + (void)trap_pfault(frame, false, NULL, NULL); return; case T_DNA: @@ -712,17 +676,29 @@ trap_is_pti(struct trapframe *frame) (PCPU_GET(curpmap)->pm_cr3 & ~CR3_PCID_MASK)); } +/* + * Handle all details of a page fault. + * Returns: + * -1 if this fault was fatal, typically from kernel mode + * (cannot happen, but we need to return something). + * 0 if this fault was handled by updating either the user or kernel + * page table, execution can continue. + * 1 if this fault was from usermode and it was not handled, a synchronous + * signal should be delivered to the thread. *signo returns the signal + * number, *ucode gives si_code. + */ static int -trap_pfault(struct trapframe *frame, int usermode) +trap_pfault(struct trapframe *frame, bool usermode, int *signo, int *ucode) { struct thread *td; struct proc *p; vm_map_t map; - vm_offset_t va; + vm_offset_t eva; int rv; vm_prot_t ftype; - vm_offset_t eva; + MPASS(!usermode || (signo != NULL && ucode != NULL)); + td = curthread; p = td->td_proc; eva = frame->tf_addr; @@ -771,13 +747,15 @@ trap_pfault(struct trapframe *frame, int usermode) return (-1); } } - va = trunc_page(eva); - if (va >= VM_MIN_KERNEL_ADDRESS) { + if (eva >= VM_MIN_KERNEL_ADDRESS) { /* * Don't allow user-mode faults in kernel address space. */ - if (usermode) - return (SIGSEGV); + if (usermode) { + *signo = SIGSEGV; + *ucode = SEGV_MAPERR; + return (1); + } map = kernel_map; } else { @@ -819,7 +797,11 @@ trap_pfault(struct trapframe *frame, int usermode) trap_fatal(frame, eva); return (-1); } - rv = KERN_PROTECTION_FAILURE; + if (usermode) { + *signo = SIGSEGV; + *ucode = SEGV_PKUERR; + return (1); + } goto after_vmfault; } @@ -843,7 +825,7 @@ trap_pfault(struct trapframe *frame, int usermode) ftype = VM_PROT_READ; /* Fault in the page. */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + rv = vm_fault_trap(map, eva, ftype, VM_FAULT_NORMAL, signo, ucode); if (rv == KERN_SUCCESS) { #ifdef HWPMC_HOOKS if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { @@ -858,17 +840,17 @@ trap_pfault(struct trapframe *frame, int usermode) #endif return (0); } + + if (usermode) + return (1); after_vmfault: - if (!usermode) { - if (td->td_intr_nesting_level == 0 && - curpcb->pcb_onfault != NULL) { - frame->tf_rip = (long)curpcb->pcb_onfault; - return (0); - } - trap_fatal(frame, eva); - return (-1); + if (td->td_intr_nesting_level == 0 && + curpcb->pcb_onfault != NULL) { + frame->tf_rip = (long)curpcb->pcb_onfault; + return (0); } - return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); + trap_fatal(frame, eva); + return (-1); } static void Modified: stable/12/sys/amd64/vmm/vmm.c ============================================================================== --- stable/12/sys/amd64/vmm/vmm.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/amd64/vmm/vmm.c Fri Oct 4 12:18:03 2019 (r353102) @@ -1412,7 +1412,7 @@ vm_handle_paging(struct vm *vm, int vcpuid, bool *retu } map = &vm->vmspace->vm_map; - rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL); + rv = vm_fault(map, vme->u.paging.gpa, ftype, VM_FAULT_NORMAL, NULL); VCPU_CTR3(vm, vcpuid, "vm_handle_paging rv = %d, gpa = %#lx, " "ftype = %d", rv, vme->u.paging.gpa, ftype); Modified: stable/12/sys/arm/arm/trap-v4.c ============================================================================== --- stable/12/sys/arm/arm/trap-v4.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/arm/arm/trap-v4.c Fri Oct 4 12:18:03 2019 (r353102) @@ -94,12 +94,12 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include #include -#include #ifdef KDB #include @@ -181,7 +181,7 @@ abort_handler(struct trapframe *tf, int type) vm_prot_t ftype; void *onfault; vm_offset_t va; - int error = 0; + int error = 0, signo, ucode; struct ksig ksig; struct proc *p; @@ -230,6 +230,8 @@ abort_handler(struct trapframe *tf, int type) if (__predict_false(data_aborts[fsr & FAULT_TYPE_MASK].func != NULL)) { if ((data_aborts[fsr & FAULT_TYPE_MASK].func)(tf, fsr, far, td, &ksig)) { + signo = ksig.signb; + ucode = ksig.code; goto do_trapsignal; } goto out; @@ -262,8 +264,8 @@ abort_handler(struct trapframe *tf, int type) * Give the user an illegal instruction signal. */ /* Deliver a SIGILL to the process */ - ksig.signb = SIGILL; - ksig.code = 0; + signo = SIGILL; + ucode = 0; goto do_trapsignal; } @@ -299,8 +301,8 @@ abort_handler(struct trapframe *tf, int type) * but uses USR mode permissions for its accesses. */ user = 1; - ksig.signb = SIGSEGV; - ksig.code = 0; + signo = SIGSEGV; + ucode = 0; goto do_trapsignal; } } else { @@ -350,9 +352,9 @@ abort_handler(struct trapframe *tf, int type) onfault = pcb->pcb_onfault; pcb->pcb_onfault = NULL; - error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + error = vm_fault_trap(map, va, ftype, VM_FAULT_NORMAL, &signo, &ucode); pcb->pcb_onfault = onfault; - if (__predict_true(error == 0)) + if (__predict_true(error == KERN_SUCCESS)) goto out; fatal_pagefault: if (user == 0) { @@ -368,18 +370,8 @@ fatal_pagefault: } - if (error == ENOMEM) { - printf("VM: pid %d (%s), uid %d killed: " - "out of swap\n", td->td_proc->p_pid, td->td_name, - (td->td_proc->p_ucred) ? - td->td_proc->p_ucred->cr_uid : -1); - ksig.signb = SIGKILL; - } else { - ksig.signb = SIGSEGV; - } - ksig.code = 0; do_trapsignal: - call_trapsignal(td, ksig.signb, ksig.code); + call_trapsignal(td, signo, ucode); out: /* If returning to user mode, make sure to invoke userret() */ if (user) @@ -613,10 +605,9 @@ prefetch_abort_handler(struct trapframe *tf) struct proc * p; struct vm_map *map; vm_offset_t fault_pc, va; - int error = 0; + int error = 0, signo, ucode; struct ksig ksig; - #if 0 /* Update vmmeter statistics */ uvmexp.traps++; @@ -652,8 +643,8 @@ prefetch_abort_handler(struct trapframe *tf) /* Ok validate the address, can only execute in USER space */ if (__predict_false(fault_pc >= VM_MAXUSER_ADDRESS || (fault_pc < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW))) { - ksig.signb = SIGSEGV; - ksig.code = 0; + signo = SIGSEGV; + ucode = 0; goto do_trapsignal; } @@ -669,24 +660,13 @@ prefetch_abort_handler(struct trapframe *tf) if (pmap_fault_fixup(map->pmap, va, VM_PROT_READ, 1)) goto out; - error = vm_fault(map, va, VM_PROT_READ | VM_PROT_EXECUTE, - VM_FAULT_NORMAL); - if (__predict_true(error == 0)) + error = vm_fault_trap(map, va, VM_PROT_READ | VM_PROT_EXECUTE, + VM_FAULT_NORMAL, &signo, &ucode); + if (__predict_true(error == KERN_SUCCESS)) goto out; - if (error == ENOMEM) { - printf("VM: pid %d (%s), uid %d killed: " - "out of swap\n", td->td_proc->p_pid, td->td_name, - (td->td_proc->p_ucred) ? - td->td_proc->p_ucred->cr_uid : -1); - ksig.signb = SIGKILL; - } else { - ksig.signb = SIGSEGV; - } - ksig.code = 0; - do_trapsignal: - call_trapsignal(td, ksig.signb, ksig.code); + call_trapsignal(td, signo, ucode); out: userret(td, tf); Modified: stable/12/sys/arm/arm/trap-v6.c ============================================================================== --- stable/12/sys/arm/arm/trap-v6.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/arm/arm/trap-v6.c Fri Oct 4 12:18:03 2019 (r353102) @@ -287,7 +287,7 @@ abort_handler(struct trapframe *tf, int prefetch) struct vmspace *vm; vm_prot_t ftype; bool usermode; - int bp_harden; + int bp_harden, ucode; #ifdef INVARIANTS void *onfault; #endif @@ -497,7 +497,9 @@ abort_handler(struct trapframe *tf, int prefetch) #endif /* Fault in the page. */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + rv = vm_fault_trap(map, va, ftype, VM_FAULT_NORMAL, &ksig.sig, + &ucode); + ksig.code = ucode; #ifdef INVARIANTS pcb->pcb_onfault = onfault; @@ -518,8 +520,6 @@ nogo: return; } - ksig.sig = SIGSEGV; - ksig.code = (rv == KERN_PROTECTION_FAILURE) ? SEGV_ACCERR : SEGV_MAPERR; ksig.addr = far; do_trapsignal: Modified: stable/12/sys/arm64/arm64/trap.c ============================================================================== --- stable/12/sys/arm64/arm64/trap.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/arm64/arm64/trap.c Fri Oct 4 12:18:03 2019 (r353102) @@ -157,7 +157,6 @@ data_abort(struct thread *td, struct trapframe *frame, struct proc *p; struct pcb *pcb; vm_prot_t ftype; - vm_offset_t va; int error, sig, ucode; #ifdef KDB bool handled; @@ -213,7 +212,6 @@ data_abort(struct thread *td, struct trapframe *frame, panic("data abort in critical section or under mutex"); } - va = trunc_page(far); if (exec) ftype = VM_PROT_EXECUTE; else @@ -221,14 +219,9 @@ data_abort(struct thread *td, struct trapframe *frame, VM_PROT_READ | VM_PROT_WRITE; /* Fault in the page. */ - error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + error = vm_fault_trap(map, far, ftype, VM_FAULT_NORMAL, &sig, &ucode); if (error != KERN_SUCCESS) { if (lower) { - sig = SIGSEGV; - if (error == KERN_PROTECTION_FAILURE) - ucode = SEGV_ACCERR; - else - ucode = SEGV_MAPERR; call_trapsignal(td, sig, ucode, (void *)far); } else { if (td->td_intr_nesting_level == 0 && Modified: stable/12/sys/i386/i386/trap.c ============================================================================== --- stable/12/sys/i386/i386/trap.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/i386/i386/trap.c Fri Oct 4 12:18:03 2019 (r353102) @@ -114,7 +114,7 @@ PMC_SOFT_DEFINE( , , page_fault, write); void trap(struct trapframe *frame); void syscall(struct trapframe *frame); -static int trap_pfault(struct trapframe *, int, vm_offset_t); +static int trap_pfault(struct trapframe *, bool, vm_offset_t, int *, int *); static void trap_fatal(struct trapframe *, vm_offset_t); #ifdef KDTRACE_HOOKS static bool trap_user_dtrace(struct trapframe *, @@ -180,9 +180,6 @@ trap_msg(int trapno) int has_f00f_bug = 0; /* Initialized so that it can be patched. */ #endif -static int prot_fault_translation = 0; -SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW, - &prot_fault_translation, 0, "Select signal to deliver on protection fault"); static int uprintf_signal; SYSCTL_INT(_machdep, OID_AUTO, uprintf_signal, CTLFLAG_RW, &uprintf_signal, 0, @@ -201,7 +198,7 @@ trap(struct trapframe *frame) ksiginfo_t ksi; struct thread *td; struct proc *p; - int signo, ucode; + int pf, signo, ucode; u_int type; register_t addr, dr6; vm_offset_t eva; @@ -211,9 +208,6 @@ trap(struct trapframe *frame) td = curthread; p = td->td_proc; - signo = 0; - ucode = 0; - addr = 0; dr6 = 0; VM_CNT_INC(v_trap); @@ -364,6 +358,7 @@ user_trctrap_out: case T_STKFLT: /* stack fault */ if (frame->tf_eflags & PSL_VM) { signo = vm86_emulate((struct vm86frame *)frame); + ucode = 0; /* XXXKIB: better code ? */ if (signo == SIGTRAP) { load_dr6(rdr6() | 0x4000); goto user_trctrap_out; @@ -394,57 +389,23 @@ user_trctrap_out: break; case T_PAGEFLT: /* page fault */ - signo = trap_pfault(frame, TRUE, eva); + addr = eva; + pf = trap_pfault(frame, true, eva, &signo, &ucode); #if defined(I586_CPU) && !defined(NO_F00F_HACK) - if (signo == -2) { + if (pf == -2) { /* * The f00f hack workaround has triggered, so * treat the fault as an illegal instruction * (T_PRIVINFLT) instead of a page fault. */ type = frame->tf_trapno = T_PRIVINFLT; - - /* Proceed as in that case. */ - ucode = ILL_PRVOPC; - signo = SIGILL; break; } #endif - if (signo == -1) + if (pf == -1) return; - if (signo == 0) + if (pf == 0) goto user; - - if (signo == SIGSEGV) - ucode = SEGV_MAPERR; - else if (prot_fault_translation == 0) { - /* - * Autodetect. This check also covers - * the images without the ABI-tag ELF - * note. - */ - if (SV_CURPROC_ABI() == SV_ABI_FREEBSD && - p->p_osrel >= P_OSREL_SIGSEGV) { - signo = SIGSEGV; - ucode = SEGV_ACCERR; - } else { - signo = SIGBUS; - ucode = T_PAGEFLT; - } - } else if (prot_fault_translation == 1) { - /* - * Always compat mode. - */ - signo = SIGBUS; - ucode = T_PAGEFLT; - } else { - /* - * Always SIGSEGV mode. - */ - signo = SIGSEGV; - ucode = SEGV_ACCERR; - } - addr = eva; break; case T_DIVIDE: /* integer divide fault */ @@ -516,7 +477,7 @@ user_trctrap_out: ("kernel trap doesn't have ucred")); switch (type) { case T_PAGEFLT: /* page fault */ - (void) trap_pfault(frame, FALSE, eva); + (void)trap_pfault(frame, false, eva, NULL, NULL); return; case T_DNA: @@ -768,16 +729,31 @@ user: ("Return from trap with kernel FPU ctx leaked")); } +/* + * Handle all details of a page fault. + * Returns: + * -2 if the fault was caused by triggered workaround for Intel Pentium + * 0xf00f bug. + * -1 if this fault was fatal, typically from kernel mode + * (cannot happen, but we need to return something). + * 0 if this fault was handled by updating either the user or kernel + * page table, execution can continue. + * 1 if this fault was from usermode and it was not handled, a synchronous + * signal should be delivered to the thread. *signo returns the signal + * number, *ucode gives si_code. + */ static int -trap_pfault(struct trapframe *frame, int usermode, vm_offset_t eva) +trap_pfault(struct trapframe *frame, bool usermode, vm_offset_t eva, + int *signo, int *ucode) { struct thread *td; struct proc *p; - vm_offset_t va; vm_map_t map; int rv; vm_prot_t ftype; + MPASS(!usermode || (signo != NULL && ucode != NULL)); + td = curthread; p = td->td_proc; @@ -825,8 +801,7 @@ trap_pfault(struct trapframe *frame, int usermode, vm_ return (-1); } } - va = trunc_page(eva); - if (va >= PMAP_TRM_MIN_ADDRESS) { + if (eva >= PMAP_TRM_MIN_ADDRESS) { /* * Don't allow user-mode faults in kernel address space. * An exception: if the faulting address is the invalid @@ -836,11 +811,17 @@ trap_pfault(struct trapframe *frame, int usermode, vm_ * fault. */ #if defined(I586_CPU) && !defined(NO_F00F_HACK) - if ((eva == (unsigned int)&idt[6]) && has_f00f_bug) + if ((eva == (unsigned int)&idt[6]) && has_f00f_bug) { + *ucode = ILL_PRVOPC; + *signo = SIGILL; return (-2); + } #endif - if (usermode) - return (SIGSEGV); + if (usermode) { + *signo = SIGSEGV; + *ucode = SEGV_MAPERR; + return (1); + } trap_fatal(frame, eva); return (-1); } else { @@ -879,7 +860,7 @@ trap_pfault(struct trapframe *frame, int usermode, vm_ ftype = VM_PROT_READ; /* Fault in the page. */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + rv = vm_fault_trap(map, eva, ftype, VM_FAULT_NORMAL, signo, ucode); if (rv == KERN_SUCCESS) { #ifdef HWPMC_HOOKS if (ftype == VM_PROT_READ || ftype == VM_PROT_WRITE) { @@ -894,16 +875,15 @@ trap_pfault(struct trapframe *frame, int usermode, vm_ #endif return (0); } - if (!usermode) { - if (td->td_intr_nesting_level == 0 && - curpcb->pcb_onfault != NULL) { - frame->tf_eip = (int)curpcb->pcb_onfault; - return (0); - } - trap_fatal(frame, eva); - return (-1); + if (usermode) + return (1); + if (td->td_intr_nesting_level == 0 && + curpcb->pcb_onfault != NULL) { + frame->tf_eip = (int)curpcb->pcb_onfault; + return (0); } - return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); + trap_fatal(frame, eva); + return (-1); } static void Modified: stable/12/sys/kern/sys_process.c ============================================================================== --- stable/12/sys/kern/sys_process.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/kern/sys_process.c Fri Oct 4 12:18:03 2019 (r353102) @@ -280,7 +280,7 @@ proc_rwmem(struct proc *p, struct uio *uio) /* * Fault and hold the page on behalf of the process. */ - error = vm_fault_hold(map, pageno, reqprot, fault_flags, &m); + error = vm_fault(map, pageno, reqprot, fault_flags, &m); if (error != KERN_SUCCESS) { if (error == KERN_RESOURCE_SHORTAGE) error = ENOMEM; Modified: stable/12/sys/mips/mips/trap.c ============================================================================== --- stable/12/sys/mips/mips/trap.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/mips/mips/trap.c Fri Oct 4 12:18:03 2019 (r353102) @@ -670,8 +670,9 @@ trap(struct trapframe *trapframe) int rv; kernel_fault: - va = trunc_page((vm_offset_t)trapframe->badvaddr); - rv = vm_fault(kernel_map, va, ftype, VM_FAULT_NORMAL); + va = (vm_offset_t)trapframe->badvaddr; + rv = vm_fault_trap(kernel_map, va, ftype, + VM_FAULT_NORMAL, NULL, NULL); if (rv == KERN_SUCCESS) return (trapframe->pc); if (td->td_pcb->pcb_onfault != NULL) { @@ -706,7 +707,7 @@ dofault: vm = p->p_vmspace; map = &vm->vm_map; - va = trunc_page((vm_offset_t)trapframe->badvaddr); + va = (vm_offset_t)trapframe->badvaddr; if (KERNLAND(trapframe->badvaddr)) { /* * Don't allow user-mode faults in kernel @@ -715,7 +716,8 @@ dofault: goto nogo; } - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + rv = vm_fault_trap(map, va, ftype, VM_FAULT_NORMAL, + &i, &ucode); /* * XXXDTRACE: add dtrace_doubletrap_func here? */ @@ -740,11 +742,6 @@ dofault: } goto err; } - i = SIGSEGV; - if (rv == KERN_PROTECTION_FAILURE) - ucode = SEGV_ACCERR; - else - ucode = SEGV_MAPERR; addr = trapframe->pc; msg = "BAD_PAGE_FAULT"; Modified: stable/12/sys/powerpc/powerpc/trap.c ============================================================================== --- stable/12/sys/powerpc/powerpc/trap.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/powerpc/powerpc/trap.c Fri Oct 4 12:18:03 2019 (r353102) @@ -86,7 +86,8 @@ __FBSDID("$FreeBSD$"); static void trap_fatal(struct trapframe *frame); static void printtrap(u_int vector, struct trapframe *frame, int isfatal, int user); -static int trap_pfault(struct trapframe *frame, int user); +static bool trap_pfault(struct trapframe *frame, bool user, int *signo, + int *ucode); static int fix_unaligned(struct thread *td, struct trapframe *frame); static int handle_onfault(struct trapframe *frame); static void syscall(struct trapframe *frame); @@ -269,9 +270,8 @@ trap(struct trapframe *frame) #endif case EXC_DSI: case EXC_ISI: - sig = trap_pfault(frame, 1); - if (sig == SIGSEGV) - ucode = SEGV_MAPERR; + if (trap_pfault(frame, true, &sig, &ucode)) + sig = 0; break; case EXC_SC: @@ -419,7 +419,7 @@ trap(struct trapframe *frame) break; #endif case EXC_DSI: - if (trap_pfault(frame, 0) == 0) + if (trap_pfault(frame, false, NULL, NULL)) return; break; case EXC_MCHK: @@ -763,10 +763,10 @@ handle_user_slb_spill(pmap_t pm, vm_offset_t addr) } #endif -static int -trap_pfault(struct trapframe *frame, int user) +static bool +trap_pfault(struct trapframe *frame, bool user, int *signo, int *ucode) { - vm_offset_t eva, va; + vm_offset_t eva; struct thread *td; struct proc *p; vm_map_t map; @@ -798,28 +798,27 @@ trap_pfault(struct trapframe *frame, int user) } else { rv = pmap_decode_kernel_ptr(eva, &is_user, &eva); if (rv != 0) - return (SIGSEGV); + return (false); if (is_user) map = &p->p_vmspace->vm_map; else map = kernel_map; } - va = trunc_page(eva); /* Fault in the page. */ - rv = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + rv = vm_fault_trap(map, eva, ftype, VM_FAULT_NORMAL, signo, ucode); /* * XXXDTRACE: add dtrace_doubletrap_func here? */ if (rv == KERN_SUCCESS) - return (0); + return (true); if (!user && handle_onfault(frame)) - return (0); + return (true); - return (SIGSEGV); + return (false); } /* Modified: stable/12/sys/riscv/riscv/trap.c ============================================================================== --- stable/12/sys/riscv/riscv/trap.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/riscv/riscv/trap.c Fri Oct 4 12:18:03 2019 (r353102) @@ -219,14 +219,9 @@ data_abort(struct trapframe *frame, int usermode) if (pmap_fault_fixup(map->pmap, va, ftype)) goto done; - error = vm_fault(map, va, ftype, VM_FAULT_NORMAL); + error = vm_fault_trap(map, va, ftype, VM_FAULT_NORMAL, &sig, &ucode); if (error != KERN_SUCCESS) { if (usermode) { - sig = SIGSEGV; - if (error == KERN_PROTECTION_FAILURE) - ucode = SEGV_ACCERR; - else - ucode = SEGV_MAPERR; call_trapsignal(td, sig, ucode, (void *)stval); } else { if (pcb->pcb_onfault != 0) { Modified: stable/12/sys/sparc64/sparc64/trap.c ============================================================================== --- stable/12/sys/sparc64/sparc64/trap.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/sparc64/sparc64/trap.c Fri Oct 4 12:18:03 2019 (r353102) @@ -91,7 +91,8 @@ void trap(struct trapframe *tf); void syscall(struct trapframe *tf); static int trap_cecc(void); -static int trap_pfault(struct thread *td, struct trapframe *tf); +static bool trap_pfault(struct thread *td, struct trapframe *tf, int *signo, + int *ucode); extern char copy_fault[]; extern char copy_nofault_begin[]; @@ -287,7 +288,8 @@ trap(struct trapframe *tf) addr = tf->tf_sfar; /* FALLTHROUGH */ case T_INSTRUCTION_MISS: - sig = trap_pfault(td, tf); + if (trap_pfault(td, tf, &sig, &ucode)) + sig = 0; break; case T_FILL: sig = rwindow_load(td, tf, 2); @@ -358,7 +360,7 @@ trap(struct trapframe *tf) case T_DATA_MISS: case T_DATA_PROTECTION: case T_INSTRUCTION_MISS: - error = trap_pfault(td, tf); + error = !trap_pfault(td, tf, &sig, &ucode); break; case T_DATA_EXCEPTION: case T_MEM_ADDRESS_NOT_ALIGNED: @@ -443,8 +445,8 @@ trap_cecc(void) return (0); } -static int -trap_pfault(struct thread *td, struct trapframe *tf) +static bool +trap_pfault(struct thread *td, struct trapframe *tf, int *signo, int *ucode) { vm_map_t map; struct proc *p; @@ -508,27 +510,27 @@ trap_pfault(struct thread *td, struct trapframe *tf) } /* Fault in the page. */ - rv = vm_fault(map, va, prot, VM_FAULT_NORMAL); + rv = vm_fault_trap(map, va, prot, VM_FAULT_NORMAL, signo, ucode); CTR3(KTR_TRAP, "trap_pfault: return td=%p va=%#lx rv=%d", td, va, rv); if (rv == KERN_SUCCESS) - return (0); + return (true); if (ctx != TLB_CTX_KERNEL && (tf->tf_tstate & TSTATE_PRIV) != 0) { if (tf->tf_tpc >= (u_long)fs_nofault_begin && tf->tf_tpc <= (u_long)fs_nofault_end) { tf->tf_tpc = (u_long)fs_fault; tf->tf_tnpc = tf->tf_tpc + 4; - return (0); + return (true); } if (tf->tf_tpc >= (u_long)copy_nofault_begin && tf->tf_tpc <= (u_long)copy_nofault_end) { tf->tf_tpc = (u_long)copy_fault; tf->tf_tnpc = tf->tf_tpc + 4; - return (0); + return (true); } } - return ((rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV); + return (false); } /* Maximum number of arguments that can be passed via the out registers. */ Modified: stable/12/sys/sys/signal.h ============================================================================== --- stable/12/sys/sys/signal.h Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/sys/signal.h Fri Oct 4 12:18:03 2019 (r353102) @@ -315,11 +315,13 @@ struct siginfo32 { #define BUS_ADRALN 1 /* Invalid address alignment. */ #define BUS_ADRERR 2 /* Nonexistent physical address. */ #define BUS_OBJERR 3 /* Object-specific hardware error. */ +#define BUS_OOMERR 100 /* Non-standard: No memory. */ /* codes for SIGSEGV */ #define SEGV_MAPERR 1 /* Address not mapped to object. */ #define SEGV_ACCERR 2 /* Invalid permissions for mapped */ /* object. */ +#define SEGV_PKUERR 100 /* x86: PKU violation */ /* codes for SIGFPE */ #define FPE_INTOVF 1 /* Integer overflow. */ Modified: stable/12/sys/vm/vm_extern.h ============================================================================== --- stable/12/sys/vm/vm_extern.h Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/vm/vm_extern.h Fri Oct 4 12:18:03 2019 (r353102) @@ -85,15 +85,16 @@ void kmeminit(void); int kernacc(void *, int, int); int useracc(void *, int, int); -int vm_fault(vm_map_t, vm_offset_t, vm_prot_t, int); +int vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, + int fault_flags, vm_page_t *m_hold); void vm_fault_copy_entry(vm_map_t, vm_map_t, vm_map_entry_t, vm_map_entry_t, vm_ooffset_t *); int vm_fault_disable_pagefaults(void); void vm_fault_enable_pagefaults(int save); -int vm_fault_hold(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, - int fault_flags, vm_page_t *m_hold); int vm_fault_quick_hold_pages(vm_map_t map, vm_offset_t addr, vm_size_t len, vm_prot_t prot, vm_page_t *ma, int max_count); +int vm_fault_trap(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, + int fault_flags, int *signo, int *ucode); int vm_forkproc(struct thread *, struct proc *, struct thread *, struct vmspace *, int); void vm_waitproc(struct proc *); Modified: stable/12/sys/vm/vm_fault.c ============================================================================== --- stable/12/sys/vm/vm_fault.c Fri Oct 4 10:45:10 2019 (r353101) +++ stable/12/sys/vm/vm_fault.c Fri Oct 4 12:18:03 2019 (r353102) @@ -88,7 +88,9 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include +#include #include #include #ifdef KTRACE @@ -528,8 +530,19 @@ vm_fault_populate(struct faultstate *fs, vm_prot_t pro return (KERN_SUCCESS); } +static int prot_fault_translation; +SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RWTUN, + &prot_fault_translation, 0, + "Control signal to deliver on protection fault"); + +/* compat definition to keep common code for signal translation */ +#define UCODE_PAGEFLT 12 +#ifdef T_PAGEFLT +_Static_assert(UCODE_PAGEFLT == T_PAGEFLT, "T_PAGEFLT"); +#endif + /* - * vm_fault: + * vm_fault_trap: * * Handle a page fault occurring at the given address, * requiring the given permissions, in the map specified. @@ -546,12 +559,13 @@ vm_fault_populate(struct faultstate *fs, vm_prot_t pro * Caller may hold no locks. */ int -vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, - int fault_flags) +vm_fault_trap(vm_map_t map, vm_offset_t vaddr, vm_prot_t fault_type, + int fault_flags, int *signo, int *ucode) { struct thread *td; int result; + MPASS(signo == NULL || ucode != NULL); td = curthread; if ((td->td_pflags & TDP_NOFAULTING) != 0) return (KERN_PROTECTION_FAILURE); @@ -559,17 +573,69 @@ vm_fault(vm_map_t map, vm_offset_t vaddr, vm_prot_t fa if (map != kernel_map && KTRPOINT(td, KTR_FAULT)) ktrfault(vaddr, fault_type); #endif - result = vm_fault_hold(map, trunc_page(vaddr), fault_type, fault_flags, + result = vm_fault(map, trunc_page(vaddr), fault_type, fault_flags, NULL); + KASSERT(result == KERN_SUCCESS || result == KERN_FAILURE || + result == KERN_INVALID_ADDRESS || + result == KERN_RESOURCE_SHORTAGE || + result == KERN_PROTECTION_FAILURE || + result == KERN_OUT_OF_BOUNDS, + ("Unexpected Mach error %d from vm_fault()", result)); #ifdef KTRACE if (map != kernel_map && KTRPOINT(td, KTR_FAULTEND)) ktrfaultend(result); #endif + if (result != KERN_SUCCESS && signo != NULL) { + switch (result) { + case KERN_FAILURE: + case KERN_INVALID_ADDRESS: + *signo = SIGSEGV; + *ucode = SEGV_MAPERR; + break; + case KERN_RESOURCE_SHORTAGE: + *signo = SIGBUS; + *ucode = BUS_OOMERR; + break; + case KERN_OUT_OF_BOUNDS: + *signo = SIGBUS; + *ucode = BUS_OBJERR; + break; + case KERN_PROTECTION_FAILURE: + if (prot_fault_translation == 0) { + /* + * Autodetect. This check also covers + * the images without the ABI-tag ELF + * note. + */ + if (SV_CURPROC_ABI() == SV_ABI_FREEBSD && + curproc->p_osrel >= P_OSREL_SIGSEGV) { + *signo = SIGSEGV; + *ucode = SEGV_ACCERR; + } else { + *signo = SIGBUS; + *ucode = UCODE_PAGEFLT; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***