- In data_abort_handler(), move the fault pc alignment check to before

the call to data_abort_fixup() as the fixup routines also try to
   de-reference the fault pc.

 - If a fault came from kernel mode, and the fault address looks to be in
   the kernel's address space, and pcb_onfault is *set*, check the
   instruction which caused the fault. If it's LDR{B,}T or STR{B,}T
   then one of the copy in/out routines is trying to read/write a
   kernel address with the wrong privilege. If that address is actually
   mapped, we could end up in an infinite loop because we failed to
   notice that it's really a 'user mode' access. Yay for "crashme".
   I suspect this also fixes PR port-arm/23052.

   Note: This *could* be fixed by adding sanity checks to copyin et al,
   but that would add extra overhead to the non-error path...

 - Fix a couple of __predict_false cases.
This commit is contained in:
scw 2003-11-14 19:00:03 +00:00
parent f306da6419
commit a590a31135
1 changed files with 24 additions and 24 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: fault.c,v 1.40 2003/11/14 00:21:30 scw Exp $ */
/* $NetBSD: fault.c,v 1.41 2003/11/14 19:00:03 scw Exp $ */
/*
* Copyright 2003 Wasabi Systems, Inc.
@ -81,7 +81,7 @@
#include "opt_kgdb.h"
#include <sys/types.h>
__KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.40 2003/11/14 00:21:30 scw Exp $");
__KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.41 2003/11/14 19:00:03 scw Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -226,7 +226,7 @@ data_abort_handler(trapframe_t *tf)
uvmexp.traps++;
/* Re-enable interrupts if they were enabled previously */
if (__predict_false((tf->tf_spsr & I32_bit) == 0))
if (__predict_true((tf->tf_spsr & I32_bit) == 0))
enable_interrupts(I32_bit);
/* Get the current lwp structure or lwp0 if there is none */
@ -270,22 +270,6 @@ data_abort_handler(trapframe_t *tf)
if (user)
l->l_addr->u_pcb.pcb_tf = tf;
/* See if the cpu state needs to be fixed up */
switch (data_abort_fixup(tf, fsr, far, l)) {
case ABORT_FIXUP_RETURN:
return;
case ABORT_FIXUP_FAILED:
/* Deliver a SIGILL to the process */
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGILL;
ksi.ksi_code = ILL_ILLOPC;
ksi.ksi_addr = (u_int32_t *)(intptr_t) far;
ksi.ksi_trap = fsr;
goto do_trapsignal;
default:
break;
}
/*
* Make sure the Program Counter is sane. We could fall foul of
* someone executing Thumb code, in which case the PC might not
@ -315,18 +299,34 @@ data_abort_handler(trapframe_t *tf)
dab_fatal(tf, fsr, far, l, NULL);
}
/* See if the cpu state needs to be fixed up */
switch (data_abort_fixup(tf, fsr, far, l)) {
case ABORT_FIXUP_RETURN:
return;
case ABORT_FIXUP_FAILED:
/* Deliver a SIGILL to the process */
KSI_INIT_TRAP(&ksi);
ksi.ksi_signo = SIGILL;
ksi.ksi_code = ILL_ILLOPC;
ksi.ksi_addr = (u_int32_t *)(intptr_t) far;
ksi.ksi_trap = fsr;
goto do_trapsignal;
default:
break;
}
va = trunc_page((vaddr_t)far);
/*
* It is only a kernel address space fault iff:
* 1. user == 0 and
* 2. pcb_onfault not set or
* 3. pcb_onfault set but supervisor space fault
* The last can occur during an exec() copyin where the
* argument space is lazy-allocated.
* 3. pcb_onfault set and not LDRT/LDRBT/STRT/STRBT instruction.
*/
if (user == 0 && (va >= VM_MIN_KERNEL_ADDRESS ||
(va < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW))) {
(va < VM_MIN_ADDRESS && vector_page == ARM_VECTORS_LOW)) &&
__predict_true((pcb->pcb_onfault == NULL ||
(ReadWord(tf->tf_pc) & 0x05200000) != 0x04200000))) {
map = kernel_map;
/* Was the fault due to the FPE/IPKDB ? */
@ -684,7 +684,7 @@ prefetch_abort_handler(trapframe_t *tf)
* from user mode so we know interrupts were not disabled.
* But we check anyway.
*/
if (__predict_false((tf->tf_spsr & I32_bit) == 0))
if (__predict_true((tf->tf_spsr & I32_bit) == 0))
enable_interrupts(I32_bit);
/* See if the cpu state needs to be fixed up */