Module Name:    src
Committed By:   maxv
Date:           Thu Jul 30 15:28:18 UTC 2015

Modified Files:
        src/sys/kern: exec_elf.c kern_pax.c
        src/sys/sys: exec_elf.h pax.h

Log Message:
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


To generate a diff of this commit:
cvs rdiff -u -r1.72 -r1.73 src/sys/kern/exec_elf.c
cvs rdiff -u -r1.28 -r1.29 src/sys/kern/kern_pax.c
cvs rdiff -u -r1.148 -r1.149 src/sys/sys/exec_elf.h
cvs rdiff -u -r1.11 -r1.12 src/sys/sys/pax.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/exec_elf.c
diff -u src/sys/kern/exec_elf.c:1.72 src/sys/kern/exec_elf.c:1.73
--- src/sys/kern/exec_elf.c:1.72	Mon Apr 27 09:19:58 2015
+++ src/sys/kern/exec_elf.c	Thu Jul 30 15:28:18 2015
@@ -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 @@ exec_elf_makecmds(struct lwp *l, struct 
 	}
 
 #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)

Index: src/sys/kern/kern_pax.c
diff -u src/sys/kern/kern_pax.c:1.28 src/sys/kern/kern_pax.c:1.29
--- src/sys/kern/kern_pax.c:1.28	Mon Apr 13 16:36:12 2015
+++ src/sys/kern/kern_pax.c	Thu Jul 30 15:28:18 2015
@@ -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 <e...@netbsd.org>
  * 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 @@ __KERNEL_RCSID(0, "$NetBSD: kern_pax.c,v
 #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 @@ int pax_aslr_global = PAX_ASLR;
 #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 @@ struct pax_segvguard_entry {
 	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 @@ pax_init(void)
 {
 #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 @@ pax_init(void)
 #endif /* PAX_SEGVGUARD */
 }
 
-#ifdef PAX_MPROTECT
 void
-pax_mprotect(struct lwp *l, vm_prot_t *prot, vm_prot_t *maxprot)
+pax_setup_elf_flags(struct lwp *l, uint32_t elf_flags)
 {
-	uint32_t f;
+	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;
+		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;
+}
 
-	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))
+void
+pax_mprotect(struct lwp *l, vm_prot_t *prot, vm_prot_t *maxprot)
+{
+	uint32_t flags;
+
+	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 @@ pax_mprotect(struct lwp *l, vm_prot_t *p
 #endif /* PAX_MPROTECT */
 
 #ifdef PAX_ASLR
-bool
-pax_aslr_active(struct lwp *l)
+static bool
+pax_aslr_elf_flags_active(uint32_t flags)
 {
-	uint32_t f;
-
 	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;
+}
 
-	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))
+bool
+pax_aslr_active(struct lwp *l)
+{
+	uint32_t flags = l->l_proc->p_pax;
+	if (!(flags & P_PAX_ASLR))
 		return false;
 	return true;
 }
@@ -315,23 +396,17 @@ pax_aslr(struct lwp *l, vaddr_t *addr, v
 		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 @@ pax_aslr_stack(struct lwp *l, struct exe
 		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 @@ pax_aslr_stack(struct lwp *l, struct exe
 #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 @@ pax_segvguard(struct lwp *l, struct vnod
 	struct pax_segvguard_uid_entry *up;
 	struct timeval tv;
 	uid_t uid;
-	uint32_t f;
+	uint32_t flags;
 	bool have_uid;
 
-	if (!pax_segvguard_enabled)
-		return (0);
-
-	f = l->l_proc->p_pax;
-	if ((pax_segvguard_global && (f & ELF_NOTE_PAX_NOGUARD) != 0) ||
-	    (!pax_segvguard_global && (f & ELF_NOTE_PAX_GUARD) == 0))
-		return (0);
+	flags = l->l_proc->p_pax;
+	if (!(flags & P_PAX_GUARD))
+		return 0;
 
 	if (vp == NULL)
 		return (EFAULT);	

Index: src/sys/sys/exec_elf.h
diff -u src/sys/sys/exec_elf.h:1.148 src/sys/sys/exec_elf.h:1.149
--- src/sys/sys/exec_elf.h:1.148	Fri Jul 24 21:27:03 2015
+++ src/sys/sys/exec_elf.h	Thu Jul 30 15:28:18 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: exec_elf.h,v 1.148 2015/07/24 21:27:03 matt Exp $	*/
+/*	$NetBSD: exec_elf.h,v 1.149 2015/07/30 15:28:18 maxv Exp $	*/
 
 /*-
  * Copyright (c) 1994 The NetBSD Foundation, Inc.
@@ -941,7 +941,7 @@ typedef struct {
 #define ELF_NOTE_PAX_MPROTECT		0x01	/* Force enable Mprotect */
 #define ELF_NOTE_PAX_NOMPROTECT		0x02	/* Force disable Mprotect */
 #define ELF_NOTE_PAX_GUARD		0x04	/* Force enable Segvguard */
-#define ELF_NOTE_PAX_NOGUARD		0x08	/* Force disable Servguard */
+#define ELF_NOTE_PAX_NOGUARD		0x08	/* Force disable Segvguard */
 #define ELF_NOTE_PAX_ASLR		0x10	/* Force enable ASLR */
 #define ELF_NOTE_PAX_NOASLR		0x20	/* Force disable ASLR */
 #define ELF_NOTE_PAX_NAMESZ		4

Index: src/sys/sys/pax.h
diff -u src/sys/sys/pax.h:1.11 src/sys/sys/pax.h:1.12
--- src/sys/sys/pax.h:1.11	Thu Dec 27 15:21:53 2007
+++ src/sys/sys/pax.h	Thu Jul 30 15:28:18 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: pax.h,v 1.11 2007/12/27 15:21:53 elad Exp $ */
+/* $NetBSD: pax.h,v 1.12 2015/07/30 15:28:18 maxv Exp $ */
 
 /*-
  * Copyright (c) 2006 Elad Efrat <e...@netbsd.org>
@@ -43,9 +43,14 @@ struct vmspace;
 #ifndef PAX_ASLR_DELTA_EXEC_LEN
 #define	PAX_ASLR_DELTA_EXEC_LEN	12
 #endif
+
+#define P_PAX_ASLR	0x01	/* Enable ASLR */
+#define P_PAX_MPROTECT	0x02	/* Enable Mprotect */
+#define P_PAX_GUARD	0x04	/* Enable Segvguard */
 #endif /* PAX_ASLR */
 
 void pax_init(void);
+void pax_setup_elf_flags(struct lwp *, uint32_t);
 void pax_adjust(struct lwp *, uint32_t);
 
 void pax_mprotect(struct lwp *, vm_prot_t *, vm_prot_t *);

Reply via email to