Module Name:    src
Committed By:   maxv
Date:           Sat Sep 26 16:12:24 UTC 2015

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

Log Message:
Revamp the way processes are PaX'ed in the kernel. Sent on tech-kern@ two
months ago, but no one reviewed it - probably because it's not a trivial
change.

This change fixes the following bug: when loading a PaX'ed binary, the
kernel updates the PaX flag of the calling process before it makes sure
the new process is actually launched. If the kernel fails to launch the
new process, it does not restore the PaX flag of the calling process,
leaving it in an inconsistent state.

Actually, simply restoring it would be horrible as well, since in the
meantime another thread may have used the flag.

The solution is therefore: modify all the functions used by PaX so that
they take as argument the exec package instead of the lwp, and set the PaX
flag in the process *right before* launching the new process - it cannot
fail in the meantime.


To generate a diff of this commit:
cvs rdiff -u -r1.76 -r1.77 src/sys/kern/exec_elf.c
cvs rdiff -u -r1.71 -r1.72 src/sys/kern/exec_subr.c
cvs rdiff -u -r1.416 -r1.417 src/sys/kern/kern_exec.c
cvs rdiff -u -r1.31 -r1.32 src/sys/kern/kern_pax.c
cvs rdiff -u -r1.15 -r1.16 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.76 src/sys/kern/exec_elf.c:1.77
--- src/sys/kern/exec_elf.c:1.76	Sat Aug  8 06:24:40 2015
+++ src/sys/kern/exec_elf.c	Sat Sep 26 16:12:24 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: exec_elf.c,v 1.76 2015/08/08 06:24:40 maxv Exp $	*/
+/*	$NetBSD: exec_elf.c,v 1.77 2015/09/26 16:12:24 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.76 2015/08/08 06:24:40 maxv Exp $");
+__KERNEL_RCSID(1, "$NetBSD: exec_elf.c,v 1.77 2015/09/26 16:12:24 maxv Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_pax.h"
@@ -116,8 +116,7 @@ static void	elf_free_emul_arg(void *);
 #define	ELF_TRUNC(a, b)		((a) & ~((b) - 1))
 
 static void
-elf_placedynexec(struct lwp *l, struct exec_package *epp, Elf_Ehdr *eh,
-    Elf_Phdr *ph)
+elf_placedynexec(struct exec_package *epp, Elf_Ehdr *eh, Elf_Phdr *ph)
 {
 	Elf_Addr align, offset;
 	int i;
@@ -127,7 +126,7 @@ elf_placedynexec(struct lwp *l, struct e
 			align = ph[i].p_align;
 
 #ifdef PAX_ASLR
-	if (pax_aslr_active(l)) {
+	if (pax_aslr_epp_active(epp)) {
 		size_t pax_align, l2, delta;
 		uint32_t r;
 
@@ -711,12 +710,8 @@ exec_elf_makecmds(struct lwp *l, struct 
 		pos = (Elf_Addr)startp;
 	}
 
-#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR)
-	pax_setup_elf_flags(l, epp->ep_pax_flags);
-#endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */
-
 	if (is_dyn)
-		elf_placedynexec(l, epp, eh, ph);
+		elf_placedynexec(epp, eh, ph);
 
 	/*
 	 * Load all the necessary sections
@@ -941,8 +936,15 @@ netbsd_elf_signature(struct lwp *l, stru
 			    np->n_descsz == ELF_NOTE_PAX_DESCSZ &&
 			    memcmp(ndata, ELF_NOTE_PAX_NAME,
 			    ELF_NOTE_PAX_NAMESZ) == 0) {
-				memcpy(&epp->ep_pax_flags, ndesc,
-				    sizeof(epp->ep_pax_flags));
+				uint32_t flags;
+				memcpy(&flags, ndesc, sizeof(flags));
+#if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR)
+				/* Convert the flags and insert them into
+				 * the exec package. */
+				pax_setup_elf_flags(epp, flags);
+#else
+				(void)flags; /* UNUSED */
+#endif /* PAX_MPROTECT || PAX_SEGVGUARD || PAX_ASLR */
 				break;
 			}
 			BADNOTE("PaX tag");

