Module Name:    src
Committed By:   ad
Date:           Sun Dec  1 15:27:58 UTC 2019

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

Log Message:
Fix a longstanding problem with LWP limits.  When changing the user's
LWP count, we must use the process credentials because that's what
the accounting entity is tied to.

Reported-by: [email protected]


To generate a diff of this commit:
cvs rdiff -u -r1.214 -r1.215 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_lwp.c
diff -u src/sys/kern/kern_lwp.c:1.214 src/sys/kern/kern_lwp.c:1.215
--- src/sys/kern/kern_lwp.c:1.214	Sun Nov 24 13:23:57 2019
+++ src/sys/kern/kern_lwp.c	Sun Dec  1 15:27:58 2019
@@ -1,4 +1,4 @@
-/*	$NetBSD: kern_lwp.c,v 1.214 2019/11/24 13:23:57 ad Exp $	*/
+/*	$NetBSD: kern_lwp.c,v 1.215 2019/12/01 15:27:58 ad Exp $	*/
 
 /*-
  * Copyright (c) 2001, 2006, 2007, 2008, 2009, 2019 The NetBSD Foundation, Inc.
@@ -209,7 +209,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.214 2019/11/24 13:23:57 ad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: kern_lwp.c,v 1.215 2019/12/01 15:27:58 ad Exp $");
 
 #include "opt_ddb.h"
 #include "opt_lockdebug.h"
@@ -771,17 +771,21 @@ lwp_create(lwp_t *l1, proc_t *p2, vaddr_
     lwp_t **rnewlwpp, int sclass, const sigset_t *sigmask,
     const stack_t *sigstk)
 {
-	struct lwp *l2, *isfree;
+	struct lwp *l2;
 	turnstile_t *ts;
 	lwpid_t lid;
 
 	KASSERT(l1 == curlwp || l1->l_proc == &proc0);
 
 	/*
-	 * Enforce limits, excluding the first lwp and kthreads.
+	 * Enforce limits, excluding the first lwp and kthreads.  We must
+	 * use the process credentials here when adjusting the limit, as
+	 * they are what's tied to the accounting entity.  However for
+	 * authorizing the action, we'll use the LWP's credentials.
 	 */
+	mutex_enter(p2->p_lock);
 	if (p2->p_nlwps != 0 && p2 != &proc0) {
-		uid_t uid = kauth_cred_getuid(l1->l_cred);
+		uid_t uid = kauth_cred_getuid(p2->p_cred);
 		int count = chglwpcnt(uid, 1);
 		if (__predict_false(count >
 		    p2->p_rlimit[RLIMIT_NTHR].rlim_cur)) {
@@ -791,6 +795,7 @@ lwp_create(lwp_t *l1, proc_t *p2, vaddr_
 			    &p2->p_rlimit[RLIMIT_NTHR], KAUTH_ARG(RLIMIT_NTHR))
 			    != 0) {
 				(void)chglwpcnt(uid, -1);
+				mutex_exit(p2->p_lock);
 				return EAGAIN;
 			}
 		}
@@ -800,27 +805,21 @@ lwp_create(lwp_t *l1, proc_t *p2, vaddr_
 	 * First off, reap any detached LWP waiting to be collected.
 	 * We can re-use its LWP structure and turnstile.
 	 */
-	isfree = NULL;
-	if (p2->p_zomblwp != NULL) {
-		mutex_enter(p2->p_lock);
-		if ((isfree = p2->p_zomblwp) != NULL) {
-			p2->p_zomblwp = NULL;
-			lwp_free(isfree, true, false);/* releases proc mutex */
-		} else
-			mutex_exit(p2->p_lock);
-	}
-	if (isfree == NULL) {
-		l2 = pool_cache_get(lwp_cache, PR_WAITOK);
-		memset(l2, 0, sizeof(*l2));
-		l2->l_ts = pool_cache_get(turnstile_cache, PR_WAITOK);
-		SLIST_INIT(&l2->l_pi_lenders);
-	} else {
-		l2 = isfree;
+	if ((l2 = p2->p_zomblwp) != NULL) {
+		p2->p_zomblwp = NULL;
+		lwp_free(l2, true, false);
+		/* p2 now unlocked by lwp_free() */
 		ts = l2->l_ts;
 		KASSERT(l2->l_inheritedprio == -1);
 		KASSERT(SLIST_EMPTY(&l2->l_pi_lenders));
 		memset(l2, 0, sizeof(*l2));
 		l2->l_ts = ts;
+	} else {
+		mutex_exit(p2->p_lock);
+		l2 = pool_cache_get(lwp_cache, PR_WAITOK);
+		memset(l2, 0, sizeof(*l2));
+		l2->l_ts = pool_cache_get(turnstile_cache, PR_WAITOK);
+		SLIST_INIT(&l2->l_pi_lenders);
 	}
 
 	l2->l_stat = LSIDL;

Reply via email to