Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 29 May 2012 19:47:06 +0000 (UTC)
From:      Edward Tomasz Napierala <trasz@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r236253 - in stable/9/sys: kern sys
Message-ID:  <201205291947.q4TJl6Zf099055@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: trasz
Date: Tue May 29 19:47:06 2012
New Revision: 236253
URL: http://svn.freebsd.org/changeset/base/236253

Log:
  MFC r232598:
  
  Make racct and rctl correctly handle jail renaming.  Previously
  they would continue using old name, the one jail was created with.
  
  PR:		bin/165207
  
  MFC r235795:
  
  Don't leak locks in prison_racct_modify().
  
  MFC r235803:
  
  Fix use-after-free in kern_jail_set() triggered e.g. by attempts
  to clear "persist" flag from empty persistent jail, like this:
  
  jail -c persist=1
  jail -n 1 -m persist=0

Modified:
  stable/9/sys/kern/kern_jail.c
  stable/9/sys/kern/kern_racct.c
  stable/9/sys/sys/racct.h
Directory Properties:
  stable/9/sys/   (props changed)

Modified: stable/9/sys/kern/kern_jail.c
==============================================================================
--- stable/9/sys/kern/kern_jail.c	Tue May 29 19:46:42 2012	(r236252)
+++ stable/9/sys/kern/kern_jail.c	Tue May 29 19:47:06 2012	(r236253)
@@ -130,6 +130,7 @@ static char *prison_path(struct prison *
 static void prison_remove_one(struct prison *pr);
 #ifdef RACCT
 static void prison_racct_attach(struct prison *pr);
+static void prison_racct_modify(struct prison *pr);
 static void prison_racct_detach(struct prison *pr);
 #endif
 #ifdef INET
@@ -1810,6 +1811,16 @@ kern_jail_set(struct thread *td, struct 
 		}
 	}
 
+#ifdef RACCT
+	if (!created) {
+		sx_sunlock(&allprison_lock);
+		prison_racct_modify(pr);
+		sx_slock(&allprison_lock);
+	}
+#endif
+
+	td->td_retval[0] = pr->pr_id;
+
 	/*
 	 * Now that it is all there, drop the temporary reference from existing
 	 * prisons.  Or add a reference to newly created persistent prisons
@@ -1830,7 +1841,7 @@ kern_jail_set(struct thread *td, struct 
 		if (!(flags & JAIL_ATTACH))
 			sx_sunlock(&allprison_lock);
 	}
-	td->td_retval[0] = pr->pr_id;
+
 	goto done_errmsg;
 
  done_deref_locked:
@@ -4427,24 +4438,32 @@ prison_racct_hold(struct prison_racct *p
 	refcount_acquire(&prr->prr_refcount);
 }
 
+static void
+prison_racct_free_locked(struct prison_racct *prr)
+{
+
+	sx_assert(&allprison_lock, SA_XLOCKED);
+
+	if (refcount_release(&prr->prr_refcount)) {
+		racct_destroy(&prr->prr_racct);
+		LIST_REMOVE(prr, prr_next);
+		free(prr, M_PRISON_RACCT);
+	}
+}
+
 void
 prison_racct_free(struct prison_racct *prr)
 {
 	int old;
 
+	sx_assert(&allprison_lock, SA_UNLOCKED);
+
 	old = prr->prr_refcount;
 	if (old > 1 && atomic_cmpset_int(&prr->prr_refcount, old, old - 1))
 		return;
 
 	sx_xlock(&allprison_lock);
-	if (refcount_release(&prr->prr_refcount)) {
-		racct_destroy(&prr->prr_racct);
-		LIST_REMOVE(prr, prr_next);
-		sx_xunlock(&allprison_lock);
-		free(prr, M_PRISON_RACCT);
-
-		return;
-	}
+	prison_racct_free_locked(prr);
 	sx_xunlock(&allprison_lock);
 }
 
@@ -4454,15 +4473,66 @@ prison_racct_attach(struct prison *pr)
 {
 	struct prison_racct *prr;
 
+	sx_assert(&allprison_lock, SA_XLOCKED);
+
 	prr = prison_racct_find_locked(pr->pr_name);
 	KASSERT(prr != NULL, ("cannot find prison_racct"));
 
 	pr->pr_prison_racct = prr;
 }
 
+/*
+ * Handle jail renaming.  From the racct point of view, renaming means
+ * moving from one prison_racct to another.
+ */
+static void
+prison_racct_modify(struct prison *pr)
+{
+	struct proc *p;
+	struct ucred *cred;
+	struct prison_racct *oldprr;
+
+	sx_slock(&allproc_lock);
+	sx_xlock(&allprison_lock);
+
+	if (strcmp(pr->pr_name, pr->pr_prison_racct->prr_name) == 0) {
+		sx_xunlock(&allprison_lock);
+		sx_sunlock(&allproc_lock);
+		return;
+	}
+
+	oldprr = pr->pr_prison_racct;
+	pr->pr_prison_racct = NULL;
+
+	prison_racct_attach(pr);
+
+	/*
+	 * Move resource utilisation records.
+	 */
+	racct_move(pr->pr_prison_racct->prr_racct, oldprr->prr_racct);
+
+	/*
+	 * Force rctl to reattach rules to processes.
+	 */
+	FOREACH_PROC_IN_SYSTEM(p) {
+		PROC_LOCK(p);
+		cred = crhold(p->p_ucred);
+		PROC_UNLOCK(p);
+		racct_proc_ucred_changed(p, cred, cred);
+		crfree(cred);
+	}
+
+	sx_sunlock(&allproc_lock);
+	prison_racct_free_locked(oldprr);
+	sx_xunlock(&allprison_lock);
+}
+
 static void
 prison_racct_detach(struct prison *pr)
 {
+
+	sx_assert(&allprison_lock, SA_UNLOCKED);
+
 	prison_racct_free(pr->pr_prison_racct);
 	pr->pr_prison_racct = NULL;
 }

Modified: stable/9/sys/kern/kern_racct.c
==============================================================================
--- stable/9/sys/kern/kern_racct.c	Tue May 29 19:46:42 2012	(r236252)
+++ stable/9/sys/kern/kern_racct.c	Tue May 29 19:47:06 2012	(r236253)
@@ -679,6 +679,18 @@ racct_proc_ucred_changed(struct proc *p,
 #endif
 }
 
+void
+racct_move(struct racct *dest, struct racct *src)
+{
+
+	mtx_lock(&racct_lock);
+
+	racct_add_racct(dest, src);
+	racct_sub_racct(src, src);
+
+	mtx_unlock(&racct_lock);
+}
+
 static void
 racctd(void)
 {

Modified: stable/9/sys/sys/racct.h
==============================================================================
--- stable/9/sys/sys/racct.h	Tue May 29 19:46:42 2012	(r236252)
+++ stable/9/sys/sys/racct.h	Tue May 29 19:47:06 2012	(r236253)
@@ -142,5 +142,6 @@ void	racct_proc_exit(struct proc *p);
 
 void	racct_proc_ucred_changed(struct proc *p, struct ucred *oldcred,
 	    struct ucred *newcred);
+void	racct_move(struct racct *dest, struct racct *src);
 
 #endif /* !_RACCT_H_ */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201205291947.q4TJl6Zf099055>