Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys Revamp PaX:



details:   https://anonhg.NetBSD.org/src/rev/4e5771516782
branches:  trunk
changeset: 339615:4e5771516782
user:      maxv <maxv%NetBSD.org@localhost>
date:      Thu Jul 30 15:28:18 2015 +0000

description:
Revamp PaX:
 - don't confuse between ELF flags and proc flags. Introduce the proc-
   specific P_PAX_ASLR, P_PAX_MPROTECT and P_PAX_GUARD flags.
 - introduce pax_setup_elf_flags(), which takes as argument the PaX flag
   of the ELF PaX note section, and which sets the proc flag as
   appropriate. Also introduce a couple of other functions used for that
   purpose.
 - modify pax_aslr_active(), and all the other similar pieces of code, so
   that it checks the proc flag directly, without extra ELF computation

In addition to making PaX clearer, the combination of these changes fixes
the following bug: if a non-PaX'ed process is launched, and then someone
sets security.pax.{aslr,mprotect,segvguard}.global=1, the process becomes
PaX'ed while its address space hasn't been randomized, which is not likely
to be a good idea.

Now, only the proc flag is checked at runtime, which means the process's
PaX status won't be altered during the execution.

Also:
 - declare PAX_DPRINTF, makes it more readable
 - fix a typo in exec_elf.h

diffstat:

 sys/kern/exec_elf.c |    6 +-
 sys/kern/kern_pax.c |  173 ++++++++++++++++++++++++++++++++++++++-------------
 sys/sys/exec_elf.h  |    4 +-
 sys/sys/pax.h       |    7 +-
 4 files changed, 140 insertions(+), 50 deletions(-)

diffs (truncated from 359 to 300 lines):

diff -r 43f2629df5f7 -r 4e5771516782 sys/kern/exec_elf.c
--- a/sys/kern/exec_elf.c       Thu Jul 30 15:03:14 2015 +0000
+++ b/sys/kern/exec_elf.c       Thu Jul 30 15:28:18 2015 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: exec_elf.c,v 1.72 2015/04/27 09:19:58 maxv Exp $       */
+/*     $NetBSD: exec_elf.c,v 1.73 2015/07/30 15:28:18 maxv Exp $       */
 
 /*-
  * Copyright (c) 1994, 2000, 2005 The NetBSD Foundation, Inc.
@@ -57,7 +57,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(1, "$NetBSD: exec_elf.c,v 1.72 2015/04/27 09:19:58 maxv Exp $");
+__KERNEL_RCSID(1, "$NetBSD: exec_elf.c,v 1.73 2015/07/30 15:28:18 maxv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_pax.h"
@@ -715,7 +715,7 @@
        }
 
 #if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR)
-       l->l_proc->p_pax = epp->ep_pax_flags;
+       pax_setup_elf_flags(l, epp->ep_pax_flags);
 #endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */
 
        if (is_dyn)
diff -r 43f2629df5f7 -r 4e5771516782 sys/kern/kern_pax.c
--- a/sys/kern/kern_pax.c       Thu Jul 30 15:03:14 2015 +0000
+++ b/sys/kern/kern_pax.c       Thu Jul 30 15:28:18 2015 +0000
@@ -1,6 +1,35 @@
-/*     $NetBSD: kern_pax.c,v 1.28 2015/04/13 16:36:12 riastradh Exp $  */
+/*     $NetBSD: kern_pax.c,v 1.29 2015/07/30 15:28:18 maxv Exp $       */
 
-/*-
+/*
+ * Copyright (c) 2015 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Maxime Villard.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
  * Copyright (c) 2006 Elad Efrat <elad%NetBSD.org@localhost>
  * All rights reserved.
  *
@@ -28,7 +57,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_pax.c,v 1.28 2015/04/13 16:36:12 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_pax.c,v 1.29 2015/07/30 15:28:18 maxv Exp $");
 
 #include "opt_pax.h"
 
@@ -45,6 +74,12 @@
 #include <sys/kauth.h>
 #include <sys/cprng.h>
 
+#ifdef PAX_ASLR_DEBUG
+#define PAX_DPRINTF(_fmt, args...)     uprintf("%s: " _fmt "\n", __func__, ##args)
+#else
+#define PAX_DPRINTF(_fmt, args...)     do {} while (/*CONSTCOND*/0)
+#endif
+
 #ifdef PAX_ASLR
 #include <sys/mman.h>
 #include <sys/exec.h>
