Source-Changes-HG archive

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

[src/trunk]: src/sys fork1: fix use-after-free problems. Addresses PR/46128 ...



details:   https://anonhg.NetBSD.org/src/rev/b25952100800
branches:  trunk
changeset: 780414:b25952100800
user:      rmind <rmind%NetBSD.org@localhost>
date:      Sun Jul 22 22:40:18 2012 +0000

description:
fork1: fix use-after-free problems.  Addresses PR/46128 from Andrew Doran.
Note: PL_PPWAIT should be fully replaced and modificaiton of l_pflag by
other LWP is undesirable, but this is enough for netbsd-6.

diffstat:

 sys/kern/kern_exec.c |  13 ++++++++++---
 sys/kern/kern_exit.c |  12 +++++++++---
 sys/kern/kern_fork.c |  40 +++++++++++++++++++++++-----------------
 sys/kern/kern_lwp.c  |   7 +++++--
 sys/sys/lwp.h        |   8 +++++---
 sys/sys/proc.h       |   5 +++--
 6 files changed, 55 insertions(+), 30 deletions(-)

diffs (258 lines):

diff -r 8ab5e18136f5 -r b25952100800 sys/kern/kern_exec.c
--- a/sys/kern/kern_exec.c      Sun Jul 22 21:05:26 2012 +0000
+++ b/sys/kern/kern_exec.c      Sun Jul 22 22:40:18 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_exec.c,v 1.352 2012/05/02 23:33:11 rmind Exp $    */
+/*     $NetBSD: kern_exec.c,v 1.353 2012/07/22 22:40:19 rmind 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.352 2012/05/02 23:33:11 rmind Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.353 2012/07/22 22:40:19 rmind Exp $");
 
 #include "opt_exec.h"
 #include "opt_ktrace.h"
@@ -1180,10 +1180,17 @@
         * exited and exec()/exit() are the only places it will be cleared.
         */
        if ((p->p_lflag & PL_PPWAIT) != 0) {
+               lwp_t *lp;
+
                mutex_enter(proc_lock);
+               lp = p->p_vforklwp;
+               p->p_vforklwp = NULL;
+
                l->l_lwpctl = NULL; /* was on loan from blocked parent */
                p->p_lflag &= ~PL_PPWAIT;
-               cv_broadcast(&p->p_pptr->p_waitcv);
+
+               lp->l_pflag &= ~LP_VFORKWAIT; /* XXX */
+               cv_broadcast(&lp->l_waitcv);
                mutex_exit(proc_lock);
        }
 
diff -r 8ab5e18136f5 -r b25952100800 sys/kern/kern_exit.c
--- a/sys/kern/kern_exit.c      Sun Jul 22 21:05:26 2012 +0000
+++ b/sys/kern/kern_exit.c      Sun Jul 22 22:40:18 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_exit.c,v 1.238 2012/04/08 11:27:45 martin Exp $   */
+/*     $NetBSD: kern_exit.c,v 1.239 2012/07/22 22:40:19 rmind Exp $    */
 
 /*-
  * Copyright (c) 1998, 1999, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.238 2012/04/08 11:27:45 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.239 2012/07/22 22:40:19 rmind Exp $");
 
 #include "opt_ktrace.h"
 #include "opt_perfctrs.h"
@@ -330,9 +330,15 @@
         */
        mutex_enter(proc_lock);
        if (p->p_lflag & PL_PPWAIT) {
+               lwp_t *lp;
+
                l->l_lwpctl = NULL; /* was on loan from blocked parent */
                p->p_lflag &= ~PL_PPWAIT;
-               cv_broadcast(&p->p_pptr->p_waitcv);
+
+               lp = p->p_vforklwp;
+               p->p_vforklwp = NULL;
+               lp->l_pflag &= ~LP_VFORKWAIT; /* XXX */
+               cv_broadcast(&lp->l_waitcv);
        }
 
        if (SESS_LEADER(p)) {
diff -r 8ab5e18136f5 -r b25952100800 sys/kern/kern_fork.c
--- a/sys/kern/kern_fork.c      Sun Jul 22 21:05:26 2012 +0000
+++ b/sys/kern/kern_fork.c      Sun Jul 22 22:40:18 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_fork.c,v 1.189 2012/03/13 18:40:52 elad Exp $     */
+/*     $NetBSD: kern_fork.c,v 1.190 2012/07/22 22:40:19 rmind Exp $    */
 
 /*-
  * Copyright (c) 1999, 2001, 2004, 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_fork.c,v 1.189 2012/03/13 18:40:52 elad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_fork.c,v 1.190 2012/07/22 22:40:19 rmind Exp $");
 
 #include "opt_ktrace.h"
 
@@ -373,7 +373,14 @@
                p2->p_limit = lim_copy(p1_lim);
        }
 
-       p2->p_lflag = ((flags & FORK_PPWAIT) ? PL_PPWAIT : 0);
+       if (flags & FORK_PPWAIT) {
+               /* Mark ourselves as waiting for a child. */
+               l1->l_pflag |= LP_VFORKWAIT;
+               p2->p_lflag = PL_PPWAIT;
+               p2->p_vforklwp = l1;
+       } else {
+               p2->p_lflag = 0;
+       }
        p2->p_sflag = 0;
        p2->p_slflag = 0;
        parent = (flags & FORK_NOWAIT) ? initproc : p1;
