On systems without xonly mmu hardware-enforcement, we can still mitigate
authorderaadt <deraadt@openbsd.org>
Tue, 31 Jan 2023 15:18:51 +0000 (15:18 +0000)
committerderaadt <deraadt@openbsd.org>
Tue, 31 Jan 2023 15:18:51 +0000 (15:18 +0000)
against classic BROP with a range-checking wrapper in front of copyin() and
copyinstr() which ensures the userland source doesn't overlap the main program
text, ld.so text, signal tramp text (it's mapping is hard to distinguish
so it comes along for the ride), or libc.so text.  ld.so tells the kernel
libc.so text range with msyscall(2).  The range checking for 2-4 elements is
done without locking (because all 4 ranges are immutable!) and is inexpensive.

write(sock, &open, 400) now fails with EFAULT.  No programs have been
discovered which require reading their own text segments with a system call.

On a machine without mmu enforcement, a test program reports the following:
                  userland   kernel
ld.so             readable   unreadable
mmap xz           unreadable unreadable
mmap x            readable   readable
mmap nrx          readable   readable
mmap nwx          readable   readable
mmap xnwx         readable   readable
main              readable   unreadable
libc unmapped?    readable   unreadable
libc mapped       readable   unreadable

ok kettenis, additional help from miod

33 files changed:
sys/arch/alpha/alpha/fp_complete.c
sys/arch/alpha/alpha/locore.s
sys/arch/alpha/alpha/trap.c
sys/arch/alpha/include/cpu.h
sys/arch/alpha/include/pmap.h
sys/arch/amd64/amd64/copy.S
sys/arch/amd64/include/pmap.h
sys/arch/arm/arm/bcopyinout.S
sys/arch/arm/arm/copystr.S
sys/arch/arm/include/pmap.h
sys/arch/hppa/hppa/db_disasm.c
sys/arch/hppa/include/cpu.h
sys/arch/i386/i386/locore.s
sys/arch/i386/include/pmap.h
sys/arch/m88k/include/cpu.h
sys/arch/m88k/m88k/m88110_fp.c
sys/arch/m88k/m88k/subr.S
sys/arch/m88k/m88k/trap.c
sys/arch/mips64/include/pmap.h
sys/arch/mips64/mips64/lcore_access.S
sys/arch/powerpc/include/pmap.h
sys/arch/powerpc/powerpc/pmap.c
sys/arch/sh/include/pmap.h
sys/arch/sh/sh/locore_subr.S
sys/arch/sparc64/include/pmap.h
sys/arch/sparc64/sparc64/db_interface.c
sys/arch/sparc64/sparc64/locore.s
sys/kern/exec_subr.c
sys/kern/kern_sig.c
sys/kern/kern_subr.c
sys/sys/systm.h
sys/uvm/uvm_map.c
sys/uvm/uvm_map.h

index 81b3cbb..1e31516 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: fp_complete.c,v 1.12 2016/03/30 15:39:46 afresh1 Exp $        */
+/*     $OpenBSD: fp_complete.c,v 1.13 2023/01/31 15:18:51 deraadt Exp $        */
 /*     $NetBSD: fp_complete.c,v 1.5 2002/01/18 22:15:56 ross Exp $     */
 
 /*-
@@ -572,7 +572,8 @@ alpha_fp_complete_at(u_long trigger_pc, struct proc *p, u_int64_t *ucode)
        u_int64_t rm, fpcr, orig_fpcr;
        u_int64_t orig_flags, new_flags, changed_flags, md_flags;
 
-       if (__predict_false(copyin((void *)trigger_pc, &inst, sizeof inst))) {
+       if (__predict_false(copyinsn(NULL, (u_int32_t *)trigger_pc,
+           (u_int32_t *)&inst))) {
                this_cannot_happen(6, -1);
                return SIGSEGV;
        }
@@ -651,10 +652,10 @@ alpha_fp_complete(u_long a0, u_long a1, struct proc *p, u_int64_t *ucode)
                ++alpha_shadow.len;
                if (pc < win_begin) {
                        win_begin = pc - TSWINSIZE + 1;
-                       if (copyin(win_begin, tsw, sizeof tsw)) {
+                       if (_copyin(win_begin, tsw, sizeof tsw)) {
                                /* sigh, try to get just one */
                                win_begin = pc;
-                               if (copyin(win_begin, tsw, 4))
+                               if (_copyin(win_begin, tsw, 4))
                                        return SIGSEGV;
                        }
                }
index 5b88d71..0c8f3cd 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: locore.s,v 1.50 2023/01/06 19:10:18 miod Exp $ */
+/* $OpenBSD: locore.s,v 1.51 2023/01/31 15:18:51 deraadt Exp $ */
 /* $NetBSD: locore.s,v 1.94 2001/04/26 03:10:44 ross Exp $ */
 
 /*-
@@ -827,7 +827,7 @@ STATIC_LEAF(copystr, 4)
        RET
        END(copystr)
 
-NESTED(copyinstr, 4, 16, ra, IM_RA|IM_S0, 0)
+NESTED(_copyinstr, 4, 16, ra, IM_RA|IM_S0, 0)
        LDGP(pv)
        ldiq    t0, VM_MAX_ADDRESS              /* make sure that src addr   */
        cmpult  a0, t0, t1                      /* is in user space.         */
@@ -847,7 +847,7 @@ NESTED(copyinstr, 4, 16, ra, IM_RA|IM_S0, 0)
        ldq     s0, (16-16)(sp)                 /* restore s0.               */
        lda     sp, 16(sp)                      /* kill stack frame.         */
        RET                                     /* v0 left over from copystr */
