From bf8c1f990d155c5375b24ac188f46d675e119d71 Mon Sep 17 00:00:00 2001 From: Jamie Gritton Date: Wed, 24 Jun 2009 15:29:36 +0000 Subject: [PATCH] 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) --- sys/kern/kern_vimage.c | 47 ++++++++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 20 deletions(-) diff --git a/sys/kern/kern_vimage.c b/sys/kern/kern_vimage.c index 90af1ad93bec..9ee3e1dc4640 100644 --- a/sys/kern/kern_vimage.c +++ b/sys/kern/kern_vimage.c @@ -117,9 +117,11 @@ vi_if_move(struct thread *td, struct ifnet *ifp, char *ifname, int jid, 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 ifnet *ifp, char *ifname, int jid, 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 ifnet *ifp, char *ifname, int jid, 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); + 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); - /* 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); } /*