Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_jail_27876.c
Show First 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | |||||
struct prison prison0 = { | struct prison prison0 = { | ||||
.pr_id = 0, | .pr_id = 0, | ||||
.pr_name = "0", | .pr_name = "0", | ||||
.pr_ref = 1, | .pr_ref = 1, | ||||
.pr_uref = 1, | .pr_uref = 1, | ||||
.pr_path = "/", | .pr_path = "/", | ||||
.pr_securelevel = -1, | .pr_securelevel = -1, | ||||
.pr_devfs_rsnum = 0, | .pr_devfs_rsnum = 0, | ||||
.pr_state = PRISON_STATE_ALIVE, | |||||
.pr_childmax = JAIL_MAX, | .pr_childmax = JAIL_MAX, | ||||
.pr_hostuuid = DEFAULT_HOSTUUID, | .pr_hostuuid = DEFAULT_HOSTUUID, | ||||
.pr_children = LIST_HEAD_INITIALIZER(prison0.pr_children), | .pr_children = LIST_HEAD_INITIALIZER(prison0.pr_children), | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
.pr_flags = PR_HOST|PR_VNET|_PR_IP_SADDRSEL, | .pr_flags = PR_HOST|PR_VNET|_PR_IP_SADDRSEL, | ||||
#else | #else | ||||
.pr_flags = PR_HOST|_PR_IP_SADDRSEL, | .pr_flags = PR_HOST|_PR_IP_SADDRSEL, | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 918 Lines • ▼ Show 20 Lines | if (pr != NULL) { | ||||
/* | /* | ||||
* Updaters get ENOENT if they cannot see the | * Updaters get ENOENT if they cannot see the | ||||
* jail. This is true even for CREATE | UPDATE, | * jail. This is true even for CREATE | UPDATE, | ||||
* which normally cannot give this error. | * which normally cannot give this error. | ||||
*/ | */ | ||||
error = ENOENT; | error = ENOENT; | ||||
vfs_opterror(opts, "jail %d not found", jid); | vfs_opterror(opts, "jail %d not found", jid); | ||||
goto done_deref; | goto done_deref; | ||||
} else if (!prison_isalive(pr)) { | } | ||||
if (!prison_isalive(pr)) { | |||||
if (!(flags & JAIL_DYING)) { | if (!(flags & JAIL_DYING)) { | ||||
error = ENOENT; | error = ENOENT; | ||||
vfs_opterror(opts, "jail %d is dying", | vfs_opterror(opts, "jail %d is dying", | ||||
jid); | jid); | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
if ((flags & JAIL_ATTACH) || | if ((flags & JAIL_ATTACH) || | ||||
(pr_flags & PR_PERSIST)) { | (pr_flags & PR_PERSIST)) { | ||||
▲ Show 20 Lines • Show All 143 Lines • ▼ Show 20 Lines | for (tpr = mypr; tpr != NULL; tpr = tpr->pr_parent) | ||||
vfs_opterror(opts, "prison limit exceeded"); | vfs_opterror(opts, "prison limit exceeded"); | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
prison_hold(ppr); | prison_hold(ppr); | ||||
if (!refcount_acquire_if_not_zero(&ppr->pr_uref)) { | if (!refcount_acquire_if_not_zero(&ppr->pr_uref)) { | ||||
/* This brings the parent back to life. */ | /* This brings the parent back to life. */ | ||||
mtx_lock(&ppr->pr_mtx); | mtx_lock(&ppr->pr_mtx); | ||||
refcount_acquire(&ppr->pr_uref); | refcount_acquire(&ppr->pr_uref); | ||||
if (ppr->pr_state == PRISON_STATE_DYING) | |||||
ppr->pr_state = PRISON_STATE_ALIVE; | |||||
mtx_unlock(&ppr->pr_mtx); | mtx_unlock(&ppr->pr_mtx); | ||||
error = osd_jail_call(ppr, PR_METHOD_CREATE, opts); | error = osd_jail_call(ppr, PR_METHOD_CREATE, opts); | ||||
if (error) { | if (error) { | ||||
pr = ppr; | pr = ppr; | ||||
drflags |= PD_DEREF | PD_DEUREF; | drflags |= PD_DEREF | PD_DEUREF; | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
} | } | ||||
if (jid == 0 && (jid = get_next_prid(&inspr)) == 0) { | if (jid == 0 && (jid = get_next_prid(&inspr)) == 0) { | ||||
error = EAGAIN; | error = EAGAIN; | ||||
vfs_opterror(opts, "no available jail IDs"); | vfs_opterror(opts, "no available jail IDs"); | ||||
pr = ppr; | pr = ppr; | ||||
drflags |= PD_DEREF | PD_DEUREF; | drflags |= PD_DEREF | PD_DEUREF; | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); | pr = malloc(sizeof(*pr), M_PRISON, M_WAITOK | M_ZERO); | ||||
refcount_init(&pr->pr_ref, 0); | pr->pr_state = PRISON_STATE_INVALID; | ||||
refcount_init(&pr->pr_ref, 1); | |||||
refcount_init(&pr->pr_uref, 0); | refcount_init(&pr->pr_uref, 0); | ||||
drflags |= PD_DEREF; | |||||
LIST_INIT(&pr->pr_children); | LIST_INIT(&pr->pr_children); | ||||
mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); | mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK); | ||||
TASK_INIT(&pr->pr_task, 0, prison_complete, pr); | TASK_INIT(&pr->pr_task, 0, prison_complete, pr); | ||||
pr->pr_id = jid; | pr->pr_id = jid; | ||||
if (inspr != NULL) | if (inspr != NULL) | ||||
TAILQ_INSERT_BEFORE(inspr, pr, pr_list); | TAILQ_INSERT_BEFORE(inspr, pr, pr_list); | ||||
else | else | ||||
▲ Show 20 Lines • Show All 77 Lines • ▼ Show 20 Lines | #endif | ||||
* Unlike other initial settings, this may return an erorr. | * Unlike other initial settings, this may return an erorr. | ||||
*/ | */ | ||||
error = cpuset_create_root(ppr, &pr->pr_cpuset); | error = cpuset_create_root(ppr, &pr->pr_cpuset); | ||||
if (error) | if (error) | ||||
goto done_deref; | goto done_deref; | ||||
mtx_lock(&pr->pr_mtx); | mtx_lock(&pr->pr_mtx); | ||||
drflags |= PD_LOCKED; | drflags |= PD_LOCKED; | ||||
/* | |||||
* New prisons do not yet have a reference, because we do not | |||||
* want others to see the incomplete prison once the | |||||
* allprison_lock is downgraded. | |||||
*/ | |||||
} else { | } else { | ||||
/* | /* | ||||
* Grab a reference for existing prisons, to ensure they | * Grab a reference for existing prisons, to ensure they | ||||
* continue to exist for the duration of the call. | * continue to exist for the duration of the call. | ||||
*/ | */ | ||||
prison_hold(pr); | prison_hold(pr); | ||||
drflags |= PD_DEREF; | drflags |= PD_DEREF; | ||||
#if defined(VIMAGE) && (defined(INET) || defined(INET6)) | #if defined(VIMAGE) && (defined(INET) || defined(INET6)) | ||||
▲ Show 20 Lines • Show All 405 Lines • ▼ Show 20 Lines | FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
pr->pr_allow = (pr->pr_allow & ~ch_allow) | pr_allow; | pr->pr_allow = (pr->pr_allow & ~ch_allow) | pr_allow; | ||||
if ((tallow = ch_allow & ~pr_allow)) | if ((tallow = ch_allow & ~pr_allow)) | ||||
prison_set_allow_locked(pr, tallow, 0); | prison_set_allow_locked(pr, tallow, 0); | ||||
/* | /* | ||||
* Persistent prisons get an extra reference, and prisons losing their | * Persistent prisons get an extra reference, and prisons losing their | ||||
* persist flag lose that reference. Only do this for existing prisons | * persist flag lose that reference. | ||||
* for now, so new ones will remain unseen until after the module | |||||
* handlers have completed. | |||||
*/ | */ | ||||
born = !prison_isalive(pr); | born = !prison_isalive(pr); | ||||
if (!created && (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags))) { | if (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags)) { | ||||
if (pr_flags & PR_PERSIST) { | if (pr_flags & PR_PERSIST) { | ||||
prison_hold(pr); | prison_hold(pr); | ||||
refcount_acquire(&pr->pr_uref); | if (refcount_acquire(&pr->pr_uref) == 0 && | ||||
pr->pr_state == PRISON_STATE_DYING) | |||||
pr->pr_state = PRISON_STATE_ALIVE; | |||||
} else { | } else { | ||||
drflags |= PD_DEUREF; | drflags |= PD_DEUREF; | ||||
prison_free_not_last(pr); | prison_free_not_last(pr); | ||||
} | } | ||||
} | } | ||||
pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags; | pr->pr_flags = (pr->pr_flags & ~ch_flags) | pr_flags; | ||||
pr->pr_flags &= ~PR_REMOVE; | pr->pr_flags &= ~PR_REMOVE; | ||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
#endif | #endif | ||||
/* Let the modules do their work. */ | /* Let the modules do their work. */ | ||||
sx_downgrade(&allprison_lock); | sx_downgrade(&allprison_lock); | ||||
drflags = (drflags & ~PD_LIST_XLOCKED) | PD_LIST_SLOCKED; | drflags = (drflags & ~PD_LIST_XLOCKED) | PD_LIST_SLOCKED; | ||||
if (born) { | if (born) { | ||||
error = osd_jail_call(pr, PR_METHOD_CREATE, opts); | error = osd_jail_call(pr, PR_METHOD_CREATE, opts); | ||||
if (error) { | if (error) | ||||
(void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL); | goto done_remove; | ||||
goto done_deref; | |||||
} | } | ||||
} | |||||
error = osd_jail_call(pr, PR_METHOD_SET, opts); | error = osd_jail_call(pr, PR_METHOD_SET, opts); | ||||
if (error) { | if (error) { | ||||
if (born) | if (born) | ||||
(void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL); | goto done_remove; | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
/* Attach this process to the prison if requested. */ | /* Attach this process to the prison if requested. */ | ||||
if (flags & JAIL_ATTACH) { | if (flags & JAIL_ATTACH) { | ||||
mtx_lock(&pr->pr_mtx); | mtx_lock(&pr->pr_mtx); | ||||
error = do_jail_attach(td, pr); | error = do_jail_attach(td, pr); | ||||
drflags &= ~PD_LIST_SLOCKED; | drflags &= ~PD_LIST_SLOCKED; | ||||
if (error) { | if (error) { | ||||
if (created) { | |||||
/* do_jail_attach has removed the prison. */ | |||||
pr = NULL; | |||||
} | |||||
vfs_opterror(opts, "attach failed"); | vfs_opterror(opts, "attach failed"); | ||||
if (born) | |||||
goto done_remove; | |||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
} | } | ||||
#ifdef RACCT | #ifdef RACCT | ||||
if (racct_enable && !created) { | if (racct_enable && !created) { | ||||
if (drflags & PD_LIST_SLOCKED) { | if (drflags & PD_LIST_SLOCKED) { | ||||
sx_sunlock(&allprison_lock); | sx_sunlock(&allprison_lock); | ||||
drflags &= ~PD_LIST_SLOCKED; | drflags &= ~PD_LIST_SLOCKED; | ||||
} | } | ||||
prison_racct_modify(pr); | prison_racct_modify(pr); | ||||
} | } | ||||
#endif | #endif | ||||
if (created) { | |||||
/* The new prison is now ready to be seen. */ | |||||
drflags = prison_lock_xlock(pr, drflags); | |||||
pr->pr_state = refcount_load(&pr->pr_uref) > 0 | |||||
? PRISON_STATE_ALIVE : PRISON_STATE_DYING; | |||||
} | |||||
td->td_retval[0] = pr->pr_id; | td->td_retval[0] = pr->pr_id; | ||||
goto done_deref; | |||||
if (created) { | done_remove: | ||||
/* | /* | ||||
* Add a reference to newly created persistent prisons | * prison_deref will call the remove methods when alive prisons die; | ||||
* (which was not done earlier so that the prison would | * otherwise it needs to be called now. | ||||
* not be publicly visible). | |||||
*/ | */ | ||||
if (pr_flags & PR_PERSIST) { | if (!(drflags & (PD_LIST_SLOCKED | PD_LIST_XLOCKED))) { | ||||
sx_xlock(&allprison_lock); | |||||
drflags |= PD_LIST_XLOCKED; | |||||
} | |||||
if (pr->pr_state != PRISON_STATE_ALIVE) | |||||
(void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL); | |||||
/* Remove the persist flag from new (or resurrected) prisons. */ | |||||
drflags = prison_lock_xlock(pr, drflags); | drflags = prison_lock_xlock(pr, drflags); | ||||
refcount_acquire(&pr->pr_ref); | if (pr->pr_flags & PR_PERSIST) { | ||||
refcount_acquire(&pr->pr_uref); | pr->pr_flags &= ~PR_PERSIST; | ||||
} else { | drflags |= PD_DEUREF; | ||||
/* Non-persistent jails need no further changes. */ | prison_free_not_last(pr); | ||||
pr = NULL; | |||||
} | } | ||||
} | |||||
done_deref: | done_deref: | ||||
/* Release any temporary prison holds and/or locks. */ | /* Release any temporary prison holds and/or locks. */ | ||||
if (pr != NULL) | if (pr != NULL) | ||||
prison_deref(pr, drflags); | prison_deref(pr, drflags); | ||||
else if (drflags & PD_LIST_SLOCKED) | else if (drflags & PD_LIST_SLOCKED) | ||||
sx_sunlock(&allprison_lock); | sx_sunlock(&allprison_lock); | ||||
else if (drflags & PD_LIST_XLOCKED) | else if (drflags & PD_LIST_XLOCKED) | ||||
▲ Show 20 Lines • Show All 556 Lines • ▼ Show 20 Lines | do_jail_attach(struct thread *td, struct prison *pr) | ||||
drflags = PD_DEREF | PD_DEUREF | PD_LOCKED | PD_LIST_SLOCKED; | drflags = PD_DEREF | PD_DEUREF | PD_LOCKED | PD_LIST_SLOCKED; | ||||
if (!prison_isalive(pr)) { | if (!prison_isalive(pr)) { | ||||
/* | /* | ||||
* This will be the first reference, so allprison_lock | * This will be the first reference, so allprison_lock | ||||
* needs an exclusive hold. | * needs an exclusive hold. | ||||
*/ | */ | ||||
drflags = prison_lock_xlock(pr, drflags); | drflags = prison_lock_xlock(pr, drflags); | ||||
} | } | ||||
refcount_acquire(&pr->pr_ref); | prison_hold(pr); | ||||
refcount_acquire(&pr->pr_uref); | if (refcount_acquire(&pr->pr_uref) == 0 && | ||||
pr->pr_state == PRISON_STATE_DYING) | |||||
pr->pr_state = PRISON_STATE_ALIVE; | |||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
drflags &= ~PD_LOCKED; | drflags &= ~PD_LOCKED; | ||||
/* Let modules do whatever they need to prepare for attaching. */ | /* Let modules do whatever they need to prepare for attaching. */ | ||||
error = osd_jail_call(pr, PR_METHOD_ATTACH, td); | error = osd_jail_call(pr, PR_METHOD_ATTACH, td); | ||||
if (error) { | if (error) { | ||||
prison_deref(pr, drflags); | prison_deref(pr, drflags); | ||||
return (error); | return (error); | ||||
▲ Show 20 Lines • Show All 237 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Hold a a prison for user visibility, by incrementing pr_uref. | * Hold a a prison for user visibility, by incrementing pr_uref. | ||||
* It is generally an error to hold a prison that isn't already | * It is generally an error to hold a prison that isn't already | ||||
* user-visible, except through the the jail system calls. It is also | * user-visible, except through the the jail system calls. It is also | ||||
* an error to hold an invalid prison. A prison record will remain | * an error to hold an invalid prison. A prison record will remain | ||||
* alive as long as it has at least one user reference, and will not | * alive as long as it has at least one user reference, and will not | ||||
* be set to the dying state was long as the prison mutex is held. | * be set to the dying state was long as either the prison mutex or | ||||
* the allprison lock is held (allprison_lock may be shared). | |||||
*/ | */ | ||||
void | void | ||||
prison_proc_hold(struct prison *pr) | prison_proc_hold(struct prison *pr) | ||||
{ | { | ||||
#ifdef INVARIANTS | #ifdef INVARIANTS | ||||
int was_alive = refcount_acquire_if_not_zero(&pr->pr_uref); | int was_alive = refcount_acquire_if_not_zero(&pr->pr_uref); | ||||
KASSERT(was_alive, | KASSERT(was_alive, | ||||
Show All 22 Lines | prison_proc_free(struct prison *pr) | ||||
if (!refcount_release_if_not_last(&pr->pr_uref)) { | if (!refcount_release_if_not_last(&pr->pr_uref)) { | ||||
/* | /* | ||||
* Don't remove the last user reference in this context, | * Don't remove the last user reference in this context, | ||||
* which is expected to be a process that is not only locked, | * which is expected to be a process that is not only locked, | ||||
* but also half dead. Add a reference so any calls to | * but also half dead. Add a reference so any calls to | ||||
* prison_free() won't re-submit the task. | * prison_free() won't re-submit the task. | ||||
*/ | */ | ||||
prison_hold(pr); | prison_hold(pr); | ||||
mtx_lock(&pr->pr_mtx); | |||||
KASSERT(!(pr->pr_flags & PR_COMPLETE_PROC), | |||||
("Redundant last reference in prison_proc_free (jid=%d)", | |||||
pr->pr_id)); | |||||
pr->pr_flags |= PR_COMPLETE_PROC; | |||||
mtx_unlock(&pr->pr_mtx); | |||||
taskqueue_enqueue(taskqueue_thread, &pr->pr_task); | taskqueue_enqueue(taskqueue_thread, &pr->pr_task); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Complete a call to either prison_free or prison_proc_free. | * Complete a call to either prison_free or prison_proc_free. | ||||
*/ | */ | ||||
static void | static void | ||||
prison_complete(void *context, int pending) | prison_complete(void *context, int pending) | ||||
{ | { | ||||
struct prison *pr = context; | struct prison *pr = context; | ||||
int drflags; | int drflags; | ||||
/* | /* | ||||
* This could be called to release the last reference, or the | * This could be called to release the last reference, or the | ||||
* last user reference; the existence of a user reference implies | * last user reference; the existence of a user reference implies | ||||
* the latter. There will always be a reference to remove, as | * the latter. There will always be a reference to remove, as | ||||
* prison_proc_free adds one. | * prison_proc_free adds one. | ||||
*/ | */ | ||||
drflags = prison_lock_xlock(pr, PD_DEREF); | drflags = prison_lock_xlock(pr, PD_DEREF); | ||||
if (refcount_load(&pr->pr_uref) > 0) | if (pr->pr_flags & PR_COMPLETE_PROC) { | ||||
pr->pr_flags &= ~PR_COMPLETE_PROC; | |||||
drflags |= PD_DEUREF; | drflags |= PD_DEUREF; | ||||
} | |||||
prison_deref(pr, drflags); | prison_deref(pr, drflags); | ||||
} | } | ||||
/* | /* | ||||
* Remove a prison reference and/or user reference (usually). | * Remove a prison reference and/or user reference (usually). | ||||
* This assumes context that allows sleeping (for allprison_lock), | * This assumes context that allows sleeping (for allprison_lock), | ||||
* with no non-sleeping locks held, except perhaps the prison itself. | * with no non-sleeping locks held, except perhaps the prison itself. | ||||
* If there are no more references, release and delist the prison. | * If there are no more references, release and delist the prison. | ||||
Show All 10 Lines | if (flags & PD_DEUREF) { | ||||
/* Drop a user reference. */ | /* Drop a user reference. */ | ||||
KASSERT(refcount_load(&pr->pr_uref) > 0, | KASSERT(refcount_load(&pr->pr_uref) > 0, | ||||
("prison_deref PD_DEUREF on a dead prison (jid=%d)", | ("prison_deref PD_DEUREF on a dead prison (jid=%d)", | ||||
pr->pr_id)); | pr->pr_id)); | ||||
if (!refcount_release_if_not_last(&pr->pr_uref)) { | if (!refcount_release_if_not_last(&pr->pr_uref)) { | ||||
/* This is the last user reference. */ | /* This is the last user reference. */ | ||||
prison_hold(pr); | prison_hold(pr); | ||||
flags = prison_lock_xlock(pr, flags); | flags = prison_lock_xlock(pr, flags); | ||||
if (refcount_release(&pr->pr_uref)) { | if (refcount_release(&pr->pr_uref) && | ||||
pr->pr_state == PRISON_STATE_ALIVE) { | |||||
/* | /* | ||||
* When the last user references goes, | * When the last user references goes, | ||||
* this becomes a dying prison (unless | * this becomes a dying prison (unless | ||||
* it was one already). | * it was one already). | ||||
*/ | */ | ||||
KASSERT( | pr->pr_state = PRISON_STATE_DYING; | ||||
refcount_load(&prison0.pr_uref) > 0, | |||||
("prison0 pr_uref=0")); | |||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
flags &= ~PD_LOCKED; | flags &= ~PD_LOCKED; | ||||
(void)osd_jail_call(pr, | (void)osd_jail_call(pr, | ||||
PR_METHOD_REMOVE, NULL); | PR_METHOD_REMOVE, NULL); | ||||
} | } | ||||
KASSERT(refcount_load(&prison0.pr_uref) > 0, | |||||
("prison0 pr_uref=0")); | |||||
if (!(flags & PD_DEREF)) | if (!(flags & PD_DEREF)) | ||||
flags |= PD_DEREF; | flags |= PD_DEREF; | ||||
else | else | ||||
prison_free_not_last(pr); | prison_free_not_last(pr); | ||||
} | } | ||||
} | } | ||||
if (flags & PD_DEREF) { | if (flags & PD_DEREF) { | ||||
/* Drop a reference. */ | /* Drop a reference. */ | ||||
KASSERT(refcount_load(&pr->pr_ref) > 0, | KASSERT(refcount_load(&pr->pr_ref) > 0, | ||||
("prison_deref PD_DEREF on a dead prison (jid=%d)", | ("prison_deref PD_DEREF on a dead prison (jid=%d)", | ||||
pr->pr_id)); | pr->pr_id)); | ||||
if (refcount_release_if_not_last(&pr->pr_ref)) | if (refcount_release_if_not_last(&pr->pr_ref)) | ||||
break; | break; | ||||
/* This is the last reference. */ | /* This is the last reference. */ | ||||
flags = prison_lock_xlock(pr, flags); | flags = prison_lock_xlock(pr, flags); | ||||
if (!refcount_release(&pr->pr_ref)) | if (!refcount_release(&pr->pr_ref)) | ||||
break; | break; | ||||
} else { | } else | ||||
/* Check the existing reference count. */ | |||||
if (!(flags & | |||||
(PD_LOCKED | PD_LIST_SLOCKED | PD_LIST_XLOCKED))) { | |||||
mtx_lock(&pr->pr_mtx); | |||||
flags |= PD_LOCKED; | |||||
} | |||||
if (refcount_load(&pr->pr_ref) > 0) | |||||
break; | break; | ||||
flags = prison_lock_xlock(pr, flags); | |||||
} | |||||
/* Do the work of actually freeing the prison. */ | /* Do the work of actually freeing the prison. */ | ||||
pr->pr_state = PRISON_STATE_INVALID; | |||||
TAILQ_REMOVE(&allprison, pr, pr_list); | TAILQ_REMOVE(&allprison, pr, pr_list); | ||||
LIST_REMOVE(pr, pr_sibling); | LIST_REMOVE(pr, pr_sibling); | ||||
ppr = pr->pr_parent; | ppr = pr->pr_parent; | ||||
for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) | for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) | ||||
tpr->pr_childcount--; | tpr->pr_childcount--; | ||||
sx_xunlock(&allprison_lock); | sx_xunlock(&allprison_lock); | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
▲ Show 20 Lines • Show All 232 Lines • ▼ Show 20 Lines | |||||
/* | /* | ||||
* Return true if the prison is currently alive. A prison is alive if it | * Return true if the prison is currently alive. A prison is alive if it | ||||
* holds user references and it isn't being removed. | * holds user references and it isn't being removed. | ||||
*/ | */ | ||||
bool | bool | ||||
prison_isalive(struct prison *pr) | prison_isalive(struct prison *pr) | ||||
{ | { | ||||
if (__predict_false(refcount_load(&pr->pr_uref) == 0)) | if (__predict_false(pr->pr_state != PRISON_STATE_ALIVE)) | ||||
return (false); | return (false); | ||||
if (__predict_false(pr->pr_flags & PR_REMOVE)) | if (__predict_false(pr->pr_flags & PR_REMOVE)) | ||||
return (false); | return (false); | ||||
return (true); | return (true); | ||||
} | } | ||||
/* | /* | ||||
* Return true if the prison is currently valid, i.e. it has been fully | * Return true if the prison is currently valid, i.e. it has been fully | ||||
* created. Note that dying prisons are still considered valid. | * created. Note that dying prisons are still considered valid. | ||||
*/ | */ | ||||
bool | bool | ||||
prison_isvalid(struct prison *pr) | prison_isvalid(struct prison *pr) | ||||
{ | { | ||||
if (__predict_false(refcount_load(&pr->pr_ref) == 0)) | if (__predict_false(pr->pr_state == PRISON_STATE_INVALID)) | ||||
return (false); | return (false); | ||||
return (true); | return (true); | ||||
} | } | ||||
/* | /* | ||||
* Return 1 if the passed credential is in a jail and that jail does not | * Return 1 if the passed credential is in a jail and that jail does not | ||||
* have its own virtual network stack, otherwise 0. | * have its own virtual network stack, otherwise 0. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 649 Lines • ▼ Show 20 Lines | if (cpr->pr_ip6s > 0) { | ||||
} | } | ||||
bcopy(cpr->pr_ip6, ip6, | bcopy(cpr->pr_ip6, ip6, | ||||
cpr->pr_ip6s * sizeof(struct in6_addr)); | cpr->pr_ip6s * sizeof(struct in6_addr)); | ||||
} | } | ||||
#endif | #endif | ||||
bzero(xp, sizeof(*xp)); | bzero(xp, sizeof(*xp)); | ||||
xp->pr_version = XPRISON_VERSION; | xp->pr_version = XPRISON_VERSION; | ||||
xp->pr_id = cpr->pr_id; | xp->pr_id = cpr->pr_id; | ||||
xp->pr_state = prison_isalive(cpr) | xp->pr_state = cpr->pr_state; | ||||
? PRISON_STATE_ALIVE : PRISON_STATE_DYING; | |||||
strlcpy(xp->pr_path, prison_path(pr, cpr), sizeof(xp->pr_path)); | strlcpy(xp->pr_path, prison_path(pr, cpr), sizeof(xp->pr_path)); | ||||
strlcpy(xp->pr_host, cpr->pr_hostname, sizeof(xp->pr_host)); | strlcpy(xp->pr_host, cpr->pr_hostname, sizeof(xp->pr_host)); | ||||
strlcpy(xp->pr_name, prison_name(pr, cpr), sizeof(xp->pr_name)); | strlcpy(xp->pr_name, prison_name(pr, cpr), sizeof(xp->pr_name)); | ||||
#ifdef INET | #ifdef INET | ||||
xp->pr_ip4s = cpr->pr_ip4s; | xp->pr_ip4s = cpr->pr_ip4s; | ||||
#endif | #endif | ||||
#ifdef INET6 | #ifdef INET6 | ||||
xp->pr_ip6s = cpr->pr_ip6s; | xp->pr_ip6s = cpr->pr_ip6s; | ||||
▲ Show 20 Lines • Show All 634 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
db_printf("prison %p:\n", pr); | db_printf("prison %p:\n", pr); | ||||
db_printf(" jid = %d\n", pr->pr_id); | db_printf(" jid = %d\n", pr->pr_id); | ||||
db_printf(" name = %s\n", pr->pr_name); | db_printf(" name = %s\n", pr->pr_name); | ||||
db_printf(" parent = %p\n", pr->pr_parent); | db_printf(" parent = %p\n", pr->pr_parent); | ||||
db_printf(" ref = %d\n", pr->pr_ref); | db_printf(" ref = %d\n", pr->pr_ref); | ||||
db_printf(" uref = %d\n", pr->pr_uref); | db_printf(" uref = %d\n", pr->pr_uref); | ||||
db_printf(" state = %d\n", pr->pr_state); | |||||
db_printf(" path = %s\n", pr->pr_path); | db_printf(" path = %s\n", pr->pr_path); | ||||
db_printf(" cpuset = %d\n", pr->pr_cpuset | db_printf(" cpuset = %d\n", pr->pr_cpuset | ||||
? pr->pr_cpuset->cs_id : -1); | ? pr->pr_cpuset->cs_id : -1); | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
db_printf(" vnet = %p\n", pr->pr_vnet); | db_printf(" vnet = %p\n", pr->pr_vnet); | ||||
#endif | #endif | ||||
db_printf(" root = %p\n", pr->pr_root); | db_printf(" root = %p\n", pr->pr_root); | ||||
db_printf(" securelevel = %d\n", pr->pr_securelevel); | db_printf(" securelevel = %d\n", pr->pr_securelevel); | ||||
▲ Show 20 Lines • Show All 87 Lines • Show Last 20 Lines |