tech-kern archive

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

PaX: Heritage bug - Take 2



[I sent this mail some days ago, but it didn't reach tech-kern@.]

	http://marc.info/?l=netbsd-tech-kern&m=142486844004373&w=2

Here is a new patch. Now, the PaX flag is converted and registered
into the exec package by the loaders (only one loader does that, the
native ELF). And right before launching the process, the flag is set
in the proc structure - if it fails, the process is aborted, so this
is not that bad. In the meantime, all the PaX operations read the
exec package's flag instead of the LWP's.

Important note, for the record:
In exec_subr.c, exec_setup_stack() is called from the loaders, so it
must read the exec package's flag. However, the other vmcmd_xx()
functions are called when setting up the proc address space, which is
done way later in execve_dovmcmds(); and they must therefore read the
LWP's flag. A particular order must be followed:
 - The loaders set the exec package's PaX flag
 - The loaders call exec_setup_stack(), which does not require a PaX
   initialization. Which is perfectly fine, since nothing has been
   initialized for the moment.
 - Here, if the loaders return an error, the calling process's PaX
   flag is not overwritten.
 - Later, the proc's PaX flag is overwritten. It is set right after
   killing the LWPs associated to that proc, and right before calling
   pax_aslr_init_vm(). pax_aslr_init_vm() reads the proc's PaX flag,
   so that's fine.
 - Right after pax_aslr_init_vm(), execve_dovmcmds() is called, and
   reads the proc's PaX flag, and expects PaX to be initialized. Which
   is perfectly fine too.
 - So now everything is ok; and if the execution fails, the process is
   aborted.

Please review this change before I commit it (if you understood
something). Thanks.

(Aside note: there may still be an inconsistency in check_exec(); it's
 not a big deal, and I'll fix it soon. Also there's a useless #ifdef
 in pax.h, I'll fix it too.)

Index: sys/pax.h
===================================================================
RCS file: /cvsroot/src/sys/sys/pax.h,v
retrieving revision 1.13
diff -u -r1.13 pax.h
--- sys/pax.h	31 Jul 2015 07:37:17 -0000	1.13
+++ sys/pax.h	31 Jul 2015 09:10:11 -0000
@@ -50,7 +50,7 @@
 #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_adjust(struct lwp *, uint32_t);

 void pax_mprotect(struct lwp *, vm_prot_t *, vm_prot_t *);
@@ -58,9 +58,11 @@

 #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(struct lwp *, vaddr_t *, vaddr_t, int);

 #endif /* !_SYS_PAX_H_ */
Index: kern/exec_elf.c
===================================================================
RCS file: /cvsroot/src/sys/kern/exec_elf.c,v
retrieving revision 1.73
diff -u -r1.73 exec_elf.c
--- kern/exec_elf.c	30 Jul 2015 15:28:18 -0000	1.73
+++ kern/exec_elf.c	31 Jul 2015 09:10:11 -0000
@@ -116,8 +116,7 @@
 #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 @@
 			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;

@@ -701,7 +700,7 @@
 	 *
 	 * Probe functions would normally see if the interpreter (if any)
 	 * exists. Emulation packages may possibly replace the interpreter in
-	 * interp[] with a changed path (/emul/xxx/<path>).
+	 * interp with a changed path (/emul/xxx/<path>).
 	 */
 	pos = ELFDEFNNAME(NO_ADDR);
 	if (epp->ep_esch->u.elf_probe_func) {
@@ -714,12 +713,8 @@
 		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
@@ -944,8 +939,15 @@
 			    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: kern/exec_subr.c
===================================================================
RCS file: /cvsroot/src/sys/kern/exec_subr.c,v
retrieving revision 1.71
diff -u -r1.71 exec_subr.c
--- kern/exec_subr.c	29 Mar 2014 09:31:11 -0000	1.71
+++ kern/exec_subr.c	31 Jul 2015 09:10:11 -0000
@@ -408,7 +408,7 @@
 	    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: kern/kern_exec.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_exec.c,v
retrieving revision 1.413
diff -u -r1.413 kern_exec.c
--- kern/kern_exec.c	31 Jul 2015 07:37:17 -0000	1.413
+++ kern/kern_exec.c	31 Jul 2015 09:10:11 -0000
@@ -705,9 +705,9 @@
 	 */

 #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
@@ -725,7 +725,7 @@

 	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 */
@@ -1097,6 +1097,9 @@
 	/* 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: kern/kern_pax.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_pax.c,v
retrieving revision 1.30
diff -u -r1.30 kern_pax.c
--- kern/kern_pax.c	31 Jul 2015 07:37:17 -0000	1.30
+++ kern/kern_pax.c	31 Jul 2015 09:10:11 -0000
@@ -285,7 +285,7 @@
 }

 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 @@
 	}
 #endif

-	l->l_proc->p_pax = flags;
+	epp->ep_pax_flags = flags;
 }


@@ -362,15 +362,26 @@
 	return true;
 }

-bool
-pax_aslr_active(struct lwp *l)
+static inline bool
+pax_aslr_flags_active(uint32_t flags)
 {
-	uint32_t flags = l->l_proc->p_pax;
 	if (!(flags & P_PAX_ASLR))
 		return false;
 	return true;
 }

+bool
+pax_aslr_epp_active(struct exec_package *epp)
+{
+	return pax_aslr_flags_active(epp->ep_pax_flags);
+}
+
+bool
+pax_aslr_active(struct lwp *l)
+{
+	return pax_aslr_flags_active(l->l_proc->p_pax);
+}
+
 void
 pax_aslr_init_vm(struct lwp *l, struct vmspace *vm)
 {
@@ -402,19 +413,20 @@
 }

 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)) {
-		u_long d = PAX_ASLR_DELTA(cprng_fast32(),
-		    PAX_ASLR_DELTA_STACK_LSB,
-		    PAX_ASLR_DELTA_STACK_LEN);
-		PAX_DPRINTF("stack 0x%lx d=0x%lx 0x%lx",
-		    epp->ep_minsaddr, d, epp->ep_minsaddr - d);
-		epp->ep_minsaddr -= d;
-		*max_stack_size -= d;
-		if (epp->ep_ssize > *max_stack_size)
-			epp->ep_ssize = *max_stack_size;
-	}
+	if (!pax_aslr_epp_active(epp))
+		return;
+
+	u_long d = PAX_ASLR_DELTA(cprng_fast32(),
+	    PAX_ASLR_DELTA_STACK_LSB,
+	    PAX_ASLR_DELTA_STACK_LEN);
+	PAX_DPRINTF("stack 0x%lx d=0x%lx 0x%lx",
+	    epp->ep_minsaddr, d, epp->ep_minsaddr - d);
+	epp->ep_minsaddr -= d;
+	*max_stack_size -= d;
+	if (epp->ep_ssize > *max_stack_size)
+		epp->ep_ssize = *max_stack_size;
 }
 #endif /* PAX_ASLR */





Home | Main Index | Thread Index | Old Index