From d62ebcb2023f9bedf18a9581f9e426635774d636 Mon Sep 17 00:00:00 2001 From: deraadt Date: Tue, 31 Jan 2023 15:18:51 +0000 Subject: [PATCH] On systems without xonly mmu hardware-enforcement, we can still mitigate 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 --- sys/arch/alpha/alpha/fp_complete.c | 9 ++-- sys/arch/alpha/alpha/locore.s | 10 ++-- sys/arch/alpha/alpha/trap.c | 4 +- sys/arch/alpha/include/cpu.h | 4 +- sys/arch/alpha/include/pmap.h | 4 +- sys/arch/amd64/amd64/copy.S | 6 +-- sys/arch/amd64/include/pmap.h | 4 +- sys/arch/arm/arm/bcopyinout.S | 4 +- sys/arch/arm/arm/copystr.S | 4 +- sys/arch/arm/include/pmap.h | 4 +- sys/arch/hppa/hppa/db_disasm.c | 9 ++-- sys/arch/hppa/include/cpu.h | 5 +- sys/arch/i386/i386/locore.s | 10 ++-- sys/arch/i386/include/pmap.h | 4 +- sys/arch/m88k/include/cpu.h | 4 +- sys/arch/m88k/m88k/m88110_fp.c | 4 +- sys/arch/m88k/m88k/subr.S | 10 ++-- sys/arch/m88k/m88k/trap.c | 12 ++--- sys/arch/mips64/include/pmap.h | 5 +- sys/arch/mips64/mips64/lcore_access.S | 14 +++--- sys/arch/powerpc/include/pmap.h | 4 +- sys/arch/powerpc/powerpc/pmap.c | 6 +-- sys/arch/sh/include/pmap.h | 4 +- sys/arch/sh/sh/locore_subr.S | 14 +++--- sys/arch/sparc64/include/pmap.h | 2 + sys/arch/sparc64/sparc64/db_interface.c | 4 +- sys/arch/sparc64/sparc64/locore.s | 10 ++-- sys/kern/exec_subr.c | 9 +++- sys/kern/kern_sig.c | 7 ++- sys/kern/kern_subr.c | 63 ++++++++++++++++++++++++- sys/sys/systm.h | 6 ++- sys/uvm/uvm_map.c | 41 +++++++++++++++- sys/uvm/uvm_map.h | 9 +++- 33 files changed, 229 insertions(+), 80 deletions(-) diff --git a/sys/arch/alpha/alpha/fp_complete.c b/sys/arch/alpha/alpha/fp_complete.c index 81b3cbb5941..1e315167382 100644 --- a/sys/arch/alpha/alpha/fp_complete.c +++ b/sys/arch/alpha/alpha/fp_complete.c @@ -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; } } diff --git a/sys/arch/alpha/alpha/locore.s b/sys/arch/alpha/alpha/locore.s index 5b88d712786..0c8f3cd1e64 100644 --- a/sys/arch/alpha/alpha/locore.s +++ b/sys/arch/alpha/alpha/locore.s @@ -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) diff --git a/sys/arch/alpha/alpha/trap.c b/sys/arch/alpha/alpha/trap.c index e5bfa7b7313..6a0c1c481ed 100644 --- a/sys/arch/alpha/alpha/trap.c +++ b/sys/arch/alpha/alpha/trap.c @@ -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. diff --git a/sys/arch/alpha/include/cpu.h b/sys/arch/alpha/include/cpu.h index 1d0e638dae5..4a89c7969fc 100644 --- a/sys/arch/alpha/include/cpu.h +++ b/sys/arch/alpha/include/cpu.h @@ -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_ */ diff --git a/sys/arch/alpha/include/pmap.h b/sys/arch/alpha/include/pmap.h index ba7088437ec..6747096c5a6 100644 --- a/sys/arch/alpha/include/pmap.h +++ b/sys/arch/alpha/include/pmap.h @@ -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() */ diff --git a/sys/arch/amd64/amd64/copy.S b/sys/arch/amd64/amd64/copy.S index b5d8c3bf8f1..ae254bf1587 100644 --- a/sys/arch/amd64/amd64/copy.S +++ b/sys/arch/amd64/amd64/copy.S @@ -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 diff --git a/sys/arch/amd64/include/pmap.h b/sys/arch/amd64/include/pmap.h index 3660f440138..c55e06b77d2 100644 --- a/sys/arch/amd64/include/pmap.h +++ b/sys/arch/amd64/include/pmap.h @@ -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 */ diff --git a/sys/arch/arm/arm/bcopyinout.S b/sys/arch/arm/arm/bcopyinout.S index 0caaa70b9b5..779741f9cf7 100644 --- a/sys/arch/arm/arm/bcopyinout.S +++ b/sys/arch/arm/arm/bcopyinout.S @@ -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 diff --git a/sys/arch/arm/arm/copystr.S b/sys/arch/arm/arm/copystr.S index 422535a8680..716c6d55665 100644 --- a/sys/arch/arm/arm/copystr.S +++ b/sys/arch/arm/arm/copystr.S @@ -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 diff --git a/sys/arch/arm/include/pmap.h b/sys/arch/arm/include/pmap.h index eb9ced1a9be..2bf588563fe 100644 --- a/sys/arch/arm/include/pmap.h +++ b/sys/arch/arm/include/pmap.h @@ -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. */ diff --git a/sys/arch/hppa/hppa/db_disasm.c b/sys/arch/hppa/hppa/db_disasm.c index 8051c8d7b4b..d7b17c9a879 100644 --- a/sys/arch/hppa/hppa/db_disasm.c +++ b/sys/arch/hppa/hppa/db_disasm.c @@ -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; diff --git a/sys/arch/hppa/include/cpu.h b/sys/arch/hppa/include/cpu.h index 4ad87f3a2f1..5ccc82f4890 100644 --- a/sys/arch/hppa/include/cpu.h +++ b/sys/arch/hppa/include/cpu.h @@ -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_ */ diff --git a/sys/arch/i386/i386/locore.s b/sys/arch/i386/i386/locore.s index f561c47a7cb..df2d034b936 100644 --- a/sys/arch/i386/i386/locore.s +++ b/sys/arch/i386/i386/locore.s @@ -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 diff --git a/sys/arch/i386/include/pmap.h b/sys/arch/i386/include/pmap.h index 7873bc79fd9..2ce9335ba5b 100644 --- a/sys/arch/i386/include/pmap.h +++ b/sys/arch/i386/include/pmap.h @@ -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 */ /* diff --git a/sys/arch/m88k/include/cpu.h b/sys/arch/m88k/include/cpu.h index 2b313e6b80f..ad2864e16cf 100644 --- a/sys/arch/m88k/include/cpu.h +++ b/sys/arch/m88k/include/cpu.h @@ -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_ */ diff --git a/sys/arch/m88k/m88k/m88110_fp.c b/sys/arch/m88k/m88k/m88110_fp.c index 11c25d01570..91934857dab 100644 --- a/sys/arch/m88k/m88k/m88110_fp.c +++ b/sys/arch/m88k/m88k/m88110_fp.c @@ -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; diff --git a/sys/arch/m88k/m88k/subr.S b/sys/arch/m88k/m88k/subr.S index b209a8fd9e8..c3e85883db1 100644 --- a/sys/arch/m88k/m88k/subr.S +++ b/sys/arch/m88k/m88k/subr.S @@ -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 diff --git a/sys/arch/m88k/m88k/trap.c b/sys/arch/m88k/m88k/trap.c index fcd512d3d83..0af00c0a7c8 100644 --- a/sys/arch/m88k/m88k/trap.c +++ b/sys/arch/m88k/m88k/trap.c @@ -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) { diff --git a/sys/arch/mips64/include/pmap.h b/sys/arch/mips64/include/pmap.h index 0352117d422..c5e2170af11 100644 --- a/sys/arch/mips64/include/pmap.h +++ b/sys/arch/mips64/include/pmap.h @@ -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 diff --git a/sys/arch/mips64/mips64/lcore_access.S b/sys/arch/mips64/mips64/lcore_access.S index 4ade78a7e10..bc51fe76cb4 100644 --- a/sys/arch/mips64/mips64/lcore_access.S +++ b/sys/arch/mips64/mips64/lcore_access.S @@ -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 diff --git a/sys/arch/powerpc/include/pmap.h b/sys/arch/powerpc/include/pmap.h index 22a2de62b10..2d404a2cbf9 100644 --- a/sys/arch/powerpc/include/pmap.h +++ b/sys/arch/powerpc/include/pmap.h @@ -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 diff --git a/sys/arch/powerpc/powerpc/pmap.c b/sys/arch/powerpc/powerpc/pmap.c index d1b7af7b329..ee143a4de5e 100644 --- a/sys/arch/powerpc/powerpc/pmap.c +++ b/sys/arch/powerpc/powerpc/pmap.c @@ -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; diff --git a/sys/arch/sh/include/pmap.h b/sys/arch/sh/include/pmap.h index 745ddc649cb..aaa3f519447 100644 --- a/sys/arch/sh/include/pmap.h +++ b/sys/arch/sh/include/pmap.h @@ -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 +#define PMAP_CHECK_COPYIN 1 + #define PMAP_STEAL_MEMORY #define PMAP_GROWKERNEL diff --git a/sys/arch/sh/sh/locore_subr.S b/sys/arch/sh/sh/locore_subr.S index b4691cfe87b..5ee3cd907a5 100644 --- a/sys/arch/sh/sh/locore_subr.S +++ b/sys/arch/sh/sh/locore_subr.S @@ -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) diff --git a/sys/arch/sparc64/include/pmap.h b/sys/arch/sparc64/include/pmap.h index acbc71b7be3..f9ee018f8a9 100644 --- a/sys/arch/sparc64/include/pmap.h +++ b/sys/arch/sparc64/include/pmap.h @@ -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 diff --git a/sys/arch/sparc64/sparc64/db_interface.c b/sys/arch/sparc64/sparc64/db_interface.c index 343cf4ea59f..f5ee2964d00 100644 --- a/sys/arch/sparc64/sparc64/db_interface.c +++ b/sys/arch/sparc64/sparc64/db_interface.c @@ -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)); } } diff --git a/sys/arch/sparc64/sparc64/locore.s b/sys/arch/sparc64/sparc64/locore.s index 891eeb2aef6..a3cdb66a6c1 100644 --- a/sys/arch/sparc64/sparc64/locore.s +++ b/sys/arch/sparc64/sparc64/locore.s @@ -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) diff --git a/sys/kern/exec_subr.c b/sys/kern/exec_subr.c index d444a8bbb25..5407a18cf66 100644 --- a/sys/kern/exec_subr.c +++ b/sys/kern/exec_subr.c @@ -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); diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index 38149c19cc8..416cef58181 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -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); diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c index c0e0d401a81..65bb9b5fa6c 100644 --- a/sys/kern/kern_subr.c +++ b/sys/kern/kern_subr.c @@ -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 $ */ /* @@ -43,6 +43,67 @@ #include #include #include +#include + +#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) diff --git a/sys/sys/systm.h b/sys/sys/systm.h index 2052f845c15..31a5622bdf4 100644 --- a/sys/sys/systm.h +++ b/sys/sys/systm.h @@ -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 *); diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c index f5c23a642b9..9ee15eaab94 100644 --- a/sys/uvm/uvm_map.c +++ b/sys/uvm/uvm_map.c @@ -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); diff --git a/sys/uvm/uvm_map.h b/sys/uvm/uvm_map.h index fa3e7c9de0c..76e52a2e7a0 100644 --- a/sys/uvm/uvm_map.h +++ b/sys/uvm/uvm_map.h @@ -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); -- 2.20.1