-       END(copyinstr)
+       END(_copyinstr)
 
 NESTED(copyoutstr, 4, 16, ra, IM_RA|IM_S0, 0)
        LDGP(pv)
@@ -914,7 +914,7 @@ LEAF(kcopyerr, 0)
        RET
 END(kcopyerr)
 
-NESTED(copyin, 3, 16, ra, IM_RA|IM_S0, 0)
+NESTED(_copyin, 3, 16, ra, IM_RA|IM_S0, 0)
        LDGP(pv)
        ldiq    t0, VM_MAX_ADDRESS              /* make sure that src addr   */
        cmpult  a0, t0, t1                      /* is in user space.         */
@@ -935,7 +935,7 @@ NESTED(copyin, 3, 16, ra, IM_RA|IM_S0, 0)
        lda     sp, 16(sp)                      /* kill stack frame.         */
        mov     zero, v0                        /* return 0. */
        RET
-       END(copyin)
+       END(_copyin)
 
 NESTED(copyout, 3, 16, ra, IM_RA|IM_S0, 0)
        LDGP(pv)
index e5bfa7b..6a0c1c4 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: trap.c,v 1.105 2023/01/16 05:32:04 deraadt Exp $ */
+/* $OpenBSD: trap.c,v 1.106 2023/01/31 15:18:51 deraadt Exp $ */
 /* $NetBSD: trap.c,v 1.52 2000/05/24 16:48:33 thorpej Exp $ */
 
 /*-
@@ -737,7 +737,7 @@ handle_opdec(p, ucodep)
        p->p_md.md_tf->tf_regs[FRAME_SP] = alpha_pal_rdusp();
 
        inst_pc = memaddr = p->p_md.md_tf->tf_regs[FRAME_PC] - 4;
-       if (copyin((caddr_t)inst_pc, &inst, sizeof (inst)) != 0) {
+       if (copyinsn(p, (u_int32_t *)inst_pc, (u_int32_t *)&inst) != 0) {
                /*
                 * really, this should never happen, but in case it
                 * does we handle it.
index 1d0e638..4a89c79 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: cpu.h,v 1.68 2022/12/10 15:02:29 cheloha Exp $ */
+/* $OpenBSD: cpu.h,v 1.69 2023/01/31 15:18:53 deraadt Exp $ */
 /* $NetBSD: cpu.h,v 1.45 2000/08/21 02:03:12 thorpej Exp $ */
 
 /*-
@@ -443,5 +443,7 @@ intr_restore(u_long s)
        splx((int)s);
 }
 
+#define copyinsn(p, v, ip)     copyin32((v), (ip))
+
 #endif /* _KERNEL */
 #endif /* _MACHINE_CPU_H_ */
index ba70884..6747096 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: pmap.h,v 1.42 2022/09/12 19:35:20 miod Exp $ */
+/* $OpenBSD: pmap.h,v 1.43 2023/01/31 15:18:54 deraadt Exp $ */
 /* $NetBSD: pmap.h,v 1.37 2000/11/19 03:16:35 thorpej Exp $ */
 
 /*-
@@ -176,6 +176,8 @@ void        pmap_do_tlb_shootdown(struct cpu_info *, struct trapframe *);
 
 extern pt_entry_t *VPT;                /* Virtual Page Table */
 
+#define PMAP_CHECK_COPYIN      1
+
 #define        PMAP_STEAL_MEMORY               /* enable pmap_steal_memory() */
 #define PMAP_GROWKERNEL                        /* enable pmap_growkernel() */
 
index b5d8c3b..ae254bf 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: copy.S,v 1.17 2023/01/06 19:10:18 miod Exp $  */
+/*     $OpenBSD: copy.S,v 1.18 2023/01/31 15:18:54 deraadt Exp $       */
 /*     $NetBSD: copy.S,v 1.1 2003/04/26 18:39:26 fvdl Exp $    */
 
 /*
@@ -147,7 +147,7 @@ ENTRY(copyout)
        ret
        lfence
 
-ENTRY(copyin)
+ENTRY(_copyin)
        RETGUARD_SETUP(kcopy, r10)
        movq    CPUVAR(CURPCB),%rax
        pushq   $0
@@ -239,7 +239,7 @@ ENTRY(copyoutstr)
        movl    $ENAMETOOLONG,%eax
        jmp     copystr_return
 
-ENTRY(copyinstr)
+ENTRY(_copyinstr)
        RETGUARD_SETUP(copyoutstr, r10)
        xchgq   %rdi,%rsi
        movq    %rdx,%r8
index 3660f44..c55e06b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pmap.h,v 1.84 2023/01/19 20:17:12 kettenis Exp $      */
+/*     $OpenBSD: pmap.h,v 1.85 2023/01/31 15:18:54 deraadt Exp $       */
 /*     $NetBSD: pmap.h,v 1.1 2003/04/26 18:39:46 fvdl Exp $    */
 
 /*
@@ -420,6 +420,8 @@ void        pmap_flush_cache(vaddr_t, vsize_t);
        pmap_flush_cache(PMAP_DIRECT_MAP(paddr), PAGE_SIZE);            \
 } while (/* CONSTCOND */ 0)
 
+#define PMAP_CHECK_COPYIN      (pg_xo == 0)
+
 #define        PMAP_STEAL_MEMORY       /* enable pmap_steal_memory() */
 #define PMAP_GROWKERNEL                /* turn on pmap_growkernel interface */
 
