Move the "stackgap" from the stack into its own page at a random address.
authorkettenis <kettenis@openbsd.org>
Mon, 26 Jan 2015 22:51:37 +0000 (22:51 +0000)
committerkettenis <kettenis@openbsd.org>
Mon, 26 Jan 2015 22:51:37 +0000 (22:51 +0000)
This allows us the unmap the initial part of the stack, such that it can't
be used as a staging area for ROP (or other) attacks.

ok guenther@, tedu@

sys/compat/common/compat_util.c
sys/kern/kern_exec.c
sys/sys/exec.h
sys/sys/proc.h

index 039fbe9..f2121d8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: compat_util.c,v 1.14 2014/12/16 18:30:03 tedu Exp $   */
+/*     $OpenBSD: compat_util.c,v 1.15 2015/01/26 22:51:37 kettenis Exp $       */
 /*     $NetBSD: compat_util.c,v 1.4 1996/03/14 19:31:45 christos Exp $ */
 
 /*
@@ -40,6 +40,7 @@
 #include <sys/ioctl.h>
 #include <sys/kernel.h>
 #include <sys/malloc.h>
+#include <sys/signalvar.h>
 #include <sys/vnode.h>
 
 #include <uvm/uvm_extern.h>
@@ -176,24 +177,29 @@ bad:
 caddr_t  
 stackgap_init(struct proc *p)
 {
-        return STACKGAPBASE;
+       struct process *pr = p->p_p;
+
+       if (pr->ps_stackgap == 0) {
+               if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_stackgap,
+                   round_page(STACKGAPLEN), NULL, 0, 0,
+                   UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE,
+                   MAP_INHERIT_COPY, MADV_RANDOM, UVM_FLAG_COPYONW)))
+                       sigexit(p, SIGILL);
+       }
+
+        return (caddr_t)pr->ps_stackgap;
 }
+
 void *          
 stackgap_alloc(caddr_t *sgp, size_t sz)
 {
        void *n = (void *) *sgp;
        caddr_t nsgp;
-       
+
        sz = ALIGN(sz);
        nsgp = *sgp + sz;
-#ifdef MACHINE_STACK_GROWS_UP
-       if (nsgp > ((caddr_t)PS_STRINGS) + STACKGAPLEN)
-               return NULL;
-#else
-       if (nsgp > ((caddr_t)PS_STRINGS))
+       if (nsgp > (caddr_t)trunc_page((vaddr_t)n) + STACKGAPLEN)
                return NULL;
-#endif
        *sgp = nsgp;
        return n;
 }
index 811d8e7..d71053b 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_exec.c,v 1.156 2015/01/20 19:43:21 kettenis Exp $        */
+/*     $OpenBSD: kern_exec.c,v 1.157 2015/01/26 22:51:37 kettenis Exp $        */
 /*     $NetBSD: kern_exec.c,v 1.75 1996/02/09 18:59:28 christos Exp $  */
 
 /*-
@@ -451,6 +451,22 @@ sys_execve(struct proc *p, void *v, register_t *retval)
        if (error)
                goto exec_abort;
 
+       /* old "stackgap" is gone now */
+       pr->ps_stackgap = 0;
+
+#ifdef MACHINE_STACK_GROWS_UP
+       pr->ps_strings = (vaddr_t)USRSTACK + sgap;
+        if (uvm_map_protect(&vm->vm_map, (vaddr_t)vm->vm_maxsaddr,
+            trunc_page(pr->ps_strings), PROT_NONE, TRUE))
+                goto exec_abort;
+#else
+       pr->ps_strings = (vaddr_t)USRSTACK - sizeof(arginfo) - sgap;
+        if (uvm_map_protect(&vm->vm_map,
+            round_page(pr->ps_strings + sizeof(arginfo)),
+            (vaddr_t)vm->vm_minsaddr, PROT_NONE, TRUE))
+                goto exec_abort;
+#endif
+
        /* remember information about the process */
        arginfo.ps_nargvstr = argc;
        arginfo.ps_nenvstr = envc;
@@ -466,11 +482,6 @@ sys_execve(struct proc *p, void *v, register_t *retval)
                goto exec_abort;
 
        /* copy out the process's ps_strings structure */
-#ifdef MACHINE_STACK_GROWS_UP
-       pr->ps_strings = (vaddr_t)PS_STRINGS + sgap;
-#else
-       pr->ps_strings = (vaddr_t)PS_STRINGS - sgap;
-#endif
        if (copyout(&arginfo, (char *)pr->ps_strings, sizeof(arginfo)))
                goto exec_abort;
 
index 81c13a7..3d8cf92 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: exec.h,v 1.27 2013/10/17 08:02:20 deraadt Exp $       */
+/*     $OpenBSD: exec.h,v 1.28 2015/01/26 22:51:37 kettenis Exp $      */
 /*     $NetBSD: exec.h,v 1.59 1996/02/09 18:25:09 christos Exp $       */
 
 /*-
@@ -57,32 +57,12 @@ struct ps_strings {
        int     ps_nenvstr;     /* the number of environment strings */
 };
 
-/*
- * Address of ps_strings structure (in user space).
- */
-#ifdef MACHINE_STACK_GROWS_UP
-#define        PS_STRINGS      ((struct ps_strings *)(USRSTACK))
-#else
-#define        PS_STRINGS \
-       ((struct ps_strings *)(USRSTACK - sizeof(struct ps_strings)))
-#endif
-
 /*
  * Below the PS_STRINGS and sigtramp, we may require a gap on the stack
  * (used to copyin/copyout various emulation data structures).
  */
 #define        STACKGAPLEN     (2*1024)        /* plenty enough for now */
 
-#ifdef MACHINE_STACK_GROWS_UP
-#define        STACKGAPBASE_UNALIGNED  \
-       ((caddr_t)PS_STRINGS + sizeof(struct ps_strings))
-#else
-#define        STACKGAPBASE_UNALIGNED  \
-       ((caddr_t)PS_STRINGS - STACKGAPLEN)
-#endif
-#define        STACKGAPBASE            \
-       ((caddr_t)ALIGN(STACKGAPBASE_UNALIGNED))
-
 /*
  * the following structures allow execve() to put together processes
  * in a more extensible and cleaner way.
index 77a372f..f00a9f8 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: proc.h,v 1.193 2015/01/20 19:43:21 kettenis Exp $     */
+/*     $OpenBSD: proc.h,v 1.194 2015/01/26 22:51:37 kettenis Exp $     */
 /*     $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $       */
 
 /*-
@@ -200,6 +200,7 @@ struct process {
        struct  pgrp *ps_pgrp;          /* Pointer to process group. */
        struct  emul *ps_emul;          /* Emulation information */
        vaddr_t ps_strings;             /* User pointers to argv/env */
+       vaddr_t ps_stackgap;            /* User pointer to the "stackgap" */
        vaddr_t ps_sigcode;             /* User pointer to the signal code */
        u_int   ps_rtableid;            /* Process routing table/domain. */
        char    ps_nice;                /* Process "nice" value. */