@@ -565,15 +572,24 @@
                sched_enqueue(l2, false);
                lwp_unlock(l2);
        }
+
+       /*
+        * Return child pid to parent process,
+        * marking us as parent via retval[1].
+        */
+       if (retval != NULL) {
+               retval[0] = p2->p_pid;
+               retval[1] = 0;
+       }
        mutex_exit(p2->p_lock);
 
        /*
         * Preserve synchronization semantics of vfork.  If waiting for
-        * child to exec or exit, set PL_PPWAIT on child, and sleep on our
-        * proc (in case of exit).
+        * child to exec or exit, sleep until it clears LP_VFORKWAIT.
         */
-       while (p2->p_lflag & PL_PPWAIT)
-               cv_wait(&p1->p_waitcv, proc_lock);
+       while (l1->l_pflag & LP_VFORKWAIT) {
+               cv_wait(&l1->l_waitcv, proc_lock);
+       }
 
        /*
         * Let the parent know that we are tracing its child.
@@ -586,17 +602,7 @@
                ksi.ksi_lid = l1->l_lid;
                kpsignal(p1, &ksi, NULL);
        }
-
        mutex_exit(proc_lock);
 
-       /*
-        * Return child pid to parent process,
-        * marking us as parent via retval[1].
-        */
-       if (retval != NULL) {
-               retval[0] = p2->p_pid;
-               retval[1] = 0;
-       }
-
        return 0;
 }
diff -r 8ab5e18136f5 -r b25952100800 sys/kern/kern_lwp.c
--- a/sys/kern/kern_lwp.c       Sun Jul 22 21:05:26 2012 +0000
+++ b/sys/kern/kern_lwp.c       Sun Jul 22 22:40:18 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: kern_lwp.c,v 1.170 2012/06/09 02:55:32 christos Exp $  */
+/*     $NetBSD: kern_lwp.c,v 1.171 2012/07/22 22:40:19 rmind Exp $     */
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -211,7 +211,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.170 2012/06/09 02:55:32 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.171 2012/07/22 22:40:19 rmind Exp $");
 
 #include "opt_ddb.h"
 #include "opt_lockdebug.h"
@@ -356,6 +356,7 @@
        callout_init(&l->l_timeout_ch, CALLOUT_MPSAFE);
        callout_setfunc(&l->l_timeout_ch, sleepq_timeout, l);
        cv_init(&l->l_sigcv, "sigwait");
+       cv_init(&l->l_waitcv, "vfork");
 
        kauth_cred_hold(proc0.p_cred);
        l->l_cred = proc0.p_cred;
@@ -824,6 +825,7 @@
        callout_init(&l2->l_timeout_ch, CALLOUT_MPSAFE);
        callout_setfunc(&l2->l_timeout_ch, sleepq_timeout, l2);
        cv_init(&l2->l_sigcv, "sigwait");