index 0caaa70..779741f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bcopyinout.S,v 1.10 2022/12/08 01:25:44 guenther Exp $        */
+/*     $OpenBSD: bcopyinout.S,v 1.11 2023/01/31 15:18:54 deraadt Exp $ */
 /*     $NetBSD: bcopyinout.S,v 1.13 2003/10/31 16:54:05 scw Exp $      */
 
 /*
@@ -67,7 +67,7 @@
  * We save/restore r4-r11:
  * r4-r11 are scratch
  */
-ENTRY(copyin)
+ENTRY(_copyin)
        /* Quick exit if length is zero */      
        teq     r2, #0
        moveq   r0, #0
index 422535a..716c6d5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: copystr.S,v 1.11 2023/01/06 19:10:18 miod Exp $       */
+/*     $OpenBSD: copystr.S,v 1.12 2023/01/31 15:18:54 deraadt Exp $    */
 /*     $NetBSD: copystr.S,v 1.8 2002/10/13 14:54:48 bjh21 Exp $        */
 
 /*
@@ -67,7 +67,7 @@
  *
  * Copy string from user space to kernel space
  */
-ENTRY(copyinstr)
+ENTRY(_copyinstr)
        SAVE_REGS
 
        teq     r2, #0x00000000
index eb9ced1..2bf5885 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pmap.h,v 1.52 2023/01/01 19:49:17 miod Exp $  */
+/*     $OpenBSD: pmap.h,v 1.53 2023/01/31 15:18:54 deraadt Exp $       */
 /*     $NetBSD: pmap.h,v 1.76 2003/09/06 09:10:46 rearnsha Exp $       */
 
 /*
@@ -251,6 +251,8 @@ extern struct pmap  kernel_pmap_store;
 void   pmap_remove_all(pmap_t);
 void   pmap_uncache_page(paddr_t, vaddr_t);
 
+#define PMAP_CHECK_COPYIN      1
+
 #define PMAP_GROWKERNEL                /* turn on pmap_growkernel interface */
 
 /* Functions we use internally. */
index 8051c8d..d7b17c9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: db_disasm.c,v 1.23 2022/08/12 08:34:43 jsg Exp $      */
+/*     $OpenBSD: db_disasm.c,v 1.24 2023/01/31 15:18:54 deraadt Exp $  */
 
 /* TODO parse 64bit insns or rewrite */
 
@@ -2314,14 +2314,15 @@ db_disasm(vaddr_t loc, int flag)
        register const struct inst *i;
        register const struct majoropcode *m;
        register u_int ext;
-       int ok, instruct;
+       int ok;
+       uint32_t instruct;
        OFS ofs = loc;
 
        if (loc == PC_REGS(&ddb_regs) && ddb_regs.tf_iir)
                instruct = ddb_regs.tf_iir;
        else if (USERMODE(loc)) {
-               if (copyin((caddr_t)(loc &~ HPPA_PC_PRIV_MASK),
-                   &instruct, sizeof(instruct)))
+               if (copyinsn(NULL, (uint32_t *)(loc &~ HPPA_PC_PRIV_MASK),
+                   &instruct))
                        instruct = 0;
        } else
                instruct = *(int *)loc;
index 4ad87f3..5ccc82f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cpu.h,v 1.98 2023/01/01 19:49:17 miod Exp $   */
+/*     $OpenBSD: cpu.h,v 1.99 2023/01/31 15:18:54 deraadt Exp $        */
 
 /*
  * Copyright (c) 2000-2004 Michael Shalayeff
@@ -303,6 +303,9 @@ struct blink_led {
 
 extern void blink_led_register(struct blink_led *);
 #endif
+
+#define copyinsn(p, v, ip) copyin32((v), (ip))
+
 #endif
 
 #endif /* _MACHINE_CPU_H_ */
index f561c47..df2d034 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: locore.s,v 1.199 2023/01/06 19:10:18 miod Exp $       */
+/*     $OpenBSD: locore.s,v 1.200 2023/01/31 15:18:54 deraadt Exp $    */
 /*     $NetBSD: locore.s,v 1.145 1996/05/03 19:41:19 christos Exp $    */
 
 /*-
@@ -506,10 +506,10 @@ ENTRY(copyout)
        ret
 
 /*
- * copyin(caddr_t from, caddr_t to, size_t len);
+ * _copyin(caddr_t from, caddr_t to, size_t len);
  * Copy len bytes from the user's address space.
  */
-ENTRY(copyin)
+ENTRY(_copyin)
 #ifdef DDB
        pushl   %ebp
        movl    %esp,%ebp
@@ -626,13 +626,13 @@ ENTRY(copyoutstr)
        jmp     copystr_return
 
 /*
- * copyinstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
+ * _copyinstr(caddr_t from, caddr_t to, size_t maxlen, size_t *lencopied);
  * Copy a NUL-terminated string, at most maxlen characters long, from the
  * user's address space.  Return the number of characters copied (including the
  * NUL) in *lencopied.  If the string is too long, return ENAMETOOLONG; else
  * return 0 or EFAULT.
  */
-ENTRY(copyinstr)
+ENTRY(_copyinstr)
 #ifdef DDB
        pushl   %ebp
        movl    %esp,%ebp
