Module Name:    src
Committed By:   ad
Date:           Thu Mar 26 21:31:55 UTC 2020

Modified Files:
        src/sys/kern: kern_exit.c kern_lwp.c

Log Message:
Fix crash observed with procfs on current-users by David Hopper.  LWP refcnt
and p_zomblwp both must reach the needed state, and LSZOMB be set, under a
single hold of p_lock.


To generate a diff of this commit:
cvs rdiff -u -r1.285 -r1.286 src/sys/kern/kern_exit.c
cvs rdiff -u -r1.230 -r1.231 src/sys/kern/kern_lwp.c

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/kern_exit.c
diff -u src/sys/kern/kern_exit.c:1.285 src/sys/kern/kern_exit.c:1.286
--- src/sys/kern/kern_exit.c:1.285	Sun Mar  8 15:05:18 2020
+++ src/sys/kern/kern_exit.c	Thu Mar 26 21:31:55 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_exit.c,v 1.285 2020/03/08 15:05:18 ad Exp $	*/
+/*	$NetBSD: kern_exit.c,v 1.286 2020/03/26 21:31:55 ad Exp $	*/
 
 /*-
  * Copyright (c) 1998, 1999, 2006, 2007, 2008, 2020 The NetBSD Foundation, Inc.
@@ -67,7 +67,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.285 2020/03/08 15:05:18 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_exit.c,v 1.286 2020/03/26 21:31:55 ad Exp $");
 
 #include "opt_ktrace.h"
 #include "opt_dtrace.h"
@@ -559,7 +559,9 @@ exit1(struct lwp *l, int exitcode, int s
 	/* Free the linux lwp id */
 	if ((l->l_pflag & LP_PIDLID) != 0 && l->l_lid != p->p_pid)
 		proc_free_pid(l->l_lid);
-	lwp_drainrefs(l);
+	if (l->l_refcnt > 0) {
+		lwp_drainrefs(l);
+	}
 	lwp_lock(l);
 	l->l_prflag &= ~LPR_DETACHED;
 	l->l_stat = LSZOMB;

Index: src/sys/kern/kern_lwp.c
diff -u src/sys/kern/kern_lwp.c:1.230 src/sys/kern/kern_lwp.c:1.231
--- src/sys/kern/kern_lwp.c:1.230	Thu Mar 26 20:19:06 2020
+++ src/sys/kern/kern_lwp.c	Thu Mar 26 21:31:55 2020
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_lwp.c,v 1.230 2020/03/26 20:19:06 ad Exp $	*/
+/*	$NetBSD: kern_lwp.c,v 1.231 2020/03/26 21:31:55 ad Exp $	*/
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008, 2009, 2019, 2020
@@ -211,7 +211,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.230 2020/03/26 20:19:06 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.231 2020/03/26 21:31:55 ad Exp $");
 
 #include "opt_ddb.h"
 #include "opt_lockdebug.h"
@@ -274,7 +274,7 @@ struct lwp lwp0 __aligned(MIN_LWP_ALIGNM
 	.l_stat = LSONPROC,
 	.l_ts = &turnstile0,
 	.l_syncobj = &sched_syncobj,
-	.l_refcnt = 1,
+	.l_refcnt = 0,
 	.l_priority = PRI_USER + NPRI_USER - 1,
 	.l_inheritedprio = -1,
 	.l_class = SCHED_OTHER,
@@ -821,7 +821,7 @@ lwp_create(lwp_t *l1, proc_t *p2, vaddr_
 
 	l2->l_stat = LSIDL;
 	l2->l_proc = p2;
-	l2->l_refcnt = 1;
+	l2->l_refcnt = 0;
 	l2->l_class = sclass;
 
 	/*
@@ -1180,19 +1180,27 @@ lwp_exit(struct lwp *l)
 	 * mark it waiting for collection in the proc structure.  Note that
 	 * before we can do that, we need to free any other dead, deatched
 	 * LWP waiting to meet its maker.
+	 *
+	 * All conditions need to be observed upon under the same hold of
+	 * p_lock, because if the lock is dropped any of them can change.
 	 */
 	mutex_enter(p->p_lock);
-	lwp_drainrefs(l);
-
-	if ((l->l_prflag & LPR_DETACHED) != 0) {
-		while ((l2 = p->p_zomblwp) != NULL) {
-			p->p_zomblwp = NULL;
-			lwp_free(l2, false, false);/* releases proc mutex */
-			mutex_enter(p->p_lock);
-			l->l_refcnt++;
+	for (;;) {
+		if (l->l_refcnt > 0) {
 			lwp_drainrefs(l);
+			continue;
+		}
+		if ((l->l_prflag & LPR_DETACHED) != 0) {
+			if ((l2 = p->p_zomblwp) != NULL) {
+				p->p_zomblwp = NULL;
+				lwp_free(l2, false, false);
+				/* proc now unlocked */
+				mutex_enter(p->p_lock);
+				continue;
+			}
+			p->p_zomblwp = l;
 		}
-		p->p_zomblwp = l;
+		break;
 	}
 
 	/*
@@ -1692,7 +1700,6 @@ lwp_addref(struct lwp *l)
 
 	KASSERT(mutex_owned(l->l_proc->p_lock));
 	KASSERT(l->l_stat != LSZOMB);
-	KASSERT(l->l_refcnt != 0);
 
 	l->l_refcnt++;
 }
@@ -1724,6 +1731,7 @@ lwp_delref2(struct lwp *l)
 	KASSERT(mutex_owned(p->p_lock));
 	KASSERT(l->l_stat != LSZOMB);
 	KASSERT(l->l_refcnt > 0);
+
 	if (--l->l_refcnt == 0)
 		cv_broadcast(&p->p_lwpcv);
 }
@@ -1737,10 +1745,8 @@ lwp_drainrefs(struct lwp *l)
 	struct proc *p = l->l_proc;
 
 	KASSERT(mutex_owned(p->p_lock));
-	KASSERT(l->l_refcnt != 0);
 
-	l->l_refcnt--;
-	while (l->l_refcnt != 0)
+	while (l->l_refcnt > 0)
 		cv_wait(&p->p_lwpcv, p->p_lock);
 }
 

Reply via email to