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_ */