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);
 }
 
 /*
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to