index 7873bc7..2ce9335 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pmap.h,v 1.91 2022/08/29 02:58:13 jsg Exp $   */
+/*     $OpenBSD: pmap.h,v 1.92 2023/01/31 15:18:54 deraadt Exp $       */
 /*     $NetBSD: pmap.h,v 1.44 2000/04/24 17:18:18 thorpej Exp $        */
 
 /*
@@ -359,6 +359,8 @@ void pmap_flush_cache(vaddr_t, vsize_t);
 void pmap_flush_page(paddr_t);
 void pmap_flush_page_pae(paddr_t);
 
+#define PMAP_CHECK_COPYIN      1
+
 #define PMAP_GROWKERNEL                /* turn on pmap_growkernel interface */
 
 /*
index 2b313e6..ad2864e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: cpu.h,v 1.71 2022/12/06 00:56:52 cheloha Exp $ */
+/*     $OpenBSD: cpu.h,v 1.72 2023/01/31 15:18:54 deraadt Exp $ */
 /*
  * Copyright (c) 1996 Nivas Madhur
  * Copyright (c) 1992, 1993
@@ -298,5 +298,7 @@ int badaddr(vaddr_t addr, int size);
 void   set_vbr(register_t);
 extern register_t kernel_vbr;
 
+#define copyinsn(p, v, ip) copyin32((v), (ip))
+
 #endif /* _KERNEL */
 #endif /* _M88K_CPU_H_ */
index 11c25d0..9193485 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: m88110_fp.c,v 1.13 2021/03/11 11:16:58 jsg Exp $      */
+/*     $OpenBSD: m88110_fp.c,v 1.14 2023/01/31 15:18:54 deraadt Exp $  */
 
 /*
  * Copyright (c) 2007, Miodrag Vallat.
@@ -97,7 +97,7 @@ m88110_fpu_exception(struct trapframe *frame)
         * Fetch the faulting instruction. This should not fail, if it
         * does, it's probably not your lucky day.
         */