Index: src/sys/kern/exec_subr.c
diff -u src/sys/kern/exec_subr.c:1.71 src/sys/kern/exec_subr.c:1.72
--- src/sys/kern/exec_subr.c:1.71	Sat Mar 29 09:31:11 2014
+++ src/sys/kern/exec_subr.c	Sat Sep 26 16:12:24 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: exec_subr.c,v 1.71 2014/03/29 09:31:11 maxv Exp $	*/
+/*	$NetBSD: exec_subr.c,v 1.72 2015/09/26 16:12:24 maxv Exp $	*/
 
 /*
  * Copyright (c) 1993, 1994, 1996 Christopher G. Demetriou
@@ -31,7 +31,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: exec_subr.c,v 1.71 2014/03/29 09:31:11 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: exec_subr.c,v 1.72 2015/09/26 16:12:24 maxv Exp $");
 
 #include "opt_pax.h"
 
@@ -408,7 +408,7 @@ exec_setup_stack(struct lwp *l, struct e
 	    max_stack_size);
 
 #ifdef PAX_ASLR
-	pax_aslr_stack(l, epp, &max_stack_size);
+	pax_aslr_stack(epp, &max_stack_size);
 #endif /* PAX_ASLR */
 
 	l->l_proc->p_stackbase = epp->ep_minsaddr;

Index: src/sys/kern/kern_exec.c
diff -u src/sys/kern/kern_exec.c:1.416 src/sys/kern/kern_exec.c:1.417
--- src/sys/kern/kern_exec.c:1.416	Sat Sep 12 18:30:46 2015
+++ src/sys/kern/kern_exec.c	Sat Sep 26 16:12:24 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_exec.c,v 1.416 2015/09/12 18:30:46 christos Exp $	*/
+/*	$NetBSD: kern_exec.c,v 1.417 2015/09/26 16:12:24 maxv Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -59,7 +59,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.416 2015/09/12 18:30:46 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.417 2015/09/26 16:12:24 maxv Exp $");
 
 #include "opt_exec.h"
 #include "opt_execfmt.h"
@@ -753,9 +753,9 @@ execve_loadvm(struct lwp *l, const char 
 	 */
 
 #ifdef PAX_ASLR
-#define	ASLR_GAP(l)	(pax_aslr_active(l) ? (cprng_fast32() % PAGE_SIZE) : 0)
+#define	ASLR_GAP(epp)	(pax_aslr_epp_active(epp) ? (cprng_fast32() % PAGE_SIZE) : 0)
 #else
-#define	ASLR_GAP(l)	0
+#define	ASLR_GAP(epp)	0
 #endif
 
 #ifdef __MACHINE_STACK_GROWS_UP