@@ -65,22 +100,22 @@
 #define PAX_ASLR_DELTA_STACK_LEN       12
 #endif
 
+static bool pax_aslr_elf_flags_active(uint32_t);
 #endif /* PAX_ASLR */
 
 #ifdef PAX_MPROTECT
 static int pax_mprotect_enabled = 1;
 static int pax_mprotect_global = PAX_MPROTECT;
+static bool pax_mprotect_elf_flags_active(uint32_t);
 #endif /* PAX_MPROTECT */
 
 #ifdef PAX_SEGVGUARD
 #ifndef PAX_SEGVGUARD_EXPIRY
 #define        PAX_SEGVGUARD_EXPIRY            (2 * 60)
 #endif
-
 #ifndef PAX_SEGVGUARD_SUSPENSION
 #define        PAX_SEGVGUARD_SUSPENSION        (10 * 60)
 #endif
-
 #ifndef        PAX_SEGVGUARD_MAXCRASHES
 #define        PAX_SEGVGUARD_MAXCRASHES        5
 #endif
@@ -105,6 +140,7 @@
        LIST_HEAD(, pax_segvguard_uid_entry) segv_uids;
 };
 
+static bool pax_segvguard_elf_flags_active(uint32_t);
 static void pax_segvguard_cb(void *);
 #endif /* PAX_SEGVGUARD */
 
