summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/libpthread/man/pthread_attr_setstack.316
-rw-r--r--lib/libpthread/man/pthread_attr_setstackaddr.315
-rw-r--r--sys/arch/alpha/alpha/machdep.c7
-rw-r--r--sys/arch/alpha/alpha/trap.c20
-rw-r--r--sys/arch/amd64/amd64/machdep.c4
-rw-r--r--sys/arch/amd64/amd64/trap.c21
-rw-r--r--sys/arch/arm/arm/fault.c20
-rw-r--r--sys/arch/arm/arm/sig_machdep.c8
-rw-r--r--sys/arch/arm64/arm64/ast.c5
-rw-r--r--sys/arch/arm64/arm64/sig_machdep.c8
-rw-r--r--sys/arch/arm64/arm64/trap.c18
-rw-r--r--sys/arch/hppa/hppa/machdep.c4
-rw-r--r--sys/arch/hppa/hppa/trap.c24
-rw-r--r--sys/arch/i386/i386/machdep.c4
-rw-r--r--sys/arch/i386/i386/trap.c20
-rw-r--r--sys/arch/m88k/m88k/sig_machdep.c5
-rw-r--r--sys/arch/macppc/macppc/machdep.c6
-rw-r--r--sys/arch/mips64/mips64/sendsig.c7
-rw-r--r--sys/arch/mips64/mips64/trap.c25
-rw-r--r--sys/arch/powerpc/powerpc/trap.c20
-rw-r--r--sys/arch/sh/sh/sh_machdep.c6
-rw-r--r--sys/arch/socppc/socppc/machdep.c6
-rw-r--r--sys/arch/sparc64/sparc64/machdep.c6
-rw-r--r--sys/arch/sparc64/sparc64/trap.c19
-rw-r--r--sys/kern/exec_subr.c19
-rw-r--r--sys/kern/init_main.c4
-rw-r--r--sys/kern/kern_sig.c7
-rw-r--r--sys/sys/exec.h3
-rw-r--r--sys/sys/proc.h6
-rw-r--r--sys/sys/syscall_mi.h23
-rw-r--r--sys/uvm/uvm.h4
-rw-r--r--sys/uvm/uvm_extern.h4
-rw-r--r--sys/uvm/uvm_fault.c5
-rw-r--r--sys/uvm/uvm_map.c165
-rw-r--r--sys/uvm/uvm_map.h6
-rw-r--r--sys/uvm/uvm_mmap.c18
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,