Page MenuHomeFreeBSD

D3617.id8638.diff
No OneTemporary

D3617.id8638.diff

Index: sys/arm/arm/pmap-v6-new.c
===================================================================
--- sys/arm/arm/pmap-v6-new.c
+++ sys/arm/arm/pmap-v6-new.c
@@ -6158,8 +6158,9 @@
* All L1 tables should always be mapped and present.
* However, we check only current one herein. For user mode,
* only permission abort from malicious user is not fatal.
+ * And alignment fault as it may have higher priority.
*/
- if (!usermode || (idx != FAULT_PERM_L2)) {
+ if (!usermode || (idx != FAULT_ALIGN && idx != FAULT_PERM_L2)) {
CTR4(KTR_PMAP, "%s: pmap %#x pm_pt1 %#x far %#x",
__func__, pmap, pmap->pm_pt1, far);
panic("%s: pm_pt1 abort", __func__);
@@ -6172,9 +6173,10 @@
* L1 table. However, only existing L2 tables are mapped
* in PT2MAP. For user mode, only L2 translation abort and
* permission abort from malicious user is not fatal.
+ * And alignment fault as it may have higher priority.
*/
- if (!usermode ||
- (idx != FAULT_TRAN_L2 && idx != FAULT_PERM_L2)) {
+ if (!usermode || (idx != FAULT_ALIGN &&
+ idx != FAULT_TRAN_L2 && idx != FAULT_PERM_L2)) {
CTR4(KTR_PMAP, "%s: pmap %#x PT2MAP %#x far %#x",
__func__, pmap, PT2MAP, far);
panic("%s: PT2MAP abort", __func__);
Index: sys/arm/arm/trap-v6.c
===================================================================
--- sys/arm/arm/trap-v6.c
+++ sys/arm/arm/trap-v6.c
@@ -168,6 +168,17 @@
};
+static __inline int
+read_instruction_nofault(vm_offset_t addr, uint32_t *inst)
+{
+
+ if (!ALIGNED_POINTER(addr, uint32_t) || cp15_ats1cpr_check(addr) != 0)
+ return (EFAULT);
+
+ *inst = *((uint32_t*)addr);
+ return (0);
+}
+
static __inline void
call_trapsignal(struct thread *td, int sig, int code, vm_offset_t addr)
{
@@ -275,7 +286,7 @@
{
struct thread *td;
vm_offset_t far, va;
- int idx, usermode;
+ int idx, usermode, usr_copy_fault;
uint32_t fsr;
struct ksig ksig;
struct proc *p;
@@ -300,8 +311,8 @@
if (usermode)
td->td_frame = tf;
- CTR4(KTR_TRAP, "abort_handler: fsr %#x (idx %u) far %#x prefetch %u",
- fsr, idx, far, prefetch);
+ CTR6(KTR_TRAP, "%s: fsr %#x (idx %u) far %#x prefetch %u user %u",
+ __func__, fsr, idx, far, prefetch, usermode);
/*
* Firstly, handle aborts that are not directly related to mapping.
@@ -316,16 +327,40 @@
return;
}
-#ifdef ARM_NEW_PMAP
- rv = pmap_fault(PCPU_GET(curpmap), far, fsr, idx, usermode);
- if (rv == 0) {
- return;
- } else if (rv == EFAULT) {
+ /*
+ * ARM has a set of unprivileged load and store instructions
+ * (LDRT/LDRBT/STRT/STRBT ...) which are supposed to be used in other
+ * than user mode and OS should recognize their aborts and behave
+ * appropriately. However, there is no way how to do that reasonably
+ * in general unless we restrict the handling somehow.
+ *
+ * Thus, we only handle such cases when these instructions are used
+ * while pcb_onfault is not NULL. This is quite reasonable restriction
+ * as the pcb_onfault is used for quick error handling of access to
+ * user address space done in kernel.
+ */
+ usr_copy_fault = 0;
+ pcb = td->td_pcb;
+ if (__predict_false(!usermode && pcb->pcb_onfault != NULL)) {
+ uint32_t inst;
- call_trapsignal(td, SIGSEGV, SEGV_MAPERR, far);
- userret(td, tf);
- return;
+ /* Read instruction safely to not double abort. */
+ if (read_instruction_nofault(TRAPF_PC(tf), &inst) != 0)
+ panic("%s: bad PC %x", __func__, TRAPF_PC(tf));
+
+ /* LDRT/LDRHT/LDRBT/STRT/STRHT/STRBT instruction? */
+ if ((inst & 0x09200000) == 0x00200000 &&
+ (inst & 0x06000000) != 0x02000000)
+ usr_copy_fault = 1;
}
+
+#ifdef ARM_NEW_PMAP
+ rv = pmap_fault(PCPU_GET(curpmap), far, fsr, idx, usermode ||
+ usr_copy_fault);
+ if (rv == 0)
+ return;
+ if (rv == EFAULT)
+ goto nogo;
#endif
/*
* Now, when we handled imprecise and debug aborts, the rest of
@@ -410,7 +445,6 @@
* Don't pass faulting cache operation to vm_fault(). We don't want
* to handle all vm stuff at this moment.
*/
- pcb = td->td_pcb;
if (__predict_false(pcb->pcb_onfault == cachebailout)) {
tf->tf_r0 = far; /* return failing address */
tf->tf_pc = (register_t)pcb->pcb_onfault;
@@ -435,32 +469,18 @@
*/
/* fusubailout is used by [fs]uswintr to avoid page faulting */
- pcb = td->td_pcb;
if (__predict_false(pcb->pcb_onfault == fusubailout)) {
tf->tf_r0 = EFAULT;
tf->tf_pc = (register_t)pcb->pcb_onfault;
return;
}
- /*
- * QQQ: ARM has a set of unprivileged load and store instructions
- * (LDRT/LDRBT/STRT/STRBT ...) which are supposed to be used
- * in other than user mode and OS should recognize their
- * aborts and behaved appropriately. However, there is no way
- * how to do that reasonably in general unless we restrict
- * the handling somehow. One way is to limit the handling for
- * aborts which come from undefined mode only.
- *
- * Anyhow, we do not use these instructions and do not implement
- * any special handling for them.
- */
-
va = trunc_page(far);
if (va >= KERNBASE) {
/*
* Don't allow user-mode faults in kernel address space.
*/
- if (usermode)
+ if (usermode || usr_copy_fault)
goto nogo;
map = kernel_map;
Index: sys/arm/include/cpu-v6.h
===================================================================
--- sys/arm/include/cpu-v6.h
+++ sys/arm/include/cpu-v6.h
@@ -155,8 +155,9 @@
_RF0(cp15_actlr_get, CP15_ACTLR(%0))
_WF1(cp15_actlr_set, CP15_ACTLR(%0))
#if __ARM_ARCH >= 6
-_WF1(cp15_ats1cpr_set, CP15_ATS1CPR(%0));
-_RF0(cp15_par_get, CP15_PAR);
+_WF1(cp15_ats1cpr_set, CP15_ATS1CPR(%0))
+_WF1(cp15_ats1cpw_set, CP15_ATS1CPW(%0))
+_RF0(cp15_par_get, CP15_PAR(%0))
_RF0(cp15_sctlr_get, CP15_SCTLR(%0))
#endif
@@ -531,6 +532,34 @@
tlb_flush_all_ng_local();
}
+/* Check address for privileged (PL1) read access. */
+static __inline int
+cp15_ats1cpr_check(vm_offset_t addr)
+{
+ register_t par, s;
+
+ s = intr_disable();
+ cp15_ats1cpr_set(addr);
+ isb();
+ par = cp15_par_get();
+ intr_restore(s);
+ return (par & 0x01 ? EFAULT : 0);
+}
+
+/* Check address for privileged (PL1) write access. */
+static __inline int
+cp15_ats1cpw_check(vm_offset_t addr)
+{
+ register_t par, s;
+
+ s = intr_disable();
+ cp15_ats1cpw_set(addr);
+ isb();
+ par = cp15_par_get();
+ intr_restore(s);
+ return (par & 0x01 ? EFAULT : 0);
+}
+
#endif /* _KERNEL */
#endif /* !MACHINE_CPU_V6_H */
Index: sys/arm/include/sysreg.h
===================================================================
--- sys/arm/include/sysreg.h
+++ sys/arm/include/sysreg.h
@@ -130,7 +130,7 @@
#define CP15_BPIALLIS p15, 0, r0, c7, c1, 6 /* Branch predictor invalidate all IS */
#endif
-#define CP15_PAR p15, 0, r0, c7, c4, 0 /* Physical Address Register */
+#define CP15_PAR(rr) p15, 0, rr, c7, c4, 0 /* Physical Address Register */
#define CP15_ICIALLU p15, 0, r0, c7, c5, 0 /* Instruction cache invalidate all PoU */
#define CP15_ICIMVAU(rr) p15, 0, rr, c7, c5, 1 /* Instruction cache invalidate */

File Metadata

Mime Type
text/plain
Expires
Sun, Apr 19, 8:18 AM (15 h, 12 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
31755758
Default Alt Text
D3617.id8638.diff (6 KB)

Event Timeline