@@ -247,9 +283,7 @@
 {
 #ifdef PAX_SEGVGUARD
        int error;
-#endif /* PAX_SEGVGUARD */
 
-#ifdef PAX_SEGVGUARD
        error = fileassoc_register("segvguard", pax_segvguard_cb,
            &segvguard_id);
        if (error) {
@@ -258,18 +292,55 @@
 #endif /* PAX_SEGVGUARD */
 }
 
+void
+pax_setup_elf_flags(struct lwp *l, uint32_t elf_flags)
+{
+       uint32_t flags = 0;
+
+#ifdef PAX_ASLR
+       if (pax_aslr_elf_flags_active(elf_flags)) {
+               flags |= P_PAX_ASLR;
+       }
+#endif
 #ifdef PAX_MPROTECT
+       if (pax_mprotect_elf_flags_active(elf_flags)) {
+               flags |= P_PAX_MPROTECT;
+       }
+#endif
+#ifdef PAX_SEGVGUARD
+       if (pax_segvguard_elf_flags_active(elf_flags)) {
+               flags |= P_PAX_GUARD;
+       }
+#endif
+
+       l->l_proc->p_pax = flags;
+}
+
+
+#ifdef PAX_MPROTECT
+static bool
+pax_mprotect_elf_flags_active(uint32_t flags)
+{
+       if (!pax_mprotect_enabled)
+               return false;
+       if (pax_mprotect_global && (flags & ELF_NOTE_PAX_NOMPROTECT) != 0) {
+               /* Mprotect explicitly disabled */
+               return false;
+       }
+       if (!pax_mprotect_global && (flags & ELF_NOTE_PAX_MPROTECT) == 0) {
+               /* Mprotect not requested */
+               return false;
+       }
+       return true;
+}
+
 void
 pax_mprotect(struct lwp *l, vm_prot_t *prot, vm_prot_t *maxprot)
 {
-       uint32_t f;
+       uint32_t flags;
 
-       if (!pax_mprotect_enabled)
-               return;
-
-       f = l->l_proc->p_pax;
-       if ((pax_mprotect_global && (f & ELF_NOTE_PAX_NOMPROTECT) != 0) ||
-           (!pax_mprotect_global && (f & ELF_NOTE_PAX_MPROTECT) == 0))
+       flags = l->l_proc->p_pax;
+       if (!(flags & P_PAX_MPROTECT))
                return;
 
        if ((*prot & (VM_PROT_WRITE|VM_PROT_EXECUTE)) != VM_PROT_EXECUTE) {
@@ -283,17 +354,27 @@
 #endif /* PAX_MPROTECT */
 
 #ifdef PAX_ASLR
+static bool
+pax_aslr_elf_flags_active(uint32_t flags)
+{
+       if (!pax_aslr_enabled)
+               return false;
+       if (pax_aslr_global && (flags & ELF_NOTE_PAX_NOASLR) != 0) {
+               /* ASLR explicitly disabled */
+               return false;
+       }
+       if (!pax_aslr_global && (flags & ELF_NOTE_PAX_ASLR) == 0) {
+               /* ASLR not requested */
+               return false;
+       }
+       return true;
+}
+
 bool
 pax_aslr_active(struct lwp *l)
 {
-       uint32_t f;
-
-       if (!pax_aslr_enabled)
-               return false;
-
-       f = l->l_proc->p_pax;
-       if ((pax_aslr_global && (f & ELF_NOTE_PAX_NOASLR) != 0) ||
-           (!pax_aslr_global && (f & ELF_NOTE_PAX_ASLR) == 0))
+       uint32_t flags = l->l_proc->p_pax;
+       if (!(flags & P_PAX_ASLR))
                return false;
        return true;
 }
@@ -315,23 +396,17 @@
                return;
 
        if (!(f & MAP_FIXED) && ((orig_addr == 0) || !(f & MAP_ANON))) {
-#ifdef PAX_ASLR_DEBUG
-               uprintf("applying to 0x%lx orig_addr=0x%lx f=%x\n",
+               PAX_DPRINTF("applying to 0x%lx orig_addr=0x%lx f=%x",
                    (unsigned long)*addr, (unsigned long)orig_addr, f);
-#endif
                if (!(l->l_proc->p_vmspace->vm_map.flags & VM_MAP_TOPDOWN))
                        *addr += l->l_proc->p_vmspace->vm_aslr_delta_mmap;
                else
                        *addr -= l->l_proc->p_vmspace->vm_aslr_delta_mmap;
-#ifdef PAX_ASLR_DEBUG
-               uprintf("result 0x%lx\n", *addr);
-#endif
+               PAX_DPRINTF("result 0x%lx", *addr);
+       } else {
+               PAX_DPRINTF("not applying to 0x%lx orig_addr=0x%lx f=%x",
+                   (unsigned long)*addr, (unsigned long)orig_addr, f);
        }
-#ifdef PAX_ASLR_DEBUG
-       else
-           uprintf("not applying to 0x%lx orig_addr=0x%lx f=%x\n",
-               (unsigned long)*addr, (unsigned long)orig_addr, f);
-#endif
 }
 
 void
@@ -341,10 +416,8 @@
                u_long d =  PAX_ASLR_DELTA(cprng_fast32(),
                    PAX_ASLR_DELTA_STACK_LSB,
                    PAX_ASLR_DELTA_STACK_LEN);
-#ifdef PAX_ASLR_DEBUG
-               uprintf("stack 0x%lx d=0x%lx 0x%lx\n",
+               PAX_DPRINTF("stack 0x%lx d=0x%lx 0x%lx",
                    epp->ep_minsaddr, d, epp->ep_minsaddr - d);
-#endif
                epp->ep_minsaddr -= d;
                *max_stack_size -= d;
                if (epp->ep_ssize > *max_stack_size)
@@ -354,6 +427,22 @@
 #endif /* PAX_ASLR */
 
 #ifdef PAX_SEGVGUARD
+static bool
+pax_segvguard_elf_flags_active(uint32_t flags)
+{
+       if (!pax_segvguard_enabled)
+               return false;
+       if (pax_segvguard_global && (flags & ELF_NOTE_PAX_NOGUARD) != 0) {
+               /* Segvguard explicitly disabled */
+               return false;
+       }
+       if (!pax_segvguard_global && (flags & ELF_NOTE_PAX_GUARD) == 0) {
+               /* Segvguard not requested */
+               return false;
+       }
+       return true;
+}
+
 static void
 pax_segvguard_cb(void *v)
 {
@@ -381,16 +470,12 @@
        struct pax_segvguard_uid_entry *up;
        struct timeval tv;
        uid_t uid;



Home | Main Index | Thread Index | Old Index