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
Konstantin Belousov
kib at FreeBSD.org
Fri Oct 4 12:18:07 UTC 2019
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 <vm/vm_kern.h>
#include <vm/vm_map.h>
#include <vm/vm_extern.h>
+#include <vm/vm_param.h>
#include <machine/cpu.h>
#include <machine/frame.h>
#include <machine/machdep.h>
#include <machine/pcb.h>
-#include <machine/vmparam.h>
#ifdef KDB
#include <sys/kdb.h>
@@ -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 <sys/racct.h>
#include <sys/resourcevar.h>
#include <sys/rwlock.h>
+#include <sys/signalvar.h>
#include <sys/sysctl.h>
+#include <sys/sysent.h>
#include <sys/vmmeter.h>
#include <sys/vnode.h>
#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 ***
More information about the svn-src-all
mailing list