@@ -773,7 +773,7 @@ execve_loadvm(struct lwp *l, const char 
 
 	data->ed_argslen = calcargs(data, argenvstrlen);
 
-	const size_t len = calcstack(data, ASLR_GAP(l) + RTLD_GAP);
+	const size_t len = calcstack(data, ASLR_GAP(epp) + RTLD_GAP);
 
 	if (len > epp->ep_ssize) {
 		/* in effect, compare to initial limit */
@@ -1125,6 +1125,9 @@ execve_runproc(struct lwp *l, struct exe
 	/* Remove POSIX timers */
 	timers_free(p, TIMERS_POSIX);
 
+	/* Set the PaX flags. */
+	p->p_pax = epp->ep_pax_flags;
+
 	/*
 	 * Do whatever is necessary to prepare the address space
 	 * for remapping.  Note that this might replace the current

Index: src/sys/kern/kern_pax.c
diff -u src/sys/kern/kern_pax.c:1.31 src/sys/kern/kern_pax.c:1.32
--- src/sys/kern/kern_pax.c:1.31	Tue Aug  4 18:28:09 2015
+++ src/sys/kern/kern_pax.c	Sat Sep 26 16:12:24 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_pax.c,v 1.31 2015/08/04 18:28:09 maxv Exp $	*/
+/*	$NetBSD: kern_pax.c,v 1.32 2015/09/26 16:12:24 maxv Exp $	*/
 
 /*
  * Copyright (c) 2015 The NetBSD Foundation, Inc.
@@ -57,7 +57,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_pax.c,v 1.31 2015/08/04 18:28:09 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_pax.c,v 1.32 2015/09/26 16:12:24 maxv Exp $");
 
 #include "opt_pax.h"
 
@@ -285,7 +285,7 @@ pax_init(void)
 }
 
 void
-pax_setup_elf_flags(struct lwp *l, uint32_t elf_flags)
+pax_setup_elf_flags(struct exec_package *epp, uint32_t elf_flags)
 {
 	uint32_t flags = 0;
 
@@ -305,7 +305,7 @@ pax_setup_elf_flags(struct lwp *l, uint3
 	}
 #endif
 
-	l->l_proc->p_pax = flags;
+	epp->ep_pax_flags = flags;
 }
 
 #if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR)
@@ -372,6 +372,12 @@ pax_aslr_elf_flags_active(uint32_t flags
 }
 
 bool
+pax_aslr_epp_active(struct exec_package *epp)
+{
+	return pax_flags_active(epp->ep_pax_flags, P_PAX_ASLR);
+}
+
+bool
 pax_aslr_active(struct lwp *l)
 {
 	return pax_flags_active(l->l_proc->p_pax, P_PAX_ASLR);
@@ -408,9 +414,9 @@ pax_aslr_mmap(struct lwp *l, vaddr_t *ad
 }
 
 void
-pax_aslr_stack(struct lwp *l, struct exec_package *epp, u_long *max_stack_size)
+pax_aslr_stack(struct exec_package *epp, u_long *max_stack_size)
 {
-	if (!pax_aslr_active(l))
+	if (!pax_aslr_epp_active(epp))
 		return;
 
 	u_long d = PAX_ASLR_DELTA(cprng_fast32(),

Index: src/sys/sys/pax.h
diff -u src/sys/sys/pax.h:1.15 src/sys/sys/pax.h:1.16
--- src/sys/sys/pax.h:1.15	Sat Aug 15 10:24:29 2015
+++ src/sys/sys/pax.h	Sat Sep 26 16:12:24 2015
@@ -1,4 +1,4 @@
-/* $NetBSD: pax.h,v 1.15 2015/08/15 10:24:29 maxv Exp $ */
+/* $NetBSD: pax.h,v 1.16 2015/09/26 16:12:24 maxv Exp $ */
 
 /*-
  * Copyright (c) 2006 Elad Efrat <e...@netbsd.org>
@@ -50,15 +50,17 @@ struct vmspace;
 #endif /* PAX_ASLR */
 
 void pax_init(void);
-void pax_setup_elf_flags(struct lwp *, uint32_t);
+void pax_setup_elf_flags(struct exec_package *, uint32_t);
 void pax_mprotect(struct lwp *, vm_prot_t *, vm_prot_t *);
 int pax_segvguard(struct lwp *, struct vnode *, const char *, bool);
 
 #define	PAX_ASLR_DELTA(delta, lsb, len)	\
     (((delta) & ((1UL << (len)) - 1)) << (lsb))
+
+bool pax_aslr_epp_active(struct exec_package *);
 bool pax_aslr_active(struct lwp *);
 void pax_aslr_init_vm(struct lwp *, struct vmspace *);
-void pax_aslr_stack(struct lwp *, struct exec_package *, u_long *);
+void pax_aslr_stack(struct exec_package *, u_long *);
 void pax_aslr_mmap(struct lwp *, vaddr_t *, vaddr_t, int);
 
 #endif /* !_SYS_PAX_H_ */

Reply via email to