Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_jail.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 541 Lines • ▼ Show 20 Lines | for (jsf = pr_flag_jailsys; | ||||
case JAIL_SYS_INHERIT: | case JAIL_SYS_INHERIT: | ||||
break; | break; | ||||
default: | default: | ||||
error = EINVAL; | error = EINVAL; | ||||
goto done_free; | goto done_free; | ||||
} | } | ||||
ch_flags |= jsf->new | jsf->disable; | ch_flags |= jsf->new | jsf->disable; | ||||
} | } | ||||
if ((flags & (JAIL_CREATE | JAIL_UPDATE | JAIL_ATTACH)) == JAIL_CREATE | if ((flags & (JAIL_CREATE | JAIL_ATTACH)) == JAIL_CREATE | ||||
&& !(pr_flags & PR_PERSIST)) { | && !(pr_flags & PR_PERSIST)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
vfs_opterror(opts, "new jail must persist or attach"); | vfs_opterror(opts, "new jail must persist or attach"); | ||||
goto done_errmsg; | goto done_errmsg; | ||||
} | } | ||||
#ifdef VIMAGE | #ifdef VIMAGE | ||||
if ((flags & JAIL_UPDATE) && (ch_flags & PR_VNET)) { | if ((flags & JAIL_UPDATE) && (ch_flags & PR_VNET)) { | ||||
error = EINVAL; | error = EINVAL; | ||||
▲ Show 20 Lines • Show All 518 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); | ||||
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); | ||||
/* | |||||
* This may make a dead prison alive again, but wait | |||||
* to label it as such until after OSD calls have had | |||||
* a chance to run (and perhaps to fail). | |||||
*/ | |||||
refcount_acquire(&pr->pr_uref); | refcount_acquire(&pr->pr_uref); | ||||
} 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; | |||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
drflags &= ~PD_LOCKED; | drflags &= ~PD_LOCKED; | ||||
#ifdef RACCT | #ifdef RACCT | ||||
if (racct_enable && created) | if (racct_enable && created) | ||||
prison_racct_attach(pr); | prison_racct_attach(pr); | ||||
#endif | #endif | ||||
▲ Show 20 Lines • Show All 57 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
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); | (void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL); | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
/* | |||||
* A new prison is now ready to be seen; either it has gained a user | |||||
* reference via persistence, or is about to gain one via attachment. | |||||
*/ | |||||
if (born) { | |||||
drflags = prison_lock_xlock(pr, drflags); | |||||
pr->pr_state = PRISON_STATE_ALIVE; | |||||
} | |||||
/* Attach this process to the prison if requested. */ | /* Attach this process to the prison if requested. */ | ||||
if (flags & JAIL_ATTACH) { | if (flags & JAIL_ATTACH) { | ||||
error = do_jail_attach(td, pr, prison_lock_xlock(pr, drflags)); | error = do_jail_attach(td, pr, prison_lock_xlock(pr, drflags)); | ||||
drflags &= ~(PD_LOCKED | PD_LIST_XLOCKED); | drflags &= ~(PD_LOCKED | PD_LIST_XLOCKED); | ||||
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"); | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
} | } | ||||
#ifdef RACCT | #ifdef RACCT | ||||
if (racct_enable && !created) { | if (racct_enable && !created) { | ||||
if (drflags & PD_LIST_XLOCKED) { | if (drflags & PD_LIST_XLOCKED) { | ||||
sx_xunlock(&allprison_lock); | sx_xunlock(&allprison_lock); | ||||
drflags &= ~PD_LIST_XLOCKED; | drflags &= ~PD_LIST_XLOCKED; | ||||
} | } | ||||
prison_racct_modify(pr); | prison_racct_modify(pr); | ||||
} | } | ||||
#endif | #endif | ||||
td->td_retval[0] = pr->pr_id; | td->td_retval[0] = pr->pr_id; | ||||
if (created) { | |||||
/* | |||||
* Add a reference to newly created persistent prisons | |||||
* (which was not done earlier so that the prison would | |||||
* not be publicly visible). | |||||
*/ | |||||
if (pr_flags & PR_PERSIST) { | |||||
drflags = prison_lock_xlock(pr, drflags); | |||||
refcount_acquire(&pr->pr_ref); | |||||
refcount_acquire(&pr->pr_uref); | |||||
} else { | |||||
/* Non-persistent jails need no further changes. */ | |||||
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) | ||||
sx_xunlock(&allprison_lock); | sx_xunlock(&allprison_lock); | ||||
▲ Show 20 Lines • Show All 448 Lines • ▼ Show 20 Lines | sys_jail_remove(struct thread *td, struct jail_remove_args *uap) | ||||
prison_remove_one(pr); | prison_remove_one(pr); | ||||
return (0); | return (0); | ||||
} | } | ||||
static void | static void | ||||
prison_remove_one(struct prison *pr) | prison_remove_one(struct prison *pr) | ||||
{ | { | ||||
struct proc *p; | struct proc *p; | ||||
int drflags; | int was_alive, drflags; | ||||
drflags = PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED; | drflags = PD_DEREF | PD_LOCKED | PD_LIST_XLOCKED; | ||||
/* | /* | ||||
* Mark the prison as doomed, so it doesn't accidentally come back | * Mark the prison as doomed, so it doesn't accidentally come back | ||||
* to life. It may still be explicitly brought back by jail_set(2). | * to life. It may still be explicitly brought back by jail_set(2). | ||||
*/ | */ | ||||
pr->pr_flags |= PR_REMOVE; | was_alive = pr->pr_state == PRISON_STATE_ALIVE; | ||||
pr->pr_state = PRISON_STATE_DYING; | |||||
/* If the prison was persistent, it is not anymore. */ | /* If the prison was persistent, it is not anymore. */ | ||||
if (pr->pr_flags & PR_PERSIST) { | if (pr->pr_flags & PR_PERSIST) { | ||||
drflags |= PD_DEUREF; | drflags |= PD_DEUREF; | ||||
prison_free_not_last(pr); | prison_free_not_last(pr); | ||||
pr->pr_flags &= ~PR_PERSIST; | pr->pr_flags &= ~PR_PERSIST; | ||||
} | } | ||||
/* | /* | ||||
* jail_remove added a reference. If that's the only one, remove | * jail_remove added a reference. If that's the only one, remove | ||||
* the prison now. refcount(9) doesn't guarantee the cache coherence | * the prison now. refcount(9) doesn't guarantee the cache coherence | ||||
* of non-zero counters, so force it here. | * of non-zero counters, so force it here. | ||||
*/ | */ | ||||
KASSERT(refcount_load(&pr->pr_ref) > 0, | KASSERT(refcount_load(&pr->pr_ref) > 0, | ||||
("prison_remove_one removing a dead prison (jid=%d)", pr->pr_id)); | ("prison_remove_one removing a dead prison (jid=%d)", pr->pr_id)); | ||||
if (atomic_load_acq_int(&pr->pr_ref) == 1) { | if (atomic_load_acq_int(&pr->pr_ref) == 1) { | ||||
prison_deref(pr, drflags); | prison_deref(pr, drflags); | ||||
return; | return; | ||||
} | } | ||||
/* Tell modules this prison has died. */ | |||||
mtx_unlock(&pr->pr_mtx); | mtx_unlock(&pr->pr_mtx); | ||||
drflags &= ~PD_LOCKED; | |||||
if (was_alive) | |||||
(void)osd_jail_call(pr, PR_METHOD_REMOVE, NULL); | |||||
sx_xunlock(&allprison_lock); | sx_xunlock(&allprison_lock); | ||||
drflags &= ~(PD_LOCKED | PD_LIST_XLOCKED); | drflags &= ~PD_LIST_XLOCKED; | ||||
/* | /* | ||||
* Kill all processes unfortunate enough to be attached to this prison. | * Kill all processes unfortunate enough to be attached to this prison. | ||||
*/ | */ | ||||
sx_slock(&allproc_lock); | sx_slock(&allproc_lock); | ||||
FOREACH_PROC_IN_SYSTEM(p) { | FOREACH_PROC_IN_SYSTEM(p) { | ||||
PROC_LOCK(p); | PROC_LOCK(p); | ||||
if (p->p_state != PRS_NEW && p->p_ucred && | if (p->p_state != PRS_NEW && p->p_ucred && | ||||
p->p_ucred->cr_prison == pr) | p->p_ucred->cr_prison == pr) | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | do_jail_attach(struct thread *td, struct prison *pr, int drflags) | ||||
/* | /* | ||||
* XXX: Note that there is a slight race here if two threads | * XXX: Note that there is a slight race here if two threads | ||||
* in the same privileged process attempt to attach to two | * in the same privileged process attempt to attach to two | ||||
* different jails at the same time. It is important for | * different jails at the same time. It is important for | ||||
* user processes not to do this, or they might end up with | * user processes not to do this, or they might end up with | ||||
* a process root from one prison, but attached to the jail | * a process root from one prison, but attached to the jail | ||||
* of another. | * of another. | ||||
*/ | */ | ||||
refcount_acquire(&pr->pr_ref); | prison_hold(pr); | ||||
refcount_acquire(&pr->pr_uref); | refcount_acquire(&pr->pr_uref); | ||||
drflags |= PD_DEREF | PD_DEUREF; | drflags |= PD_DEREF | PD_DEUREF; | ||||
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) { | ||||
▲ Show 20 Lines • Show All 275 Lines • ▼ Show 20 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 | ||||
* last user reference; the existence of a user reference implies | * user reference (plus the reference held in prison_proc_free). | ||||
* the latter. There will always be a reference to remove, as | |||||
* 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 18 Lines | if (flags & PD_DEUREF) { | ||||
("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)) { | ||||
if (!(flags & PD_DEREF)) { | if (!(flags & PD_DEREF)) { | ||||
prison_hold(pr); | prison_hold(pr); | ||||
flags |= PD_DEREF; | flags |= PD_DEREF; | ||||
} | } | ||||
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. | * this becomes a dying prison. | ||||
*/ | */ | ||||
KASSERT( | KASSERT( | ||||
refcount_load(&prison0.pr_uref) > 0, | refcount_load(&prison0.pr_uref) > 0, | ||||
("prison0 pr_uref=0")); | ("prison0 pr_uref=0")); | ||||
pr->pr_state = PRISON_STATE_DYING; | |||||
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); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (flags & PD_DEREF) { | if (flags & PD_DEREF) { | ||||
Show All 11 Lines | if (flags & PD_DEREF) { | ||||
KASSERT( | KASSERT( | ||||
refcount_load(&pr->pr_uref) == 0, | refcount_load(&pr->pr_uref) == 0, | ||||
("prison_deref: last ref, " | ("prison_deref: last ref, " | ||||
"but still has %d urefs (jid=%d)", | "but still has %d urefs (jid=%d)", | ||||
pr->pr_uref, pr->pr_id)); | pr->pr_uref, pr->pr_id)); | ||||
KASSERT( | KASSERT( | ||||
refcount_load(&prison0.pr_ref) != 0, | refcount_load(&prison0.pr_ref) != 0, | ||||
("prison0 pr_ref=0")); | ("prison0 pr_ref=0")); | ||||
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); | ||||
TAILQ_INSERT_TAIL(&freeprison, pr, | TAILQ_INSERT_TAIL(&freeprison, pr, | ||||
pr_list); | pr_list); | ||||
for (ppr = pr->pr_parent; | for (ppr = pr->pr_parent; | ||||
ppr != NULL; | ppr != NULL; | ||||
ppr = ppr->pr_parent) | ppr = ppr->pr_parent) | ||||
ppr->pr_childcount--; | ppr->pr_childcount--; | ||||
▲ Show 20 Lines • Show All 250 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)) | |||||
return (false); | |||||
return (true); | return (true); | ||||
} | } | ||||
/* | /* | ||||
* Return true if the prison is currently valid. A prison is valid if it has | * Return true if the prison is currently valid. A prison is valid if it has | ||||
* been fully created, and is not being destroyed. Note that dying prisons | * been fully created, and is not being destroyed. Note that dying prisons | ||||
* are still considered valid. Invalid prisons won't be found under normal | * are still considered valid. Invalid prisons won't be found under normal | ||||
* circumstances, as they're only put in that state by functions that have | * circumstances, as they're only put in that state by functions that have | ||||
* an exclusive hold on allprison_lock. | * an exclusive hold on allprison_lock. | ||||
*/ | */ | ||||
bool | bool | ||||
prison_isvalid(struct prison *pr) | prison_isvalid(struct prison *pr) | ||||
{ | { | ||||
if (__predict_false(pr->pr_state == PRISON_STATE_INVALID)) | |||||
return (false); | |||||
if (__predict_false(refcount_load(&pr->pr_ref) == 0)) | if (__predict_false(refcount_load(&pr->pr_ref) == 0)) | ||||
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 648 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 = %s\n", | |||||
pr->pr_state == PRISON_STATE_ALIVE ? "alive" : | |||||
pr->pr_state == PRISON_STATE_DYING ? "dying" : | |||||
"invalid"); | |||||
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 |