diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -1688,8 +1688,12 @@ #ifdef VIMAGE /* Allocate a new vnet if specified. */ - pr->pr_vnet = (pr_flags & PR_VNET) - ? vnet_alloc() : ppr->pr_vnet; + if (pr_flags & PR_VNET) { + pr->pr_vnet = vnet_alloc(); + pr->pr_flags |= PR_VNET_ROOT; + } else { + pr->pr_vnet = ppr->pr_vnet; + } #endif /* * Allocate a dedicated cpuset for each jail. @@ -3207,9 +3211,12 @@ * Removing a prison frees references * from its parent. */ + ppr = pr->pr_parent; + pr->pr_parent = NULL; mtx_unlock(&pr->pr_mtx); + + pr = ppr; flags &= ~PD_LOCKED; - pr = pr->pr_parent; flags |= PD_DEREF | PD_DEUREF; continue; } @@ -3236,7 +3243,7 @@ */ TAILQ_FOREACH_SAFE(rpr, &freeprison, pr_list, tpr) { #ifdef VIMAGE - if (rpr->pr_vnet != rpr->pr_parent->pr_vnet) + if (rpr->pr_flags & PR_VNET_ROOT) vnet_destroy(rpr->pr_vnet); #endif if (rpr->pr_root != NULL) @@ -3283,8 +3290,9 @@ mtx_unlock(&pr->pr_mtx); rpr = NULL; - FOREACH_PRISON_DESCENDANT_PRE_POST(pr, cpr, descend) { + FOREACH_PRISON_DESCENDANT_PRE_POST(pr, cpr, ppr, descend) { if (descend) { + ppr = cpr->pr_parent; if (!prison_isalive(cpr)) { descend = false; continue; @@ -3329,6 +3337,10 @@ prison_free_not_last(ppr); for (; ppr != NULL; ppr = ppr->pr_parent) ppr->pr_childcount--; + ppr = rpr->pr_parent; + rpr->pr_parent = NULL; + } else { + ppr = cpr->pr_parent; } mtx_unlock(&cpr->pr_mtx); } diff --git a/sys/sys/jail.h b/sys/sys/jail.h --- a/sys/sys/jail.h +++ b/sys/sys/jail.h @@ -234,6 +234,8 @@ /* by this jail or an ancestor */ #define PR_COMPLETE_PROC 0x08000000 /* prison_complete called from */ /* prison_proc_free, releases uref */ +#define PR_VNET_ROOT 0x10000000 /* prison's parent has a different */ + /* vnet */ /* * Flags for pr_allow @@ -353,8 +355,13 @@ /* * Traverse a prison's descendants, visiting both preorder and postorder. + * + * The consumers is to set cppr to the parent of the current prison, cpr, + * at the end of each iteration. In particular, the pr_parent field is + * set to NULL after releasing the parent reference, so we avoid dereferencing + * directly. */ -#define FOREACH_PRISON_DESCENDANT_PRE_POST(ppr, cpr, descend) \ +#define FOREACH_PRISON_DESCENDANT_PRE_POST(ppr, cpr, cppr, descend) \ for ((cpr) = (ppr), (descend) = 1; \ ((cpr) = (descend) \ ? ((descend) = !LIST_EMPTY(&(cpr)->pr_children)) \ @@ -362,7 +369,7 @@ : (cpr) \ : ((descend) = LIST_NEXT(cpr, pr_sibling) != NULL) \ ? LIST_NEXT(cpr, pr_sibling) \ - : cpr->pr_parent) != (ppr);) + : (cppr)) != (ppr);) /* * Attributes of the physical system, and the root of the jail tree.