kernel - Fix coredump race with threaded processes
authorMatthew Dillon <dillon@apollo.backplane.com>
Mon, 29 Aug 2016 18:15:51 +0000 (11:15 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Mon, 29 Aug 2016 18:15:51 +0000 (11:15 -0700)
* Fix an issue where a threaded process trying to coredump could race
  and cause some threads to get stuck in tstop() when the main thread
  is trying to finally exit.  This creates an unkillable blocked process.

Reported-by: zrj, marino
sys/kern/kern_exit.c
sys/kern/kern_sig.c
sys/kern/kern_synch.c

index a1c7b86..b121ef5 100644 (file)
@@ -271,8 +271,10 @@ killlwps(struct lwp *lp)
        }
 
        /*
-        * Wait for everything to clear out.
+        * Wait for everything to clear out.  Also make sure any tstop()s
+        * are signalled (we are holding p_token for the interlock).
         */
+       wakeup(p);
        while (p->p_nthreads > 1)
                tsleep(&p->p_nthreads, 0, "killlwps", 0);
 }
index 9f15017..fbd6b02 100644 (file)
@@ -2362,7 +2362,9 @@ coredump(struct lwp *lp, int sig)
                return (EINVAL);
        error = nlookup_init(&nd, name, UIO_SYSSPACE, NLC_LOCKVP);
        if (error == 0)
-               error = vn_open(&nd, NULL, O_CREAT | FWRITE | O_NOFOLLOW, S_IRUSR | S_IWUSR);
+               error = vn_open(&nd, NULL,
+                               O_CREAT | FWRITE | O_NOFOLLOW,
+                               S_IRUSR | S_IWUSR);
        kfree(name, M_TEMP);
        if (error) {
                nlookup_done(&nd);
index 537016b..df157a2 100644 (file)
@@ -1198,9 +1198,18 @@ tstop(void)
                        PRELE(q);
                }
        }
+
+       /*
+        * Wait here while in a stopped state, interlocked with lwp_token.
+        * We must break-out if the whole process is trying to exit.
+        */
        while (p->p_stat == SSTOP || p->p_stat == SCORE) {
                lp->lwp_stat = LSSTOP;
+               if (lp->lwp_mpflags & LWP_MP_WEXIT)
+                       break;
                tsleep(p, 0, "stop", 0);
+               if (lp->lwp_mpflags & LWP_MP_WEXIT)
+                       break;
        }
        p->p_nstopped--;
        atomic_clear_int(&lp->lwp_mpflags, LWP_MP_WSTOP);