-       if (copyin((void *)fault_addr, &insn, sizeof insn) != 0) {
+       if (copyinsn(p, (u_int32_t *)fault_addr, (u_int32_t *)&insn) != 0) {
                sig = SIGBUS;
                fault_type = BUS_OBJERR;
                goto deliver;
index b209a8f..c3e8588 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr.S,v 1.28 2022/12/06 18:50:59 guenther Exp $  */
+/* $OpenBSD: subr.S,v 1.29 2023/01/31 15:18:54 deraadt Exp $   */
 /*
  * Mach Operating System
  * Copyright (c) 1993-1992 Carnegie Mellon University
@@ -185,7 +185,7 @@ ENTRY(do_xmem_byte) /* do_xmem_byte(address, data, supervisor) */
 
 /*
  * Copy specified amount of data from user space into the kernel
- * copyin(from, to, len)
+ * _copyin(from, to, len)
  *     r2 == from (user source address)
  *     r3 == to (kernel destination address)
  *     r4 == length
@@ -195,7 +195,7 @@ ENTRY(do_xmem_byte) /* do_xmem_byte(address, data, supervisor) */
 #define        DEST    %r3
 #define        LEN     %r4
 
-ENTRY(copyin)
+ENTRY(_copyin)
        /* set up fault handler */
        ldcr    %r5,  CPU
        ld      %r6,  %r5,  CI_CURPCB
@@ -421,7 +421,7 @@ ASLOCAL(copyin32_misaligned)
  * Copy a null terminated string from the user space to the kernel
  * address space.
  *
- * copyinstr(from, to, maxlen, &lencopied)
+ * _copyinstr(from, to, maxlen, &lencopied)
  * r2 == from
  * r3 == to
  * r4 == maxlen
@@ -433,7 +433,7 @@ ASLOCAL(copyin32_misaligned)
 #define        CNT     %r4
 #define        LEN     %r5
 
-ENTRY(copyinstr)
+ENTRY(_copyinstr)
 
        /* setup fault handler */
        ldcr    %r6,  CPU
index fcd512d..0af00c0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: trap.c,v 1.125 2023/01/16 05:32:05 deraadt Exp $      */
+/*     $OpenBSD: trap.c,v 1.126 2023/01/31 15:18:54 deraadt Exp $      */
 /*
  * Copyright (c) 2004, Miodrag Vallat.
  * Copyright (c) 1998 Steve Murphree, Jr.
@@ -535,7 +535,7 @@ user_fault:
                        vaddr_t pc = PC_REGS(&frame->tf_regs);
 
                        /* read break instruction */
-                       copyin((caddr_t)pc, &instr, sizeof(u_int));
+                       copyinsn(p, (u_int32_t *)pc, (u_int32_t *)&instr);
 
                        /* check and see if we got here by accident */
                        if ((p->p_md.md_bp0va != pc &&
@@ -668,8 +668,8 @@ m88110_trap(u_int type, struct trapframe *frame)
                                    (frame->tf_exip + 4) | 1, frame->tf_enip);
                } else {
                        /* copyin here should not fail */
-                       if (copyin((const void *)frame->tf_exip, &instr,
-                           sizeof instr) == 0 &&
+                       if (copyinsn(p, (u_int32_t *)frame->tf_exip,
+                           (u_int32_t *)&instr) == 0 &&
                            instr == 0xf400cc01) {
                                uprintf("mc88110 errata #16, exip 0x%lx enip 0x%lx",
                                    (frame->tf_exip + 4) | 1, frame->tf_enip);
@@ -1075,7 +1075,7 @@ m88110_user_fault:
                        vaddr_t pc = PC_REGS(&frame->tf_regs);
 
                        /* read break instruction */
-                       copyin((caddr_t)pc, &instr, sizeof(u_int));
+                       copyinsn(p, (u_int32_t *)pc, (u_int32_t *)&instr);
 
                        /* check and see if we got here by accident */
                        if ((p->p_md.md_bp0va != pc &&
@@ -1662,7 +1662,7 @@ double_reg_fixup(struct trapframe *frame, int fault)
         */
 
        pc = PC_REGS(&frame->tf_regs);
-       if (copyin((void *)pc, &instr, sizeof(u_int32_t)) != 0)
+       if (copyinsn(NULL, (u_int32_t *)pc, (u_int32_t *)&instr) != 0)
                return SIGSEGV;
 
        switch (instr & 0xfc00ff00) {
index 0352117..c5e2170 100644 (file)
@@ -1,4 +1,4 @@
-/*      $OpenBSD: pmap.h,v 1.52 2023/01/11 03:19:52 visa Exp $ */
+/*      $OpenBSD: pmap.h,v 1.53 2023/01/31 15:18:55 deraadt Exp $ */
 
 /*
  * Copyright (c) 1987 Carnegie-Mellon University
@@ -147,6 +147,9 @@ extern      struct pmap *const kernel_pmap_ptr;
 #define        pmap_wired_count(pmap)          ((pmap)->pm_stats.wired_count)
 #define        pmap_kernel()                   (kernel_pmap_ptr)
 
+extern pt_entry_t pg_ri;
+#define PMAP_CHECK_COPYIN              (pg_ri == 0)
+
 #define        PMAP_STEAL_MEMORY               /* Enable 'stealing' during boot */
 
 #define        PMAP_PREFER
index 4ade78a..bc51fe7 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: lcore_access.S,v 1.33 2022/12/08 01:25:45 guenther Exp $ */
+/*     $OpenBSD: lcore_access.S,v 1.34 2023/01/31 15:18:55 deraadt Exp $ */
 
 /*
  * Copyright (c) 2001-2003 Opsycon AB  (www.opsycon.se / www.opsycon.com)
@@ -147,13 +147,13 @@ END(mem_zero_page)
  * Copy a null terminated string from the user address space into
  * the kernel address space.
  *
- *     copyinstr(fromaddr, toaddr, maxlength, &lencopied)
+ *     _copyinstr(fromaddr, toaddr, maxlength, &lencopied)
  *             caddr_t fromaddr;
  *             caddr_t toaddr;
  *             u_int maxlength;
  *             u_int *lencopied;
  */
-NON_LEAF(copyinstr, FRAMESZ(CF_SZ), ra)
+NON_LEAF(_copyinstr, FRAMESZ(CF_SZ), ra)
        PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
        .mask   0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
        PTR_S   ra, CF_RA_OFFS(sp)
@@ -171,7 +171,7 @@ NON_LEAF(copyinstr, FRAMESZ(CF_SZ), ra)
        PTR_ADDU sp, sp, FRAMESZ(CF_SZ)
        j       ra
         NOP
-END(copyinstr)
+END(_copyinstr)
 
 /*
  * Copy a null terminated string from the kernel address space into
@@ -205,12 +205,12 @@ END(copyoutstr)
 
 /*
  * Copy specified amount of data from user space into the kernel
- *     copyin(from, to, len)
+ *     _copyin(from, to, len)
  *             caddr_t *from;  (user source address)
  *             caddr_t *to;    (kernel destination address)
  *             unsigned len;
  */
-NON_LEAF(copyin, FRAMESZ(CF_SZ), ra)
+NON_LEAF(_copyin, FRAMESZ(CF_SZ), ra)
        PTR_SUBU sp, sp, FRAMESZ(CF_SZ)
        .mask   0x80000000, (CF_RA_OFFS - FRAMESZ(CF_SZ))
        PTR_S   ra, CF_RA_OFFS(sp)
@@ -228,7 +228,7 @@ NON_LEAF(copyin, FRAMESZ(CF_SZ), ra)
        PTR_ADDU sp, sp, FRAMESZ(CF_SZ)
        j       ra
         move   v0, zero
-END(copyin)
+END(_copyin)
 
 /*
  * Copy specified amount of data from kernel to the user space
index 22a2de6..2d404a2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pmap.h,v 1.62 2023/01/31 01:27:58 gkoehler Exp $      */
+/*     $OpenBSD: pmap.h,v 1.63 2023/01/31 15:18:55 deraadt Exp $       */
 /*     $NetBSD: pmap.h,v 1.1 1996/09/30 16:34:29 ws Exp $      */
 
 /*-
@@ -154,6 +154,8 @@ int reserve_dumppages(caddr_t p);
 #define pmap_unuse_final(p)            /* nothing */
 #define        pmap_remove_holes(vm)           do { /* nothing */ } while (0)
 
+#define PMAP_CHECK_COPYIN      (ppc_proc_is_64b == 0)
+
 #define        PMAP_STEAL_MEMORY
 
 #define PG_PMAP_MOD    PG_PMAP0
index d1b7af7..ee143a4 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pmap.c,v 1.179 2023/01/31 01:27:58 gkoehler Exp $ */
+/*     $OpenBSD: pmap.c,v 1.180 2023/01/31 15:18:55 deraadt Exp $ */
 
 /*
  * Copyright (c) 2015 Martin Pieuchot
@@ -1750,7 +1750,7 @@ pmap_popusr(u_int32_t sr)
 }
 
 int
-copyin(const void *udaddr, void *kaddr, size_t len)
+_copyin(const void *udaddr, void *kaddr, size_t len)
 {
        void *p;
        size_t l;
@@ -1835,7 +1835,7 @@ copyin32(const uint32_t *udaddr, uint32_t *kaddr)
 }
 
 int
-copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
+_copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
 {
        const u_char *uaddr = udaddr;
        u_char *kp    = kaddr;
index 745ddc6..aaa3f51 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: pmap.h,v 1.17 2023/01/01 19:49:17 miod Exp $  */
+/*     $OpenBSD: pmap.h,v 1.18 2023/01/31 15:18:55 deraadt Exp $       */
 /*     $NetBSD: pmap.h,v 1.28 2006/04/10 23:12:11 uwe Exp $    */
 
 /*-
@@ -45,6 +45,8 @@
 #ifdef _KERNEL
 #include <sys/queue.h>
 
+#define PMAP_CHECK_COPYIN      1
+
 #define        PMAP_STEAL_MEMORY
 #define        PMAP_GROWKERNEL
 
index b4691cf..5ee3cd9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: locore_subr.S,v 1.14 2022/12/08 02:11:27 guenther Exp $       */
+/*     $OpenBSD: locore_subr.S,v 1.15 2023/01/31 15:18:55 deraadt Exp $        */
 /*     $NetBSD: locore_subr.S,v 1.28 2006/01/23 22:52:09 uwe Exp $     */
 
 /*
@@ -611,10 +611,10 @@ ENTRY(copyout)
 
 
 /*
- * LINTSTUB: Func: int copyin(const void *usrc, void *kdst, size_t len)
+ * LINTSTUB: Func: int _copyin(const void *usrc, void *kdst, size_t len)
  *     Copy len bytes from the user address space.
  */
-ENTRY(copyin)
+ENTRY(_copyin)
        mov.l   r14,    @-r15
        sts.l   pr,     @-r15
        mov     r15,    r14
@@ -663,7 +663,7 @@ ENTRY(copyin)
        .long   curpcb
 .L_copyin_memcpy:
        .long   memcpy
-       SET_ENTRY_SIZE(copyin)
+       SET_ENTRY_SIZE(_copyin)
 
 
 /*
@@ -743,13 +743,13 @@ ENTRY(copyoutstr)
 
 
 /*
- * LINTSTUB: Func: int copyinstr(const void *src, void *dst, size_t maxlen, size_t *lencopied)
+ * LINTSTUB: Func: int _copyinstr(const void *src, void *dst, size_t maxlen, size_t *lencopied)
  *     Copy a NUL-terminated string, at most maxlen characters long,
  *     from the user address space.  Return the number of characters
  *     copied (including the NUL) in *lencopied.  If the string is
  *     too long, return ENAMETOOLONG; else return 0 or EFAULT.
  */
-ENTRY(copyinstr)
+ENTRY(_copyinstr)
        mov.l   r8,     @-r15
        mov     #EFAULT, r3             /* assume there was a problem */
        mov     r4,     r8
@@ -815,7 +815,7 @@ ENTRY(copyinstr)
        .long   VM_MAXUSER_ADDRESS
 .L_copyinstr_curpcb:
        .long   curpcb
-       SET_ENTRY_SIZE(copyinstr)
+       SET_ENTRY_SIZE(_copyinstr)
 
 /*
  * LINTSTUB: Func: int kcopy(const void *src, void *dst, size_t len)
index acbc71b..f9ee018 100644 (file)
@@ -169,6 +169,8 @@ int pmap_copyinsn(pmap_t, vaddr_t, uint32_t *);
 /* pmap prefer offset in alignment */
 #define PMAP_PREFER_OFFSET(of) ((of) & VA_ALIAS_MASK)
 
+#define PMAP_CHECK_COPYIN      CPU_ISSUN4V
+
 #define PMAP_GROWKERNEL         /* turn on pmap_growkernel interface */
 
 #define        __HAVE_PMAP_COLLECT
index 343cf4e..f5ee296 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: db_interface.c,v 1.60 2022/10/21 18:55:42 miod Exp $  */
+/*     $OpenBSD: db_interface.c,v 1.61 2023/01/31 15:18:55 deraadt Exp $       */
 /*     $NetBSD: db_interface.c,v 1.61 2001/07/31 06:55:47 eeh Exp $ */
 
 /*
@@ -532,7 +532,7 @@ db_read_bytes(vaddr_t addr, size_t size, char *data)
                if (src >= (char *)VM_MIN_KERNEL_ADDRESS)
                        *data++ = probeget((paddr_t)(u_long)src++, ASI_P, 1);
                else
-                       copyin(src++, data++, sizeof(u_char));
+                       _copyin(src++, data++, sizeof(u_char));
        }
 }
 
index 891eeb2..a3cdb66 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: locore.s,v 1.198 2023/01/11 19:57:17 miod Exp $       */
+/*     $OpenBSD: locore.s,v 1.199 2023/01/31 15:18:55 deraadt Exp $    */
 /*     $NetBSD: locore.s,v 1.137 2001/08/13 06:10:10 jdolecek Exp $    */
 
 /*
@@ -5451,12 +5451,12 @@ ENTRY(getfp)
         mov %fp, %o0
 
 /*
- * copyinstr(fromaddr, toaddr, maxlength, &lencopied)
+ * _copyinstr(fromaddr, toaddr, maxlength, &lencopied)
  *
  * Copy a null terminated string from the user address space into
  * the kernel address space.
  */
-ENTRY(copyinstr)
+ENTRY(_copyinstr)
        ! %o0 = fromaddr, %o1 = toaddr, %o2 = maxlen, %o3 = &lencopied
        brgz,pt %o2, 1f                                 ! Make sure len is valid
         nop
@@ -5537,7 +5537,7 @@ Lcsfault:
 
 #define        BCOPY_SMALL     32      /* if < 32, copy by bytes */
 
-ENTRY(copyin)
+ENTRY(_copyin)
 !      flushw                  ! Make sure we don't have stack probs & lose hibits of %o
        GET_CPCB(%o3)
        wr      %g0, ASI_AIUS, %asi
@@ -5711,7 +5711,7 @@ Lcopyin_done:
        wr      %g0, ASI_PRIMARY_NOFAULT, %asi          ! Restore ASI
        retl
         clr    %o0                     ! return 0
-END(copyin)
+END(_copyin)
 
 /*
  * copyout(src, dst, len)
index d444a8b..5407a18 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: exec_subr.c,v 1.64 2022/12/05 23:18:37 deraadt Exp $  */
+/*     $OpenBSD: exec_subr.c,v 1.65 2023/01/31 15:18:56 deraadt Exp $  */
 /*     $NetBSD: exec_subr.c,v 1.9 1994/12/04 03:10:42 mycroft Exp $    */
 
 /*
@@ -215,6 +215,13 @@ vmcmd_map_pagedvn(struct proc *p, struct exec_vmcmd *cmd)
                if (cmd->ev_flags & VMCMD_IMMUTABLE)
                        uvm_map_immutable(&p->p_vmspace->vm_map, cmd->ev_addr,
                            round_page(cmd->ev_addr + cmd->ev_len), 1);
+#ifdef PMAP_CHECK_COPYIN
+               if (PMAP_CHECK_COPYIN &&
+                   ((flags & UVM_FLAG_SYSCALL) ||
+                   ((cmd->ev_flags & VMCMD_IMMUTABLE) && (cmd->ev_prot & PROT_EXEC))))
+                       uvm_map_check_copyin_add(&p->p_vmspace->vm_map,
+                           cmd->ev_addr, round_page(cmd->ev_addr + cmd->ev_len));
+#endif
        }
 
        return (error);
index 38149c1..416cef5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_sig.c,v 1.303 2023/01/02 23:09:48 guenther Exp $ */
+/*     $OpenBSD: kern_sig.c,v 1.304 2023/01/31 15:18:56 deraadt Exp $  */
 /*     $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $   */
 
 /*
@@ -1635,6 +1635,11 @@ coredump(struct proc *p)
 
        atomic_setbits_int(&pr->ps_flags, PS_COREDUMP);
 
+#ifdef PMAP_CHECK_COPYIN
+       /* disable copyin checks, so we can write out text sections if needed */
+       p->p_vmspace->vm_map.check_copyin_count = 0;
+#endif
+
        /* Don't dump if will exceed file size limit. */
        if (USPACE + ptoa(vm->vm_dsize + vm->vm_ssize) >= lim_cur(RLIMIT_CORE))
                return (EFBIG);
index c0e0d40..65bb9b5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_subr.c,v 1.51 2022/08/14 01:58:27 jsg Exp $      */
+/*     $OpenBSD: kern_subr.c,v 1.52 2023/01/31 15:18:56 deraadt Exp $  */
 /*     $NetBSD: kern_subr.c,v 1.15 1996/04/09 17:21:56 ragge Exp $     */
 
 /*
 #include <sys/sched.h>
 #include <sys/malloc.h>
 #include <sys/queue.h>
+#include <uvm/uvm_extern.h>
+
+#ifdef PMAP_CHECK_COPYIN
+
+static inline int check_copyin(struct proc *, const void *, size_t);
+extern int _copyinstr(const void *, void *, size_t, size_t *);
+extern int _copyin(const void *uaddr, void *kaddr, size_t len);
+
+/*
+ * If range overlaps an check_copyin region, return EFAULT
+ */
+static inline int
+check_copyin(struct proc *p, const void *vstart, size_t len)
+{
+       struct vm_map *map = &p->p_vmspace->vm_map;
+       const vaddr_t start = (vaddr_t)vstart;
+       const vaddr_t end = start + len;
+       int i, max;
+
+       /* XXX if the array was sorted, we could shortcut */
+       max = map->check_copyin_count;
+       membar_consumer();
+       for (i = 0; i < max; i++) {
+               vaddr_t s = map->check_copyin[i].start;
+               vaddr_t e = map->check_copyin[i].end;
+               if ((start >= s && start < e) || (end > s && end < e))
+                       return EFAULT;
+       }
+       return (0);
+}
+
+int
+copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done)
+{
+       size_t alen;
+       int error;
+
+       /*
+        * Must do the copyin checks after figuring out the string length,
+        * the buffer size length may cross into another ELF segment
+        */
+       error = _copyinstr(uaddr, kaddr, len, &alen);
+       if (PMAP_CHECK_COPYIN && error == 0)
+               error = check_copyin(curproc, uaddr, alen);
+       if (done)
+               *done = alen;
+       return (error);
+}
+
+int
+copyin(const void *uaddr, void *kaddr, size_t len)
+{
+       int error = 0;
+
+       if (PMAP_CHECK_COPYIN)
+               error = check_copyin(curproc, uaddr, len);
+       if (error == 0)
+               error = _copyin(uaddr, kaddr, len);
+       return (error);
+}
+#endif /* PMAP_CHECK_COPYIN */
 
 int
 uiomove(void *cp, size_t n, struct uio *uio)
index 2052f84..31a5622 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: systm.h,v 1.160 2023/01/06 19:10:18 miod Exp $        */
+/*     $OpenBSD: systm.h,v 1.161 2023/01/31 15:18:56 deraadt Exp $     */
 /*     $NetBSD: systm.h,v 1.50 1996/06/09 04:55:09 briggs Exp $        */
 
 /*-
@@ -203,9 +203,13 @@ void       *memset(void *, int, size_t)
 
 int    copyinstr(const void *, void *, size_t, size_t *)
                __attribute__ ((__bounded__(__string__,2,3)));
+int    _copyinstr(const void *, void *, size_t, size_t *)
+               __attribute__ ((__bounded__(__string__,2,3)));
 int    copyoutstr(const void *, void *, size_t, size_t *);
 int    copyin(const void *, void *, size_t)
                __attribute__ ((__bounded__(__buffer__,2,3)));
+int    _copyin(const void *, void *, size_t)
+               __attribute__ ((__bounded__(__buffer__,2,3)));
 int    copyout(const void *, void *, size_t);
 int    copyin32(const uint32_t *, uint32_t *);
 
index f5c23a6..9ee15ea 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uvm_map.c,v 1.308 2023/01/25 23:42:03 deraadt Exp $   */
+/*     $OpenBSD: uvm_map.c,v 1.309 2023/01/31 15:18:55 deraadt Exp $   */
 /*     $NetBSD: uvm_map.c,v 1.86 2000/11/27 08:40:03 chs Exp $ */
 
 /*
@@ -3472,6 +3472,9 @@ uvmspace_exec(struct proc *p, vaddr_t start, vaddr_t end)
 
                uvmspace_free(ovm);
        }
+#ifdef PMAP_CHECK_COPYIN
+       p->p_vmspace->vm_map.check_copyin_count = 0;    /* disable checks */
+#endif
 
        /* Release dead entries */
        uvm_unmap_detach(&dead_entries, 0);
@@ -4225,6 +4228,39 @@ uvm_map_inherit(struct vm_map *map, vaddr_t start, vaddr_t end,
        return (0);
 }
 
+#ifdef PMAP_CHECK_COPYIN
+static void inline
+check_copyin_add(struct vm_map *map, vaddr_t start, vaddr_t end)
+{
+       if (PMAP_CHECK_COPYIN == 0 ||
+           map->check_copyin_count >= UVM_MAP_CHECK_COPYIN_MAX)
+               return;
+       map->check_copyin[map->check_copyin_count].start = start;
+       map->check_copyin[map->check_copyin_count].end = end;
+       membar_producer();
+       map->check_copyin_count++;
+}
+
+/* 
+ * uvm_map_check_copyin_add: remember regions which are X-only for copyin(),
+ * copyinstr(), uiomove(), and others
+ *
+ * => map must be unlocked
+ */
+int
+uvm_map_check_copyin_add(struct vm_map *map, vaddr_t start, vaddr_t end)
+{
+       if (start > end)
+               return EINVAL;
+       start = MAX(start, map->min_offset);
+       end = MIN(end, map->max_offset);
+       if (start >= end)
+               return 0;
+       check_copyin_add(map, start, end);
+       return (0);
+}
+#endif /* PMAP_CHECK_COPYIN */
+
 /* 
  * uvm_map_syscall: permit system calls for range of addrs in map.
  *
@@ -4258,6 +4294,9 @@ uvm_map_syscall(struct vm_map *map, vaddr_t start, vaddr_t end)
                entry = RBT_NEXT(uvm_map_addr, entry);
        }
 
+#ifdef PMAP_CHECK_COPYIN
+       check_copyin_add(map, start, end);      /* Add libc's text segment */
+#endif
        map->wserial++;
        map->flags |= VM_MAP_SYSCALL_ONCE;
        vm_map_unlock(map);
index fa3e7c9..76e52a2 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: uvm_map.h,v 1.82 2023/01/26 07:44:31 deraadt Exp $    */
+/*     $OpenBSD: uvm_map.h,v 1.83 2023/01/31 15:18:55 deraadt Exp $    */
 /*     $NetBSD: uvm_map.h,v 1.24 2001/02/18 21:19:08 chs Exp $ */
 
 /*
@@ -309,6 +309,12 @@ struct vm_map {
        struct uvm_addr_state   *uaddr_any[4];  /* More selectors. */
        struct uvm_addr_state   *uaddr_brk_stack; /* Brk/stack selector. */
 
+#define UVM_MAP_CHECK_COPYIN_MAX 4     /* main, sigtramp, ld.so, libc.so */
+       struct uvm_check_copyin {
+               vaddr_t         start, end;
+       }                       check_copyin[UVM_MAP_CHECK_COPYIN_MAX];
+       int                     check_copyin_count;
+
        /*
         * XXX struct mutex changes size because of compile options, so
         * place after fields which are inspected by libkvm / procmap(8)
@@ -354,6 +360,7 @@ int         uvm_map_extract(struct vm_map *, vaddr_t, vsize_t,
 struct vm_map *        uvm_map_create(pmap_t, vaddr_t, vaddr_t, int);
 vaddr_t                uvm_map_pie(vaddr_t);
 vaddr_t                uvm_map_hint(struct vmspace *, vm_prot_t, vaddr_t, vaddr_t);
+int            uvm_map_check_copyin_add(struct vm_map *, vaddr_t, vaddr_t);
 int            uvm_map_syscall(struct vm_map *, vaddr_t, vaddr_t);
 int            uvm_map_immutable(struct vm_map *, vaddr_t, vaddr_t, int);
 int            uvm_map_inherit(struct vm_map *, vaddr_t, vaddr_t, vm_inherit_t);