diff options
36 files changed, 482 insertions, 76 deletions
diff --git a/lib/libpthread/man/pthread_attr_setstack.3 b/lib/libpthread/man/pthread_attr_setstack.3 index 306dbdae8fd..ea622633cfb 100644 --- a/lib/libpthread/man/pthread_attr_setstack.3 +++ b/lib/libpthread/man/pthread_attr_setstack.3 @@ -1,9 +1,9 @@ -.\" $OpenBSD: pthread_attr_setstack.3,v 1.4 2013/06/05 03:44:50 tedu Exp $ +.\" $OpenBSD: pthread_attr_setstack.3,v 1.5 2018/04/12 17:13:34 deraadt Exp $ .\" Manual page derived from TOG's UNIX98 documentation. .\" .\" David Leonard, 2000. Public Domain. .\" -.Dd $Mdocdate: June 5 2013 $ +.Dd $Mdocdate: April 12 2018 $ .Dt PTHREAD_ATTR_SETSTACK 3 .Os .Sh NAME @@ -39,6 +39,18 @@ and the size of the storage shall be bytes. The stacksize shall be at least .Dv PTHREAD_STACK_MIN . +.Pp +On +.Ox +the provided stack must be page-aligned. +It will be replaced (meaning zeroed) with a new +.Ar MAP_ANON | Ar MAP_STACK +mapping. +It is recommended that the initial mapping be allocated using +an allocator which has a matching deallocator that discards whole +pages, to clear the +.Ar MAP_STACK +attribute afterwards. .Sh RETURN VALUES Upon successful completion, .Fn pthread_attr_setstack diff --git a/lib/libpthread/man/pthread_attr_setstackaddr.3 b/lib/libpthread/man/pthread_attr_setstackaddr.3 index 18b8db4b580..0c464bbf429 100644 --- a/lib/libpthread/man/pthread_attr_setstackaddr.3 +++ b/lib/libpthread/man/pthread_attr_setstackaddr.3 @@ -1,9 +1,9 @@ -.\" $OpenBSD: pthread_attr_setstackaddr.3,v 1.11 2013/06/05 03:44:50 tedu Exp $ +.\" $OpenBSD: pthread_attr_setstackaddr.3,v 1.12 2018/04/12 17:13:34 deraadt Exp $ .\" Manual page derived from TOG's UNIX98 documentation. .\" .\" David Leonard, 2000. Public Domain. .\" -.Dd $Mdocdate: June 5 2013 $ +.Dd $Mdocdate: April 12 2018 $ .Dt PTHREAD_ATTR_SETSTACKADDR 3 .Os .Sh NAME @@ -34,6 +34,17 @@ attribute specifies the location of storage to be used for the created thread's stack. The size of the storage is at least .Dv PTHREAD_STACK_MIN . +.Pp +On +.Ox +the stack must have been allocated using +.Xr mmap +with the +.Va MAP_STACK +attribute. +Otherwise, use of the stack will cause SIGABRT faults. +.Xr pthread_attr_setstack 3 +can avoid this problem because it knows the size of the stack to remap. .Sh RETURN VALUES Upon successful completion, .Fn pthread_attr_setstackaddr diff --git a/sys/arch/alpha/alpha/machdep.c b/sys/arch/alpha/alpha/machdep.c index a4f9a41cd7f..a4ff49d2e6b 100644 --- a/sys/arch/alpha/alpha/machdep.c +++ b/sys/arch/alpha/alpha/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.183 2017/12/30 20:46:59 guenther Exp $ */ +/* $OpenBSD: machdep.c,v 1.184 2018/04/12 17:13:41 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.210 2000/06/01 17:12:38 thorpej Exp $ */ /*- @@ -1414,8 +1414,9 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, */ if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(oldsp) && (psp->ps_sigonstack & sigmask(sig))) - scp = (struct sigcontext *)(p->p_sigstk.ss_sp + - p->p_sigstk.ss_size - rndfsize); + scp = (struct sigcontext *) + (trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size) + - rndfsize); else scp = (struct sigcontext *)(oldsp - rndfsize); diff --git a/sys/arch/alpha/alpha/trap.c b/sys/arch/alpha/alpha/trap.c index 2fee1864859..2dce18bcb26 100644 --- a/sys/arch/alpha/alpha/trap.c +++ b/sys/arch/alpha/alpha/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.84 2018/04/09 04:11:02 deraadt Exp $ */ +/* $OpenBSD: trap.c,v 1.85 2018/04/12 17:13:41 deraadt Exp $ */ /* $NetBSD: trap.c,v 1.52 2000/05/24 16:48:33 thorpej Exp $ */ /*- @@ -242,8 +242,26 @@ trap(a0, a1, a2, entry, framep) framep->tf_regs[FRAME_SP] = alpha_pal_rdusp(); user = (framep->tf_regs[FRAME_PS] & ALPHA_PSL_USERMODE) != 0; if (user) { + vaddr_t sp; + p->p_md.md_tf = framep; refreshcreds(p); + + sp = PROC_STACK(p); + if (p->p_vmspace->vm_map.serial != p->p_spserial || + p->p_spstart == 0 || sp < p->p_spstart || + sp >= p->p_spend) { + KERNEL_LOCK(); + if (!uvm_map_check_stack_range(p, sp)) { + printf("trap [%s]%d/%d type %d: sp %lx not inside %lx-%lx\n", + p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid, + 0, sp, p->p_spstart, p->p_spend); + sv.sival_ptr = (void *)PROC_PC(p); + trapsignal(p, SIGSEGV, entry, SEGV_ACCERR, sv); + } + + KERNEL_UNLOCK(); + } } switch (entry) { diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index b05455ab943..8810f71dcb8 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.240 2018/03/29 01:21:02 guenther Exp $ */ +/* $OpenBSD: machdep.c,v 1.241 2018/04/12 17:13:43 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.3 2003/05/07 22:58:18 fvdl Exp $ */ /*- @@ -593,7 +593,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, /* Allocate space for the signal handler context. */ if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(tf->tf_rsp) && (psp->ps_sigonstack & sigmask(sig))) - sp = (register_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size; + sp = trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size); else sp = tf->tf_rsp - 128; diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c index dc2d115c207..418395b54b7 100644 --- a/sys/arch/amd64/amd64/trap.c +++ b/sys/arch/amd64/amd64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.64 2018/02/21 19:24:15 guenther Exp $ */ +/* $OpenBSD: trap.c,v 1.65 2018/04/12 17:13:43 deraadt Exp $ */ /* $NetBSD: trap.c,v 1.2 2003/05/04 23:51:56 fvdl Exp $ */ /*- @@ -175,9 +175,28 @@ trap(struct trapframe *frame) #endif if (!KERNELMODE(frame->tf_cs, frame->tf_rflags)) { + vaddr_t sp; + type |= T_USER; p->p_md.md_regs = frame; refreshcreds(p); + + sp = PROC_STACK(p); + if (p->p_vmspace->vm_map.serial != p->p_spserial || + p->p_spstart == 0 || sp < p->p_spstart || + sp >= p->p_spend) { + KERNEL_LOCK(); + if (!uvm_map_check_stack_range(p, sp)) { + printf("trap [%s]%d/%d type %d: sp %lx not inside %lx-%lx\n", + p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid, + (int)frame->tf_trapno, sp, p->p_spstart, p->p_spend); + sv.sival_ptr = (void *)PROC_PC(p); + trapsignal(p, SIGSEGV, type & ~T_USER, + SEGV_ACCERR, sv); + } + + KERNEL_UNLOCK(); + } } switch (type) { diff --git a/sys/arch/arm/arm/fault.c b/sys/arch/arm/arm/fault.c index 8ece22e083b..c69f5ea9439 100644 --- a/sys/arch/arm/arm/fault.c +++ b/sys/arch/arm/arm/fault.c @@ -1,4 +1,4 @@ -/* $OpenBSD: fault.c,v 1.32 2018/01/26 16:22:19 kettenis Exp $ */ +/* $OpenBSD: fault.c,v 1.33 2018/04/12 17:13:43 deraadt Exp $ */ /* $NetBSD: fault.c,v 1.46 2004/01/21 15:39:21 skrll Exp $ */ /* @@ -237,8 +237,26 @@ data_abort_handler(trapframe_t *tf) */ if (user) { + vaddr_t sp; + p->p_addr->u_pcb.pcb_tf = tf; refreshcreds(p); + + sp = PROC_STACK(p); + if (p->p_vmspace->vm_map.serial != p->p_spserial || + p->p_spstart == 0 || sp < p->p_spstart || + sp >= p->p_spend) { + KERNEL_LOCK(); + if (!uvm_map_check_stack_range(p, sp)) { + printf("trap [%s]%d/%d type %d: sp %lx not inside %lx-%lx\n", + p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid, + 0, sp, p->p_spstart, p->p_spend); + + sv.sival_ptr = (void *)PROC_PC(p); + trapsignal(p, SIGSEGV, 0, SEGV_ACCERR, sv); + } + KERNEL_UNLOCK(); + } } /* diff --git a/sys/arch/arm/arm/sig_machdep.c b/sys/arch/arm/arm/sig_machdep.c index a0655e1bab1..8808158457a 100644 --- a/sys/arch/arm/arm/sig_machdep.c +++ b/sys/arch/arm/arm/sig_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sig_machdep.c,v 1.15 2017/03/12 17:57:12 kettenis Exp $ */ +/* $OpenBSD: sig_machdep.c,v 1.16 2018/04/12 17:13:43 deraadt Exp $ */ /* $NetBSD: sig_machdep.c,v 1.22 2003/10/08 00:28:41 thorpej Exp $ */ /* @@ -58,6 +58,8 @@ #include <machine/pcb.h> #include <arm/cpufunc.h> +#include <uvm/uvm_extern.h> + static __inline struct trapframe * process_frame(struct proc *p) { @@ -87,8 +89,8 @@ sendsig(sig_t catcher, int sig, int returnmask, u_long code, int type, /* Allocate space for the signal handler context. */ if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(tf->tf_usr_sp) && (psp->ps_sigonstack & sigmask(sig))) - fp = (struct sigframe *)((caddr_t)p->p_sigstk.ss_sp + - p->p_sigstk.ss_size); + fp = (struct sigframe *) + trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size); else fp = (struct sigframe *)tf->tf_usr_sp; diff --git a/sys/arch/arm64/arm64/ast.c b/sys/arch/arm64/arm64/ast.c index 240d6cc5355..dc5586ff085 100644 --- a/sys/arch/arm64/arm64/ast.c +++ b/sys/arch/arm64/arm64/ast.c @@ -1,4 +1,4 @@ -/* $OpenBSD: ast.c,v 1.4 2017/09/08 05:36:51 deraadt Exp $ */ +/* $OpenBSD: ast.c,v 1.5 2018/04/12 17:13:43 deraadt Exp $ */ /* * Copyright (c) 2015 Dale Rahn <drahn@dalerahn.com> * @@ -18,7 +18,10 @@ #include <sys/param.h> #include <sys/systm.h> #include <sys/proc.h> +#include <sys/signalvar.h> +#include <sys/proc.h> #include <sys/user.h> +#include <sys/signal.h> #include <sys/syscall.h> #include <sys/syscall_mi.h> #include <machine/pcb.h> diff --git a/sys/arch/arm64/arm64/sig_machdep.c b/sys/arch/arm64/arm64/sig_machdep.c index 739544a5424..dcd0e38c0d6 100644 --- a/sys/arch/arm64/arm64/sig_machdep.c +++ b/sys/arch/arm64/arm64/sig_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sig_machdep.c,v 1.4 2017/08/08 21:52:41 drahn Exp $ */ +/* $OpenBSD: sig_machdep.c,v 1.5 2018/04/12 17:13:43 deraadt Exp $ */ /* * Copyright (c) 1990 The Regents of the University of California. @@ -78,6 +78,8 @@ #include <machine/frame.h> #include <machine/pcb.h> +#include <uvm/uvm_extern.h> + static __inline struct trapframe * process_frame(struct proc *p) { @@ -109,8 +111,8 @@ sendsig(sig_t catcher, int sig, int returnmask, u_long code, int type, /* Allocate space for the signal handler context. */ if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(tf->tf_sp) && (psp->ps_sigonstack & sigmask(sig))) - fp = (struct sigframe *)((caddr_t)p->p_sigstk.ss_sp + - p->p_sigstk.ss_size); + fp = (struct sigframe *) + trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size); else fp = (struct sigframe *)tf->tf_sp; diff --git a/sys/arch/arm64/arm64/trap.c b/sys/arch/arm64/arm64/trap.c index c655e5e6607..6e493a4e15f 100644 --- a/sys/arch/arm64/arm64/trap.c +++ b/sys/arch/arm64/arm64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.18 2018/04/09 22:21:05 kettenis Exp $ */ +/* $OpenBSD: trap.c,v 1.19 2018/04/12 17:13:43 deraadt Exp $ */ /*- * Copyright (c) 2014 Andrew Turner * All rights reserved. @@ -225,6 +225,7 @@ do_el0_sync(struct trapframe *frame) union sigval sv; uint32_t exception; uint64_t esr, far; + vaddr_t sp; esr = READ_SPECIALREG(esr_el1); exception = ESR_ELx_EXCEPTION(esr); @@ -235,6 +236,21 @@ do_el0_sync(struct trapframe *frame) p->p_addr->u_pcb.pcb_tf = frame; refreshcreds(p); + sp = PROC_STACK(p); + if (p->p_vmspace->vm_map.serial != p->p_spserial || + p->p_spstart == 0 || sp < p->p_spstart || + sp >= p->p_spend) { + KERNEL_LOCK(); + if (!uvm_map_check_stack_range(p, sp)) { + printf("trap [%s]%d/%d type %d: sp %lx not inside %lx-%lx\n", + p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid, + exception, sp, p->p_spstart, p->p_spend); + sv.sival_ptr = (void *)PROC_PC(p); + trapsignal(p, SIGSEGV, exception, SEGV_ACCERR, sv); + } + KERNEL_UNLOCK(); + } + switch(exception) { case EXCP_UNKNOWN: vfp_save(); diff --git a/sys/arch/hppa/hppa/machdep.c b/sys/arch/hppa/hppa/machdep.c index 3cbd49e0e02..3f9b5f2ab77 100644 --- a/sys/arch/hppa/hppa/machdep.c +++ b/sys/arch/hppa/hppa/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.250 2017/12/30 20:46:59 guenther Exp $ */ +/* $OpenBSD: machdep.c,v 1.251 2018/04/12 17:13:43 deraadt Exp $ */ /* * Copyright (c) 1999-2003 Michael Shalayeff @@ -1224,7 +1224,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, */ if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(tf->tf_sp) && (psp->ps_sigonstack & sigmask(sig))) - scp = (register_t)p->p_sigstk.ss_sp; + scp = round_page((vaddr_t)p->p_sigstk.ss_sp); else scp = (tf->tf_sp + 63) & ~63; diff --git a/sys/arch/hppa/hppa/trap.c b/sys/arch/hppa/hppa/trap.c index b58f2c9158d..4769647a5d6 100644 --- a/sys/arch/hppa/hppa/trap.c +++ b/sys/arch/hppa/hppa/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.142 2017/07/22 15:20:11 kettenis Exp $ */ +/* $OpenBSD: trap.c,v 1.143 2018/04/12 17:13:43 deraadt Exp $ */ /* * Copyright (c) 1998-2004 Michael Shalayeff @@ -213,9 +213,29 @@ trap(int type, struct trapframe *frame) mtctl(frame->tf_eiem, CR_EIEM); } - if (type & T_USER) + if (type & T_USER) { + vaddr_t sp; + refreshcreds(p); + //sp = frame->tf_sp; + sp = PROC_STACK(p); + if (p->p_vmspace->vm_map.serial != p->p_spserial || + p->p_spstart == 0 || sp < p->p_spstart || + sp >= p->p_spend) { + KERNEL_LOCK(); + if (!uvm_map_check_stack_range(p, sp)) { + printf("trap [%s]%d/%d type %d: sp %lx not inside %lx-%lx\n", + p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid, + type & ! ~T_USER, sp, p->p_spstart, p->p_spend); + sv.sival_ptr = (void *)PROC_PC(p); + trapsignal(p, SIGSEGV, type & ~T_USER, + SEGV_ACCERR, sv); + } + KERNEL_UNLOCK(); + } + } + switch (type) { case T_NONEXIST: case T_NONEXIST | T_USER: diff --git a/sys/arch/i386/i386/machdep.c b/sys/arch/i386/i386/machdep.c index 14f8a48bd8e..6f7c5d4fca1 100644 --- a/sys/arch/i386/i386/machdep.c +++ b/sys/arch/i386/i386/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.615 2018/04/11 15:44:08 bluhm Exp $ */ +/* $OpenBSD: machdep.c,v 1.616 2018/04/12 17:13:43 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.214 1996/11/10 03:16:17 thorpej Exp $ */ /*- @@ -2401,7 +2401,7 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, */ if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(tf->tf_esp) && (psp->ps_sigonstack & sigmask(sig))) - sp = (long)p->p_sigstk.ss_sp + p->p_sigstk.ss_size; + sp = trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size); else sp = tf->tf_esp; diff --git a/sys/arch/i386/i386/trap.c b/sys/arch/i386/i386/trap.c index c801739197b..046cbc9e274 100644 --- a/sys/arch/i386/i386/trap.c +++ b/sys/arch/i386/i386/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.136 2017/10/04 17:41:01 deraadt Exp $ */ +/* $OpenBSD: trap.c,v 1.137 2018/04/12 17:13:43 deraadt Exp $ */ /* $NetBSD: trap.c,v 1.95 1996/05/05 06:50:02 mycroft Exp $ */ /*- @@ -154,9 +154,27 @@ trap(struct trapframe *frame) #endif if (!KERNELMODE(frame->tf_cs, frame->tf_eflags)) { + vaddr_t sp; + type |= T_USER; p->p_md.md_regs = frame; refreshcreds(p); + + sp = PROC_STACK(p); + if (p->p_vmspace->vm_map.serial != p->p_spserial || + p->p_spstart == 0 || sp < p->p_spstart || + sp >= p->p_spend) { + KERNEL_LOCK(); + if (!uvm_map_check_stack_range(p, sp)) { + printf("trap [%s]%d/%d type %d: sp %lx not inside %lx-%lx\n", + p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid, + (int)frame->tf_trapno, sp, p->p_spstart, p->p_spend); + sv.sival_ptr = (void *)PROC_PC(p); + trapsignal(p, SIGSEGV, type & ~T_USER, + SEGV_ACCERR, sv); + } + KERNEL_UNLOCK(); + } } switch (type) { diff --git a/sys/arch/m88k/m88k/sig_machdep.c b/sys/arch/m88k/m88k/sig_machdep.c index 534b173b712..7b9766ab7b5 100644 --- a/sys/arch/m88k/m88k/sig_machdep.c +++ b/sys/arch/m88k/m88k/sig_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sig_machdep.c,v 1.27 2016/10/08 23:31:57 guenther Exp $ */ +/* $OpenBSD: sig_machdep.c,v 1.28 2018/04/12 17:13:43 deraadt Exp $ */ /* * Copyright (c) 2014 Miodrag Vallat. * @@ -128,7 +128,8 @@ sendsig(sig_t catcher, int sig, int mask, unsigned long code, int type, if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(tf->tf_r[31]) && (psp->ps_sigonstack & sigmask(sig))) { addr = local_stack_frame(tf, - (vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size, fsize); + trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size), + fsize); } else addr = local_stack_frame(tf, tf->tf_r[31], fsize); diff --git a/sys/arch/macppc/macppc/machdep.c b/sys/arch/macppc/macppc/machdep.c index 6aaae3cb1cb..1470b2a78df 100644 --- a/sys/arch/macppc/macppc/machdep.c +++ b/sys/arch/macppc/macppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.182 2017/12/11 05:27:40 deraadt Exp $ */ +/* $OpenBSD: machdep.c,v 1.183 2018/04/12 17:13:43 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -461,8 +461,8 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(tf->fixreg[1]) && (psp->ps_sigonstack & sigmask(sig))) - fp = (struct sigframe *)(p->p_sigstk.ss_sp - + p->p_sigstk.ss_size); + fp = (struct sigframe *) + trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size); else fp = (struct sigframe *)tf->fixreg[1]; diff --git a/sys/arch/mips64/mips64/sendsig.c b/sys/arch/mips64/mips64/sendsig.c index 3e6ebfd02e8..38b8324aa22 100644 --- a/sys/arch/mips64/mips64/sendsig.c +++ b/sys/arch/mips64/mips64/sendsig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sendsig.c,v 1.27 2016/05/21 00:56:43 deraadt Exp $ */ +/* $OpenBSD: sendsig.c,v 1.28 2018/04/12 17:13:43 deraadt Exp $ */ /* * Copyright (c) 1990 The Regents of the University of California. @@ -121,8 +121,9 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, fsize -= sizeof(siginfo_t); if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(regs->sp) && (psp->ps_sigonstack & sigmask(sig))) - fp = (struct sigframe *)(p->p_sigstk.ss_sp + - p->p_sigstk.ss_size - fsize); + fp = (struct sigframe *) + (trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size) + - fsize); else fp = (struct sigframe *)(regs->sp - fsize); /* diff --git a/sys/arch/mips64/mips64/trap.c b/sys/arch/mips64/mips64/trap.c index 75f6c1360cd..4ffa78973cf 100644 --- a/sys/arch/mips64/mips64/trap.c +++ b/sys/arch/mips64/mips64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.130 2017/09/02 15:56:29 visa Exp $ */ +/* $OpenBSD: trap.c,v 1.131 2018/04/12 17:13:43 deraadt Exp $ */ /* * Copyright (c) 1988 University of Utah. @@ -251,9 +251,30 @@ trap(struct trapframe *trapframe) } #endif - if (type & T_USER) + if (type & T_USER) { + vaddr_t sp; + refreshcreds(p); + sp = trapframe->sp; + if (p->p_vmspace->vm_map.serial != p->p_spserial || + p->p_spstart == 0 || sp < p->p_spstart || + sp >= p->p_spend) { + KERNEL_LOCK(); + if (!uvm_map_check_stack_range(p, sp)) { + union sigval sv; + + printf("trap [%s]%d/%d type %d: sp %lx not inside %lx-%lx\n", + p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid, type, + sp, p->p_spstart, p->p_spend); + + sv.sival_ptr = (void *)trapframe->pc; + trapsignal(p, SIGSEGV, 0, SEGV_ACCERR, sv); + } + KERNEL_UNLOCK(); + } + } + itsa(trapframe, ci, p, type); if (type & T_USER) diff --git a/sys/arch/powerpc/powerpc/trap.c b/sys/arch/powerpc/powerpc/trap.c index 5974f88b802..564cdf2f640 100644 --- a/sys/arch/powerpc/powerpc/trap.c +++ b/sys/arch/powerpc/powerpc/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.106 2016/12/20 12:08:01 jsg Exp $ */ +/* $OpenBSD: trap.c,v 1.107 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: trap.c,v 1.3 1996/10/13 03:31:37 christos Exp $ */ /* @@ -234,8 +234,26 @@ trap(struct trapframe *frame) db_expr_t offset; if (frame->srr1 & PSL_PR) { + vaddr_t sp; + type |= EXC_USER; refreshcreds(p); + + sp = PROC_STACK(p); + if (p->p_vmspace->vm_map.serial != p->p_spserial || + p->p_spstart == 0 || sp < p->p_spstart || + sp >= p->p_spend) { + KERNEL_LOCK(); + if (!uvm_map_check_stack_range(p, sp)) { + printf("trap [%s]%d/%d type %d: sp %lx not inside %lx-%lx\n", + p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid, + type, sp, p->p_spstart, p->p_spend); + sv.sival_ptr = (void *)PROC_PC(p); + trapsignal(p, SIGSEGV, type, SEGV_ACCERR, sv); + } + + KERNEL_UNLOCK(); + } } switch (type) { diff --git a/sys/arch/sh/sh/sh_machdep.c b/sys/arch/sh/sh/sh_machdep.c index ec1c393a77d..218db7f2e75 100644 --- a/sys/arch/sh/sh/sh_machdep.c +++ b/sys/arch/sh/sh/sh_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sh_machdep.c,v 1.46 2016/05/21 00:56:44 deraadt Exp $ */ +/* $OpenBSD: sh_machdep.c,v 1.47 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: sh3_machdep.c,v 1.59 2006/03/04 01:13:36 uwe Exp $ */ /* @@ -460,8 +460,8 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(p->p_md.md_regs->tf_r15) && (psp->ps_sigonstack & sigmask(sig))) - fp = (struct sigframe *)((vaddr_t)p->p_sigstk.ss_sp + - p->p_sigstk.ss_size); + fp = (struct sigframe *) + trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size); else fp = (void *)p->p_md.md_regs->tf_r15; --fp; diff --git a/sys/arch/socppc/socppc/machdep.c b/sys/arch/socppc/socppc/machdep.c index bf0b0228074..830a2e24307 100644 --- a/sys/arch/socppc/socppc/machdep.c +++ b/sys/arch/socppc/socppc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.73 2017/12/11 05:27:40 deraadt Exp $ */ +/* $OpenBSD: machdep.c,v 1.74 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.4 1996/10/16 19:33:11 ws Exp $ */ /* @@ -487,8 +487,8 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(tf->fixreg[1]) && (psp->ps_sigonstack & sigmask(sig))) - fp = (struct sigframe *)(p->p_sigstk.ss_sp - + p->p_sigstk.ss_size); + fp = (struct sigframe *) + trunc_page(vaddr_t)p->p_sigstk.ss_sp + pp->p_sigstk.ss_size); else fp = (struct sigframe *)tf->fixreg[1]; diff --git a/sys/arch/sparc64/sparc64/machdep.c b/sys/arch/sparc64/sparc64/machdep.c index 153633b01fb..1aa11f69ac7 100644 --- a/sys/arch/sparc64/sparc64/machdep.c +++ b/sys/arch/sparc64/sparc64/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.187 2017/12/30 20:46:59 guenther Exp $ */ +/* $OpenBSD: machdep.c,v 1.188 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: machdep.c,v 1.108 2001/07/24 19:30:14 eeh Exp $ */ /*- @@ -432,8 +432,8 @@ sendsig(sig_t catcher, int sig, int mask, u_long code, int type, */ if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !sigonstack(oldsp) && (psp->ps_sigonstack & sigmask(sig))) - fp = (struct sigframe *)((caddr_t)p->p_sigstk.ss_sp + - p->p_sigstk.ss_size); + fp = (struct sigframe *) + trunc_page((vaddr_t)p->p_sigstk.ss_sp + p->p_sigstk.ss_size); else fp = (struct sigframe *)oldsp; /* Allocate an aligned sigframe */ diff --git a/sys/arch/sparc64/sparc64/trap.c b/sys/arch/sparc64/sparc64/trap.c index 55c8bd6213d..7cc1973a107 100644 --- a/sys/arch/sparc64/sparc64/trap.c +++ b/sys/arch/sparc64/sparc64/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.98 2017/07/22 15:17:49 kettenis Exp $ */ +/* $OpenBSD: trap.c,v 1.99 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: trap.c,v 1.73 2001/08/09 01:03:01 eeh Exp $ */ /* @@ -348,6 +348,7 @@ trap(struct trapframe64 *tf, unsigned type, vaddr_t pc, long tstate) struct proc *p; struct pcb *pcb; int pstate = (tstate>>TSTATE_PSTATE_SHIFT); + vaddr_t sp; u_int64_t s; int64_t n; union sigval sv; @@ -427,6 +428,22 @@ trap(struct trapframe64 *tf, unsigned type, vaddr_t pc, long tstate) p->p_md.md_tf = tf; /* for ptrace/signals */ refreshcreds(p); + sp = PROC_STACK(p); + if (p->p_vmspace->vm_map.serial != p->p_spserial || + p->p_spstart == 0 || sp < p->p_spstart || + sp >= p->p_spend) { + KERNEL_LOCK(); + if (!uvm_map_check_stack_range(p, sp)) { + printf("trap [%s]%d/%d type %d: sp %lx not inside %lx-%lx\n", + p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid, + (int)type, sp, p->p_spstart, p->p_spend); + sv.sival_ptr = (void *)PROC_PC(p); + trapsignal(p, SIGSEGV, type, SEGV_ACCERR, sv); + } + + KERNEL_UNLOCK(); + } + switch (type) { default: diff --git a/sys/kern/exec_subr.c b/sys/kern/exec_subr.c index c1924edbaab..f2282a4a357 100644 --- a/sys/kern/exec_subr.c +++ b/sys/kern/exec_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec_subr.c,v 1.54 2018/02/10 02:54:33 mortimer Exp $ */ +/* $OpenBSD: exec_subr.c,v 1.55 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: exec_subr.c,v 1.9 1994/12/04 03:10:42 mycroft Exp $ */ /* @@ -276,7 +276,8 @@ vmcmd_map_zero(struct proc *p, struct exec_vmcmd *cmd) return (uvm_map(&p->p_vmspace->vm_map, &cmd->ev_addr, round_page(cmd->ev_len), NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(cmd->ev_prot, PROT_MASK, MAP_INHERIT_COPY, - MADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_COPYONW))); + MADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_COPYONW | + (cmd->ev_flags & VMCMD_STACK ? UVM_FLAG_STACK : 0)))); } /* @@ -379,17 +380,19 @@ exec_setup_stack(struct proc *p, struct exec_package *epp) #ifdef MACHINE_STACK_GROWS_UP NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ((epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr), - epp->ep_maxsaddr + epp->ep_ssize, NULLVP, 0, PROT_NONE); - NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize, + epp->ep_maxsaddr + epp->ep_ssize, NULLVP, 0, + PROT_NONE); + NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize, epp->ep_maxsaddr, NULLVP, 0, - PROT_READ | PROT_WRITE); + PROT_READ | PROT_WRITE, VMCMD_STACK); #else NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, ((epp->ep_minsaddr - epp->ep_ssize) - epp->ep_maxsaddr), - epp->ep_maxsaddr, NULLVP, 0, PROT_NONE); - NEW_VMCMD(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize, + epp->ep_maxsaddr, NULLVP, 0, + PROT_NONE); + NEW_VMCMD2(&epp->ep_vmcmds, vmcmd_map_zero, epp->ep_ssize, (epp->ep_minsaddr - epp->ep_ssize), NULLVP, 0, - PROT_READ | PROT_WRITE); + PROT_READ | PROT_WRITE, VMCMD_STACK); #endif return (0); diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 17bff8830fb..87604c5b501 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: init_main.c,v 1.275 2018/03/20 15:45:32 mpi Exp $ */ +/* $OpenBSD: init_main.c,v 1.276 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: init_main.c,v 1.84.4.1 1996/06/02 09:08:06 mrg Exp $ */ /* @@ -652,7 +652,7 @@ start_init(void *arg) if (uvm_map(&p->p_vmspace->vm_map, &addr, PAGE_SIZE, NULL, UVM_UNKNOWN_OFFSET, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_MASK, MAP_INHERIT_COPY, - MADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW))) + MADV_NORMAL, UVM_FLAG_FIXED|UVM_FLAG_OVERLAY|UVM_FLAG_COPYONW|UVM_FLAG_STACK))) panic("init: couldn't allocate argument space"); for (pathp = &initpaths[0]; (path = *pathp) != NULL; pathp++) { diff --git a/sys/kern/kern_sig.c b/sys/kern/kern_sig.c index c6ed90cc214..cb448f48280 100644 --- a/sys/kern/kern_sig.c +++ b/sys/kern/kern_sig.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_sig.c,v 1.218 2018/03/27 08:22:41 mpi Exp $ */ +/* $OpenBSD: kern_sig.c,v 1.219 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: kern_sig.c,v 1.54 1996/04/22 01:38:32 christos Exp $ */ /* @@ -554,6 +554,11 @@ sys_sigaltstack(struct proc *p, void *v, register_t *retval) } if (ss.ss_size < MINSIGSTKSZ) return (ENOMEM); + + error = uvm_map_remap_as_stack(p, (vaddr_t)ss.ss_sp, ss.ss_size); + if (error) + return (error); + p->p_sigstk = ss; return (0); } diff --git a/sys/sys/exec.h b/sys/sys/exec.h index 98fc9e64383..ad2594ad7e6 100644 --- a/sys/sys/exec.h +++ b/sys/sys/exec.h @@ -1,4 +1,4 @@ -/* $OpenBSD: exec.h,v 1.36 2017/02/08 21:04:44 guenther Exp $ */ +/* $OpenBSD: exec.h,v 1.37 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: exec.h,v 1.59 1996/02/09 18:25:09 christos Exp $ */ /*- @@ -98,6 +98,7 @@ struct exec_vmcmd { int ev_flags; #define VMCMD_RELATIVE 0x0001 /* ev_addr is relative to base entry */ #define VMCMD_BASE 0x0002 /* marks a base entry */ +#define VMCMD_STACK 0x0004 /* create with UVM_FLAG_STACK */ }; #define EXEC_DEFAULT_VMCMD_SETSIZE 8 /* # of cmds in set to start */ diff --git a/sys/sys/proc.h b/sys/sys/proc.h index edcaf7cb960..1c7ea4697e2 100644 --- a/sys/sys/proc.h +++ b/sys/sys/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.247 2018/02/26 13:43:51 mpi Exp $ */ +/* $OpenBSD: proc.h,v 1.248 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */ /*- @@ -330,6 +330,10 @@ struct proc { #define p_startcopy p_sigmask sigset_t p_sigmask; /* Current signal mask. */ + u_int p_spserial; + vaddr_t p_spstart; + vaddr_t p_spend; + u_char p_priority; /* Process priority. */ u_char p_usrpri; /* User-priority based on p_estcpu and ps_nice. */ int p_pledge_syscall; /* Cache of current syscall */ diff --git a/sys/sys/syscall_mi.h b/sys/sys/syscall_mi.h index bf0a0fff6a6..5df0efd4cb0 100644 --- a/sys/sys/syscall_mi.h +++ b/sys/sys/syscall_mi.h @@ -1,4 +1,4 @@ -/* $OpenBSD: syscall_mi.h,v 1.18 2017/04/20 15:21:51 deraadt Exp $ */ +/* $OpenBSD: syscall_mi.h,v 1.19 2018/04/12 17:13:44 deraadt Exp $ */ /* * Copyright (c) 1982, 1986, 1989, 1993 @@ -31,7 +31,9 @@ * @(#)kern_xxx.c 8.2 (Berkeley) 11/14/93 */ +#include <sys/param.h> #include <sys/pledge.h> +#include <uvm/uvm_extern.h> #ifdef KTRACE #include <sys/ktrace.h> @@ -48,6 +50,7 @@ mi_syscall(struct proc *p, register_t code, const struct sysent *callp, uint64_t tval; int lock = !(callp->sy_flags & SY_NOLOCK); int error, pledged; + vaddr_t sp = PROC_STACK(p); /* refresh the thread's cache of the process's creds */ refreshcreds(p); @@ -65,6 +68,24 @@ mi_syscall(struct proc *p, register_t code, const struct sysent *callp, } #endif + if (p->p_vmspace->vm_map.serial != p->p_spserial || + p->p_spstart == 0 || sp < p->p_spstart || sp >= p->p_spend) { + KERNEL_LOCK(); + + if (!uvm_map_check_stack_range(p, sp)) { + printf("syscall [%s]%d/%d sp %lx not inside %lx-%lx\n", + p->p_p->ps_comm, p->p_p->ps_pid, p->p_tid, + sp, p->p_spstart, p->p_spend); + + p->p_sitrapno = 0; + p->p_sicode = SEGV_ACCERR; + p->p_sigval.sival_ptr = (void *)PROC_PC(p); + psignal(p, SIGSEGV); + KERNEL_UNLOCK(); + return (EPERM); + } + KERNEL_UNLOCK(); + } if (lock) KERNEL_LOCK(); pledged = (p->p_p->ps_flags & PS_PLEDGE); diff --git a/sys/uvm/uvm.h b/sys/uvm/uvm.h index 3f08fd19a1f..3e765a66226 100644 --- a/sys/uvm/uvm.h +++ b/sys/uvm/uvm.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm.h,v 1.61 2016/08/11 01:17:33 dlg Exp $ */ +/* $OpenBSD: uvm.h,v 1.62 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: uvm.h,v 1.24 2000/11/27 08:40:02 chs Exp $ */ /* @@ -88,6 +88,7 @@ struct uvm { #define UVM_ET_NEEDSCOPY 0x08 /* needs_copy */ #define UVM_ET_HOLE 0x10 /* no backend */ #define UVM_ET_NOFAULT 0x20 /* don't fault */ +#define UVM_ET_STACK 0x40 /* this is a stack */ #define UVM_ET_FREEMAPPED 0x80 /* map entry is on free list (DEBUG) */ #define UVM_ET_ISOBJ(E) (((E)->etype & UVM_ET_OBJ) != 0) @@ -96,6 +97,7 @@ struct uvm { #define UVM_ET_ISNEEDSCOPY(E) (((E)->etype & UVM_ET_NEEDSCOPY) != 0) #define UVM_ET_ISHOLE(E) (((E)->etype & UVM_ET_HOLE) != 0) #define UVM_ET_ISNOFAULT(E) (((E)->etype & UVM_ET_NOFAULT) != 0) +#define UVM_ET_ISSTACK(E) (((E)->etype & UVM_ET_STACK) != 0) #ifdef _KERNEL diff --git a/sys/uvm/uvm_extern.h b/sys/uvm/uvm_extern.h index d1e440b7844..3005a61fcd0 100644 --- a/sys/uvm/uvm_extern.h +++ b/sys/uvm/uvm_extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_extern.h,v 1.142 2017/04/30 13:04:49 mpi Exp $ */ +/* $OpenBSD: uvm_extern.h,v 1.143 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: uvm_extern.h,v 1.57 2001/03/09 01:02:12 chs Exp $ */ /* @@ -111,7 +111,7 @@ typedef int vm_prot_t; #define UVM_FLAG_QUERY 0x0400000 /* do everything, except actual execution */ #define UVM_FLAG_NOFAULT 0x0800000 /* don't fault */ #define UVM_FLAG_UNMAP 0x1000000 /* unmap to make space */ - +#define UVM_FLAG_STACK 0x2000000 /* page may contain a stack */ /* macros to extract info */ #define UVM_PROTECTION(X) ((X) & PROT_MASK) diff --git a/sys/uvm/uvm_fault.c b/sys/uvm/uvm_fault.c index c521f63f4a3..635283fac7b 100644 --- a/sys/uvm/uvm_fault.c +++ b/sys/uvm/uvm_fault.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_fault.c,v 1.92 2017/07/20 18:22:25 bluhm Exp $ */ +/* $OpenBSD: uvm_fault.c,v 1.93 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: uvm_fault.c,v 1.51 2000/08/06 00:22:53 thorpej Exp $ */ /* @@ -234,7 +234,8 @@ uvmfault_amapcopy(struct uvm_faultinfo *ufi) /* copy if needed. */ if (UVM_ET_ISNEEDSCOPY(ufi->entry)) - amap_copy(ufi->map, ufi->entry, M_NOWAIT, TRUE, + amap_copy(ufi->map, ufi->entry, M_NOWAIT, + UVM_ET_ISSTACK(ufi->entry) ? FALSE : TRUE, ufi->orig_rvaddr, ufi->orig_rvaddr + 1); /* didn't work? must be out of RAM. sleep. */ diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c index 1fb3f00e241..b52968992c1 100644 --- a/sys/uvm/uvm_map.c +++ b/sys/uvm/uvm_map.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_map.c,v 1.233 2017/11/30 00:36:10 guenther Exp $ */ +/* $OpenBSD: uvm_map.c,v 1.234 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: uvm_map.c,v 1.86 2000/11/27 08:40:03 chs Exp $ */ /* @@ -91,6 +91,7 @@ #include <sys/malloc.h> #include <sys/pool.h> #include <sys/sysctl.h> +#include <sys/syslog.h> #ifdef SYSVSHM #include <sys/shm.h> @@ -1000,8 +1001,14 @@ uvm_mapanon(struct vm_map *map, vaddr_t *addr, vsize_t sz, KASSERT((*addr & PAGE_MASK) == 0); /* Check that the space is available. */ - if (flags & UVM_FLAG_UNMAP) + if (flags & UVM_FLAG_UNMAP) { + if ((flags & UVM_FLAG_STACK) && + !uvm_map_is_stack_remappable(map, *addr, sz)) { + error = EINVAL; + goto unlock; + } uvm_unmap_remove(map, *addr, *addr + sz, &dead, FALSE, TRUE); + } if (!uvm_map_isavail(map, NULL, &first, &last, *addr, sz)) { error = ENOMEM; goto unlock; @@ -1064,6 +1071,11 @@ uvm_mapanon(struct vm_map *map, vaddr_t *addr, vsize_t sz, entry->inheritance = inherit; entry->wired_count = 0; entry->advice = advice; + if (flags & UVM_FLAG_STACK) { + entry->etype |= UVM_ET_STACK; + if (flags & (UVM_FLAG_FIXED | UVM_FLAG_UNMAP)) + map->serial++; + } if (flags & UVM_FLAG_COPYONW) { entry->etype |= UVM_ET_COPYONWRITE; if ((flags & UVM_FLAG_OVERLAY) == 0) @@ -1320,6 +1332,11 @@ uvm_map(struct vm_map *map, vaddr_t *addr, vsize_t sz, entry->inheritance = inherit; entry->wired_count = 0; entry->advice = advice; + if (flags & UVM_FLAG_STACK) { + entry->etype |= UVM_ET_STACK; + if (flags & UVM_FLAG_UNMAP) + map->serial++; + } if (uobj) entry->etype |= UVM_ET_OBJ; else if (flags & UVM_FLAG_HOLE) @@ -1746,6 +1763,137 @@ uvm_map_lookup_entry(struct vm_map *map, vaddr_t address, } /* + * Inside a vm_map find the sp address and verify MAP_STACK, and also + * remember low and high regions of that of region which is marked + * with MAP_STACK. Return TRUE. + * If sp isn't in a MAP_STACK region return FALSE. + */ +boolean_t +uvm_map_check_stack_range(struct proc *p, vaddr_t sp) +{ + vm_map_t map = &p->p_vmspace->vm_map; + vm_map_entry_t entry; + + if (sp < map->min_offset || sp >= map->max_offset) + return(FALSE); + + /* lock map */ + vm_map_lock_read(map); + + /* lookup */ + if (!uvm_map_lookup_entry(map, trunc_page(sp), &entry)) { + vm_map_unlock_read(map); + return(FALSE); + } + + if ((entry->etype & UVM_ET_STACK) == 0) { + vm_map_unlock_read(map); + return (FALSE); + } + p->p_spstart = entry->start; + p->p_spend = entry->end; + p->p_spserial = map->serial; + vm_map_unlock_read(map); + return(TRUE); +} + +/* + * Check whether the given address range can be converted to a MAP_STACK + * mapping. + * + * Must be called with map locked. + */ +boolean_t +uvm_map_is_stack_remappable(struct vm_map *map, vaddr_t addr, vaddr_t sz) +{ + vaddr_t end = addr + sz; + struct vm_map_entry *first, *iter, *prev = NULL; + + if (!uvm_map_lookup_entry(map, addr, &first)) { + printf("map stack 0x%lx-0x%lx of map %p failed: no mapping\n", + addr, end, map); + return FALSE; + } + + /* + * Check that the address range exists, is contiguous, and + * has the right protection. + */ + for (iter = first; iter != NULL && iter->start < end; + prev = iter, iter = RBT_NEXT(uvm_map_addr, iter)) { + /* + * Make sure that we do not have holes in the range. + */ +#if 0 + if (prev != NULL) { + printf("prev->start 0x%lx, prev->end 0x%lx, " + "iter->start 0x%lx, iter->end 0x%lx\n", + prev->start, prev->end, iter->start, iter->end); + } +#endif + + if (prev != NULL && prev->end != iter->start) { + printf("map stack 0x%lx-0x%lx of map %p failed: " + "hole in range\n", addr, end, map); + return FALSE; + } + if (iter->start == iter->end || UVM_ET_ISHOLE(iter)) { + printf("map stack 0x%lx-0x%lx of map %p failed: " + "hole in range\n", addr, end, map); + return FALSE; + } + + /* + * Now check the protection. + */ +#if 0 + printf("iter prot: 0x%x\n", iter->protection); +#endif + if (iter->protection != (PROT_READ | PROT_WRITE)) { + printf("map stack 0x%lx-0x%lx of map %p failed: " + "bad protection\n", addr, end, map); + return FALSE; + } + } + + return TRUE; +} + +/* + * Remap the middle-pages of an existing mapping as a stack range. + * If there exists a previous contiguous mapping with the given range + * [addr, addr + sz), with protection PROT_READ|PROT_WRITE, then the + * mapping is dropped, and a new anon mapping is created and marked as + * a stack. + * + * Must be called with map unlocked. + */ +int +uvm_map_remap_as_stack(struct proc *p, vaddr_t addr, vaddr_t sz) +{ + vm_map_t map = &p->p_vmspace->vm_map; + vaddr_t start, end; + int error; + int flags = UVM_MAPFLAG(PROT_READ | PROT_WRITE, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_INHERIT_COPY, MADV_NORMAL, + UVM_FLAG_STACK | UVM_FLAG_FIXED | UVM_FLAG_UNMAP | + UVM_FLAG_COPYONW); + + start = round_page(addr); + end = trunc_page(addr + sz); + + if (start < map->min_offset || end >= map->max_offset || end < start) + return EINVAL; + + error = uvm_mapanon(map, &start, end - start, 0, flags); + if (error != 0) + printf("map stack for pid %d failed\n", p->p_p->ps_pid); + + return error; +} + +/* * uvm_map_pie: return a random load address for a PIE executable * properly aligned. */ @@ -1975,6 +2123,10 @@ uvm_unmap_remove(struct vm_map *map, vaddr_t start, vaddr_t end, } } + /* A stack has been removed.. */ + if (UVM_ET_ISSTACK(entry) && (map->flags & VM_MAP_ISVMSPACE)) + map->serial++; + /* Kill entry. */ uvm_unmap_kill_entry(map, entry); @@ -2084,7 +2236,8 @@ uvm_map_pageable_wire(struct vm_map *map, struct vm_map_entry *first, UVM_ET_ISNEEDSCOPY(iter) && ((iter->protection & PROT_WRITE) || iter->object.uvm_obj == NULL)) { - amap_copy(map, iter, M_WAITOK, TRUE, + amap_copy(map, iter, M_WAITOK, + UVM_ET_ISSTACK(iter) ? FALSE : TRUE, iter->start, iter->end); } iter->wired_count++; @@ -2853,11 +3006,12 @@ uvm_map_printit(struct vm_map *map, boolean_t full, entry, entry->start, entry->end, entry->object.uvm_obj, (long long)entry->offset, entry->aref.ar_amap, entry->aref.ar_pageoff); - (*pr)("\tsubmap=%c, cow=%c, nc=%c, prot(max)=%d/%d, inh=%d, " + (*pr)("\tsubmap=%c, cow=%c, nc=%c, stack=%c, prot(max)=%d/%d, inh=%d, " "wc=%d, adv=%d\n", (entry->etype & UVM_ET_SUBMAP) ? 'T' : 'F', (entry->etype & UVM_ET_COPYONWRITE) ? 'T' : 'F', (entry->etype & UVM_ET_NEEDSCOPY) ? 'T' : 'F', + (entry->etype & UVM_ET_STACK) ? 'T' : 'F', entry->protection, entry->max_protection, entry->inheritance, entry->wired_count, entry->advice); @@ -4165,7 +4319,8 @@ uvm_map_extract(struct vm_map *srcmap, vaddr_t start, vsize_t len, for (entry = first; entry != NULL && entry->start < end; entry = RBT_NEXT(uvm_map_addr, entry)) { if (UVM_ET_ISNEEDSCOPY(entry)) - amap_copy(srcmap, entry, M_NOWAIT, TRUE, start, end); + amap_copy(srcmap, entry, M_NOWAIT, + UVM_ET_ISSTACK(entry) ? FALSE : TRUE, start, end); if (UVM_ET_ISNEEDSCOPY(entry)) { /* * amap_copy failure diff --git a/sys/uvm/uvm_map.h b/sys/uvm/uvm_map.h index 317d0283d12..07ca0d0ef45 100644 --- a/sys/uvm/uvm_map.h +++ b/sys/uvm/uvm_map.h @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_map.h,v 1.59 2016/09/16 03:39:25 dlg Exp $ */ +/* $OpenBSD: uvm_map.h,v 1.60 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: uvm_map.h,v 1.24 2001/02/18 21:19:08 chs Exp $ */ /* @@ -292,6 +292,7 @@ struct vm_map { struct pmap * pmap; /* Physical map */ struct rwlock lock; /* Lock for map data */ struct mutex mtx; + u_int serial; /* signals stack changes */ struct uvm_map_addr addr; /* Entry tree, by addr */ @@ -393,6 +394,9 @@ int uvm_map_inherit(vm_map_t, vaddr_t, vaddr_t, vm_inherit_t); int uvm_map_advice(vm_map_t, vaddr_t, vaddr_t, int); void uvm_map_init(void); boolean_t uvm_map_lookup_entry(vm_map_t, vaddr_t, vm_map_entry_t *); +boolean_t uvm_map_check_stack_range(struct proc *, vaddr_t sp); +boolean_t uvm_map_is_stack_remappable(vm_map_t, vaddr_t, vsize_t); +int uvm_map_remap_as_stack(struct proc *, vaddr_t, vsize_t); int uvm_map_replace(vm_map_t, vaddr_t, vaddr_t, vm_map_entry_t, int); int uvm_map_reserve(vm_map_t, vsize_t, vaddr_t, vsize_t, diff --git a/sys/uvm/uvm_mmap.c b/sys/uvm/uvm_mmap.c index 464ee703beb..8f8cbb58e8b 100644 --- a/sys/uvm/uvm_mmap.c +++ b/sys/uvm/uvm_mmap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: uvm_mmap.c,v 1.148 2018/03/27 08:42:49 mpi Exp $ */ +/* $OpenBSD: uvm_mmap.c,v 1.149 2018/04/12 17:13:44 deraadt Exp $ */ /* $NetBSD: uvm_mmap.c,v 1.49 2001/02/18 21:19:08 chs Exp $ */ /* @@ -371,7 +371,6 @@ sys_mmap(struct proc *p, void *v, register_t *retval) size = (vsize_t) SCARG(uap, len); prot = SCARG(uap, prot); flags = SCARG(uap, flags); - flags &= ~MAP_STACK; /* XXX MAP_STACK coming in 2018 */ fd = SCARG(uap, fd); pos = SCARG(uap, pos); @@ -390,6 +389,16 @@ sys_mmap(struct proc *p, void *v, register_t *retval) return (EINVAL); if ((flags & (MAP_FIXED|__MAP_NOREPLACE)) == __MAP_NOREPLACE) return (EINVAL); + if (flags & MAP_STACK) { + if ((flags & (MAP_ANON|MAP_PRIVATE)) != (MAP_ANON|MAP_PRIVATE)) + return (EINVAL); + if (flags & ~(MAP_STACK|MAP_FIXED|MAP_ANON|MAP_PRIVATE)) + return (EINVAL); + if (pos != 0) + return (EINVAL); + if ((prot & (PROT_READ|PROT_WRITE)) != (PROT_READ|PROT_WRITE)) + return (EINVAL); + } if (size == 0) return (EINVAL); @@ -667,7 +676,6 @@ sys_munmap(struct proc *p, void *v, register_t *retval) TAILQ_INIT(&dead_entries); uvm_unmap_remove(map, addr, addr + size, &dead_entries, FALSE, TRUE); - vm_map_unlock(map); /* and unlock */ uvm_unmap_detach(&dead_entries, 0); @@ -1045,6 +1053,8 @@ uvm_mmapanon(vm_map_t map, vaddr_t *addr, vsize_t size, vm_prot_t prot, else /* shared: create amap now */ uvmflag |= UVM_FLAG_OVERLAY; + if (flags & MAP_STACK) + uvmflag |= UVM_FLAG_STACK; /* set up mapping flags */ uvmflag = UVM_MAPFLAG(prot, maxprot, @@ -1151,6 +1161,8 @@ uvm_mmapfile(vm_map_t map, vaddr_t *addr, vsize_t size, vm_prot_t prot, uvmflag |= UVM_FLAG_COPYONW; if (flags & __MAP_NOFAULT) uvmflag |= (UVM_FLAG_NOFAULT | UVM_FLAG_OVERLAY); + if (flags & MAP_STACK) + uvmflag |= UVM_FLAG_STACK; /* set up mapping flags */ uvmflag = UVM_MAPFLAG(prot, maxprot, |