svn commit: r194841 - head/sys/kern

Jamie Gritton jamie at FreeBSD.org
Wed Jun 24 15:29:37 UTC 2009


Author: jamie
Date: Wed Jun 24 15:29:36 2009
New Revision: 194841
URL: http://svn.freebsd.org/changeset/base/194841

Log:
  Fix a race in vi_if_move, where a vnet is used after the prison that
  referred to it has been released.
  
  Approved by:	bz (mentor)

Modified:
  head/sys/kern/kern_vimage.c

Modified: head/sys/kern/kern_vimage.c
==============================================================================
--- head/sys/kern/kern_vimage.c	Wed Jun 24 15:24:51 2009	(r194840)
+++ head/sys/kern/kern_vimage.c	Wed Jun 24 15:29:36 2009	(r194841)
@@ -117,9 +117,11 @@ vi_if_move(struct thread *td, struct ifn
 	struct prison *pr;
 	struct vimage *new_vip, *my_vip;
 	struct vnet *new_vnet;
+	int error;
 
 	if (vi_req != NULL) {
 		/* SIOCSIFVIMAGE */
+		pr = NULL;
 		/* Check for API / ABI version mismatch. */
 		if (vi_req->vi_api_cookie != VI_API_COOKIE)
 			return (EDOOFUS);
@@ -148,6 +150,7 @@ vi_if_move(struct thread *td, struct ifn
 		sx_sunlock(&allprison_lock);
 		if (pr == NULL)
 			return (ENXIO);
+		prison_hold_locked(pr);
 		mtx_unlock(&pr->pr_mtx);
 		if (ifp != NULL) {
 			/* SIOCSIFVNET */
@@ -158,31 +161,35 @@ vi_if_move(struct thread *td, struct ifn
 			CURVNET_SET(pr->pr_vnet);
 			ifp = ifunit(ifname);
 			CURVNET_RESTORE();
-			if (ifp == NULL)
+			if (ifp == NULL) {
+				prison_free(pr);
 				return (ENXIO);
+			}
 		}
-
-		/* No-op if the target jail has the same vnet. */
-		if (new_vnet == ifp->if_vnet)
-			return (0);
 	}
 
-	/*
-	 * Check for naming clashes in target vnet.  Not locked so races
-	 * are possible.
-	 */
-	CURVNET_SET_QUIET(new_vnet);
-	t_ifp = ifunit(ifname);
-	CURVNET_RESTORE();
-	if (t_ifp != NULL)
-		return (EEXIST);
-
-	/* Detach from curvnet and attach to new_vnet. */
-	if_vmove(ifp, new_vnet);
+	error = 0;
+	if (new_vnet != ifp->if_vnet) {
+		/*
+		 * Check for naming clashes in target vnet.  Not locked so races
+		 * are possible.
+		 */
+		CURVNET_SET_QUIET(new_vnet);
+		t_ifp = ifunit(ifname);
+		CURVNET_RESTORE();
+		if (t_ifp != NULL)
+			error = EEXIST;
+		else {
+			/* Detach from curvnet and attach to new_vnet. */
+			if_vmove(ifp, new_vnet);
 
-	/* Report the new if_xname back to the userland */
-	sprintf(ifname, "%s", ifp->if_xname);
-	return (0);
+			/* Report the new if_xname back to the userland */
+			sprintf(ifname, "%s", ifp->if_xname);
+		}
+	}
+	if (pr != NULL)
+		prison_free(pr);
+	return (error);
 }
 
 /*


More information about the svn-src-head mailing list