Source-Changes-HG archive

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

[src/trunk]: src/sys Revamp the way processes are PaX'ed in the kernel. Sent ...



details:   https://anonhg.NetBSD.org/src/rev/8a2878c487bc
branches:  trunk
changeset: 810872:8a2878c487bc
user:      maxv <maxv%NetBSD.org@localhost>
date:      Sat Sep 26 16:12:24 2015 +0000

description:
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.

diffstat:

 sys/kern/exec_elf.c  |  26 ++++++++++++++------------
 sys/kern/exec_subr.c |   6 +++---
 sys/kern/kern_exec.c |  13 ++++++++-----
 sys/kern/kern_pax.c  |  18 ++++++++++++------
 sys/sys/pax.h        |   8 +++++---
 5 files changed, 42 insertions(+), 29 deletions(-)

diffs (235 lines):

diff -r 701c07365810 -r 8a2878c487bc sys/kern/exec_elf.c
--- a/sys/kern/exec_elf.c       Sat Sep 26 13:59:28 2015 +0000
+++ b/sys/kern/exec_elf.c       Sat Sep 26 16:12:24 2015 +0000
@@ -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 @@
 #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;
 
@@ -711,12 +710,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
@@ -941,8 +936,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");
diff -r 701c07365810 -r 8a2878c487bc sys/kern/exec_subr.c
--- a/sys/kern/exec_subr.c      Sat Sep 26 13:59:28 2015 +0000
+++ b/sys/kern/exec_subr.c      Sat Sep 26 16:12:24 2015 +0000
@@ -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 @@
            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;
diff -r 701c07365810 -r 8a2878c487bc sys/kern/kern_exec.c
--- a/sys/kern/kern_exec.c      Sat Sep 26 13:59:28 2015 +0000
+++ b/sys/kern/kern_exec.c      Sat Sep 26 16:12:24 2015 +0000
@@ -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 @@
         */
 
 #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 @@
 
        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 @@
        /* 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
diff -r 701c07365810 -r 8a2878c487bc sys/kern/kern_pax.c
--- a/sys/kern/kern_pax.c       Sat Sep 26 13:59:28 2015 +0000
+++ b/sys/kern/kern_pax.c       Sat Sep 26 16:12:24 2015 +0000
@@ -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 @@
 }
 
 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;
 }
 
 #if defined(PAX_MPROTECT) || defined(PAX_SEGVGUARD) || defined(PAX_ASLR)
@@ -372,6 +372,12 @@
 }
 
 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 @@
 }
 
 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(),
diff -r 701c07365810 -r 8a2878c487bc sys/sys/pax.h
--- a/sys/sys/pax.h     Sat Sep 26 13:59:28 2015 +0000
+++ b/sys/sys/pax.h     Sat Sep 26 16:12:24 2015 +0000
@@ -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 <elad%NetBSD.org@localhost>
@@ -50,15 +50,17 @@
 #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_ */



Home | Main Index | Thread Index | Old Index