Add and use a specific routine to fetch instructions from userland when
authormiod <miod@openbsd.org>
Tue, 24 Jan 2023 07:26:33 +0000 (07:26 +0000)
committermiod <miod@openbsd.org>
Tue, 24 Jan 2023 07:26:33 +0000 (07:26 +0000)
doing floating-point emulation, as copyin will fail on exec-only mappings
now.
ok deraadt@ kettenis@

sys/arch/sparc64/include/pmap.h
sys/arch/sparc64/sparc64/pmap.c
sys/arch/sparc64/sparc64/trap.c

index 6b49abd..acbc71b 100644 (file)
@@ -159,7 +159,8 @@ extern struct pmap kernel_pmap_;
 
 #define pmap_proc_iflush(p,va,len)     /* nothing */
 
-void pmap_bootstrap(u_long, u_long, u_int, u_int);
+void   pmap_bootstrap(u_long, u_long, u_int, u_int);
+int    pmap_copyinsn(pmap_t, vaddr_t, uint32_t *);
 
 /* make sure all page mappings are modulo 16K to prevent d$ aliasing */
 #define PMAP_PREFER
index dde9b9f..e067df1 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pmap.c,v 1.109 2023/01/23 19:31:41 miod Exp $ */
+/*     $OpenBSD: pmap.c,v 1.110 2023/01/24 07:26:34 miod Exp $ */
 /*     $NetBSD: pmap.c,v 1.107 2001/08/31 16:47:41 eeh Exp $   */
 /*
  * 
@@ -2915,3 +2915,25 @@ db_dump_pv(db_expr_t addr, int have_addr, db_expr_t count, char *modif)
 }
 
 #endif
+
+/*
+ * Read an instruction from a given virtual memory address.
+ * EXEC_ONLY mappings are bypassed.
+ */
+int
+pmap_copyinsn(pmap_t pmap, vaddr_t va, uint32_t *insn)
+{
+       paddr_t pa;
+
+       if (pmap == pmap_kernel())
+               return EINVAL;
+
+       mtx_enter(&pmap->pm_mtx);
+       /* inline pmap_extract */
+       pa = pseg_get(pmap, va) & TLB_PA_MASK;
+       if (pa != 0)
+               *insn = lduwa(pa | (va & PAGE_MASK), ASI_PHYS_CACHED);
+       mtx_leave(&pmap->pm_mtx);
+
+       return pa == 0 ? EFAULT : 0;
+}
index f697b72..7321a66 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: trap.c,v 1.113 2023/01/16 05:32:05 deraadt Exp $      */
+/*     $OpenBSD: trap.c,v 1.114 2023/01/24 07:26:34 miod Exp $ */
 /*     $NetBSD: trap.c,v 1.73 2001/08/09 01:03:01 eeh Exp $ */
 
 /*
@@ -322,6 +322,8 @@ void text_access_error(struct trapframe *tf, unsigned type,
        vaddr_t pc, u_long sfsr, vaddr_t afva, u_long afsr);
 void syscall(struct trapframe *, register_t code, register_t pc);
 
+int    copyinsn(struct proc *p, vaddr_t uva, int *insn);
+
 /*
  * If someone stole the FPU while we were away, do not enable it
  * on return.  This is not done in userret() above as it must follow
@@ -465,7 +467,7 @@ dopanic:
        {
                union instr ins;
 
-               if (copyin((caddr_t)pc, &ins, sizeof(ins)) != 0) {
+               if (copyinsn(p, pc, &ins.i_int) != 0) {
                        /* XXX Can this happen? */
                        trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
                        break;
@@ -543,7 +545,7 @@ dopanic:
        {
                union instr ins;
 
-               if (copyin((caddr_t)pc, &ins, sizeof(ins)) != 0) {
+               if (copyinsn(p, pc, &ins.i_int) != 0) {
                        /* XXX Can this happen? */
                        trapsignal(p, SIGILL, 0, ILL_ILLOPC, sv);
                        break;
@@ -624,7 +626,8 @@ dopanic:
                         * Push the faulting instruction on the queue;
                         * we might need to emulate it.
                         */
-                       copyin((caddr_t)pc, &p->p_md.md_fpstate->fs_queue[0].fq_instr, sizeof(int));
+                       (void)copyinsn(p, pc,
+                           &p->p_md.md_fpstate->fs_queue[0].fq_instr);
                        p->p_md.md_fpstate->fs_queue[0].fq_addr = (int *)pc;
                        p->p_md.md_fpstate->fs_qsize = 1;
                }
@@ -1252,3 +1255,21 @@ child_return(void *arg)
 
        mi_child_return(p);
 }
+
+int
+copyinsn(struct proc *p, vaddr_t uva, int *insn)
+{
+       struct vm_map *map = &p->p_vmspace->vm_map;
+       int error = 0;
+
+       if (__predict_false((uva & 3) != 0))
+               return EFAULT;
+
+       do {
+               if (pmap_copyinsn(map->pmap, uva, (uint32_t *)insn) == 0)
+                       break;
+               error = uvm_fault(map, trunc_page(uva), 0, PROT_EXEC);
+       } while (error == 0);
+
+       return error;
+}