+       cv_init(&l2->l_waitcv, "vfork");
        l2->l_syncobj = &sched_syncobj;
 
        if (rnewlwpp != NULL)
@@ -1162,6 +1164,7 @@
        sigclear(&l->l_sigpend, NULL, &kq);
        ksiginfo_queue_drain(&kq);
        cv_destroy(&l->l_sigcv);
+       cv_destroy(&l->l_waitcv);
 
        /*
         * Free lwpctl structure and affinity.
diff -r 8ab5e18136f5 -r b25952100800 sys/sys/lwp.h
--- a/sys/sys/lwp.h     Sun Jul 22 21:05:26 2012 +0000
+++ b/sys/sys/lwp.h     Sun Jul 22 22:40:18 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: lwp.h,v 1.162 2012/06/09 02:31:15 christos Exp $       */
+/*     $NetBSD: lwp.h,v 1.163 2012/07/22 22:40:18 rmind Exp $  */
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008, 2009, 2010
@@ -53,9 +53,9 @@
 #include <machine/proc.h>              /* Machine-dependent proc substruct. */
 
 /*
- * Lightweight process.  Field markings and the corresponding locks: 
+ * Lightweight process.  Field markings and the corresponding locks:
  *
- * a:  proclist_lock
+ * a:  proc_lock
  * c:  condition variable interlock, passed to cv_wait()
  * l:  *l_mutex
  * p:  l_proc->p_lock
@@ -124,6 +124,7 @@
        u_int           l_slptime;      /* l: time since last blocked */
        callout_t       l_timeout_ch;   /* !: callout for tsleep */
        u_int           l_emap_gen;     /* !: emap generation number */
+       kcondvar_t      l_waitcv;       /* a: vfork() wait */
 
 #if PCU_UNIT_COUNT > 0
        struct cpu_info * volatile l_pcu_cpu[PCU_UNIT_COUNT];
@@ -245,6 +246,7 @@
 #define        LP_INTR         0x00000040 /* Soft interrupt handler */
 #define        LP_SYSCTLWRITE  0x00000080 /* sysctl write lock held */
 #define        LP_MUSTJOIN     0x00000100 /* Must join kthread on exit */
+#define        LP_VFORKWAIT    0x00000200 /* Waiting at vfork() for a child */
 #define        LP_TIMEINTR     0x00010000 /* Time this soft interrupt */
 #define        LP_RUNNING      0x20000000 /* Active on a CPU */
 #define        LP_BOUND        0x80000000 /* Bound to a CPU */
diff -r 8ab5e18136f5 -r b25952100800 sys/sys/proc.h
--- a/sys/sys/proc.h    Sun Jul 22 21:05:26 2012 +0000
+++ b/sys/sys/proc.h    Sun Jul 22 22:40:18 2012 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: proc.h,v 1.316 2012/02/19 21:06:58 rmind Exp $ */
+/*     $NetBSD: proc.h,v 1.317 2012/07/22 22:40:18 rmind Exp $ */
 
 /*-
  * Copyright (c) 2006, 2007, 2008 The NetBSD Foundation, Inc.
@@ -212,7 +212,7 @@
        krwlock_t       p_reflock;      /* p: lock for debugger, procfs */
        kcondvar_t      p_waitcv;       /* p: wait, stop CV on children */
        kcondvar_t      p_lwpcv;        /* p: wait, stop CV on LWPs */
-      
+
        /* Substructures: */
        struct kauth_cred *p_cred;      /* p: Master copy of credentials */
        struct filedesc *p_fd;          /* :: Ptr to open files structure */
@@ -256,6 +256,7 @@
        u_int           p_nstopchild;   /* l: Count of stopped/dead children */
        u_int           p_waited;       /* l: parent has waited on child */
        struct lwp      *p_zomblwp;     /* p: detached LWP to be reaped */
+       struct lwp      *p_vforklwp;    /* p: parent LWP waiting at vfork() */
 
        /* scheduling */
        void            *p_sched_info;  /* p: Scheduler-specific structure */



Home | Main Index | Thread Index | Old Index