diff options
Diffstat (limited to 'sys/kern')
-rw-r--r-- | sys/kern/kern_jail.c | 104 | ||||
-rw-r--r-- | sys/kern/sysv_msg.c | 2 | ||||
-rw-r--r-- | sys/kern/sysv_sem.c | 2 | ||||
-rw-r--r-- | sys/kern/sysv_shm.c | 2 | ||||
-rw-r--r-- | sys/kern/uipc_mqueue.c | 3 |
5 files changed, 71 insertions, 42 deletions
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index ff540875c90e..ba4c1aab0d85 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -1008,7 +1008,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) TAILQ_FOREACH(inspr, &allprison, pr_list) { if (inspr->pr_id == jid) { mtx_lock(&inspr->pr_mtx); - if (inspr->pr_ref > 0) { + if (prison_isvalid(inspr)) { pr = inspr; drflags |= PD_LOCKED; inspr = NULL; @@ -1041,7 +1041,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) error = ENOENT; vfs_opterror(opts, "jail %d not found", jid); goto done_deref; - } else if (pr->pr_uref == 0) { + } else if (!prison_isalive(pr)) { if (!(flags & JAIL_DYING)) { error = ENOENT; vfs_opterror(opts, "jail %d is dying", @@ -1118,24 +1118,18 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) FOREACH_PRISON_CHILD(ppr, tpr) { if (tpr != pr && tpr->pr_ref > 0 && !strcmp(tpr->pr_name + pnamelen, namelc)) { - if (pr == NULL && - cuflags != JAIL_CREATE) { - mtx_lock(&tpr->pr_mtx); - if (tpr->pr_ref > 0) { + mtx_lock(&tpr->pr_mtx); + drflags |= PD_LOCKED; + if (prison_isalive(tpr)) { + if (pr == NULL && + cuflags != JAIL_CREATE) { /* * Use this jail * for updates. */ - if (tpr->pr_uref > 0) { - pr = tpr; - drflags |= - PD_LOCKED; - break; - } - deadpr = tpr; + pr = tpr; + break; } - mtx_unlock(&tpr->pr_mtx); - } else if (tpr->pr_uref > 0) { /* * Create, or update(jid): * name must not exist in an @@ -1147,13 +1141,19 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) name); goto done_deref; } + if (pr == NULL && + cuflags != JAIL_CREATE && + prison_isvalid(tpr)) + deadpr = tpr; + mtx_unlock(&tpr->pr_mtx); + drflags &= ~PD_LOCKED; } } /* If no active jail is found, use a dying one. */ if (deadpr != NULL && pr == NULL) { if (flags & JAIL_DYING) { mtx_lock(&deadpr->pr_mtx); - if (deadpr->pr_ref == 0) { + if (!prison_isvalid(deadpr)) { mtx_unlock(&deadpr->pr_mtx); goto name_again; } @@ -1192,7 +1192,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) goto done_deref; } mtx_lock(&ppr->pr_mtx); - if (ppr->pr_ref == 0) { + if (!prison_isvalid(ppr)) { mtx_unlock(&ppr->pr_mtx); error = ENOENT; vfs_opterror(opts, "jail \"%s\" not found", @@ -1735,7 +1735,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) * for now, so new ones will remain unseen until after the module * handlers have completed. */ - born = pr->pr_uref == 0; + born = !prison_isalive(pr); if (!created && (ch_flags & PR_PERSIST & (pr_flags ^ pr->pr_flags))) { if (pr_flags & PR_PERSIST) { pr->pr_ref++; @@ -2029,8 +2029,8 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) TAILQ_FOREACH(pr, &allprison, pr_list) { if (pr->pr_id > jid && prison_ischild(mypr, pr)) { mtx_lock(&pr->pr_mtx); - if (pr->pr_ref > 0 && - (pr->pr_uref > 0 || (flags & JAIL_DYING))) + if ((flags & JAIL_DYING) + ? prison_isvalid(pr) : prison_isalive(pr)) break; mtx_unlock(&pr->pr_mtx); } @@ -2051,7 +2051,8 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) pr = prison_find_child(mypr, jid); if (pr != NULL) { drflags |= PD_LOCKED; - if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { + if (!(prison_isalive(pr) || + (flags & JAIL_DYING))) { error = ENOENT; vfs_opterror(opts, "jail %d is dying", jid); @@ -2075,7 +2076,7 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) pr = prison_find_name(mypr, name); if (pr != NULL) { drflags |= PD_LOCKED; - if (pr->pr_uref == 0 && !(flags & JAIL_DYING)) { + if (!(prison_isalive(pr) || (flags & JAIL_DYING))) { error = ENOENT; vfs_opterror(opts, "jail \"%s\" is dying", name); @@ -2203,7 +2204,7 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) if (error != 0 && error != ENOENT) goto done; } - i = (pr->pr_uref == 0); + i = !prison_isalive(pr); error = vfs_setopt(opts, "dying", &i, sizeof(i)); if (error != 0 && error != ENOENT) goto done; @@ -2314,7 +2315,7 @@ sys_jail_remove(struct thread *td, struct jail_remove_args *uap) lpr = NULL; FOREACH_PRISON_DESCENDANT(pr, cpr, descend) { mtx_lock(&cpr->pr_mtx); - if (cpr->pr_ref > 0) { + if (prison_isvalid(cpr)) { tpr = cpr; cpr->pr_ref++; } else { @@ -2414,11 +2415,8 @@ sys_jail_attach(struct thread *td, struct jail_attach_args *uap) return (EINVAL); } - /* - * Do not allow a process to attach to a prison that is not - * considered to be "alive". - */ - if (pr->pr_uref == 0) { + /* Do not allow a process to attach to a prison that is not alive. */ + if (!prison_isalive(pr)) { mtx_unlock(&pr->pr_mtx); sx_sunlock(&allprison_lock); return (EINVAL); @@ -2514,7 +2512,7 @@ prison_find(int prid) TAILQ_FOREACH(pr, &allprison, pr_list) { if (pr->pr_id == prid) { mtx_lock(&pr->pr_mtx); - if (pr->pr_ref > 0) + if (prison_isvalid(pr)) return (pr); /* * Any active prison with the same ID would have @@ -2542,7 +2540,7 @@ prison_find_child(struct prison *mypr, int prid) FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { if (pr->pr_id == prid) { mtx_lock(&pr->pr_mtx); - if (pr->pr_ref > 0) + if (prison_isvalid(pr)) return (pr); mtx_unlock(&pr->pr_mtx); } @@ -2567,18 +2565,17 @@ prison_find_name(struct prison *mypr, const char *name) FOREACH_PRISON_DESCENDANT(mypr, pr, descend) { if (!strcmp(pr->pr_name + mylen, name)) { mtx_lock(&pr->pr_mtx); - if (pr->pr_ref > 0) { - if (pr->pr_uref > 0) - return (pr); + if (prison_isalive(pr)) + return (pr); + if (prison_isvalid(pr)) deadpr = pr; - } mtx_unlock(&pr->pr_mtx); } } /* There was no valid prison - perhaps there was a dying one. */ if (deadpr != NULL) { mtx_lock(&deadpr->pr_mtx); - if (deadpr->pr_ref == 0) { + if (!prison_isvalid(deadpr)) { mtx_unlock(&deadpr->pr_mtx); goto again; } @@ -2968,6 +2965,37 @@ prison_ischild(struct prison *pr1, struct prison *pr2) } /* + * Return true if the prison is currently alive. A prison is alive if it is + * valid and it holds user references. + */ +bool +prison_isalive(struct prison *pr) +{ + + mtx_assert(&pr->pr_mtx, MA_OWNED); + if (__predict_false(pr->pr_ref == 0)) + return (false); + if (__predict_false(pr->pr_uref == 0)) + return (false); + return (true); +} + +/* + * 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 + * are still considered valid. + */ +bool +prison_isvalid(struct prison *pr) +{ + + mtx_assert(&pr->pr_mtx, MA_OWNED); + if (__predict_false(pr->pr_ref == 0)) + return (false); + return (true); +} + +/* * Return 1 if the passed credential is in a jail and that jail does not * have its own virtual network stack, otherwise 0. */ @@ -3623,14 +3651,14 @@ sysctl_jail_list(SYSCTL_HANDLER_ARGS) cpr->pr_ip6s * sizeof(struct in6_addr)); } #endif - if (cpr->pr_ref == 0) { + if (!prison_isvalid(cpr)) { mtx_unlock(&cpr->pr_mtx); continue; } bzero(xp, sizeof(*xp)); xp->pr_version = XPRISON_VERSION; xp->pr_id = cpr->pr_id; - xp->pr_state = cpr->pr_uref > 0 + xp->pr_state = prison_isalive(cpr) ? PRISON_STATE_ALIVE : PRISON_STATE_DYING; strlcpy(xp->pr_path, prison_path(pr, cpr), sizeof(xp->pr_path)); strlcpy(xp->pr_host, cpr->pr_hostname, sizeof(xp->pr_host)); diff --git a/sys/kern/sysv_msg.c b/sys/kern/sysv_msg.c index 098bba612636..f048234f3a33 100644 --- a/sys/kern/sysv_msg.c +++ b/sys/kern/sysv_msg.c @@ -290,7 +290,7 @@ msginit() if (rsv == NULL) rsv = osd_reserve(msg_prison_slot); prison_lock(pr); - if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) { + if (prison_isvalid(pr) && (pr->pr_allow & PR_ALLOW_SYSVIPC)) { (void)osd_jail_set_reserved(pr, msg_prison_slot, rsv, &prison0); rsv = NULL; diff --git a/sys/kern/sysv_sem.c b/sys/kern/sysv_sem.c index 612f45a3144a..deee60d87a5a 100644 --- a/sys/kern/sysv_sem.c +++ b/sys/kern/sysv_sem.c @@ -321,7 +321,7 @@ seminit(void) if (rsv == NULL) rsv = osd_reserve(sem_prison_slot); prison_lock(pr); - if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) { + if (prison_isvalid(pr) && (pr->pr_allow & PR_ALLOW_SYSVIPC)) { (void)osd_jail_set_reserved(pr, sem_prison_slot, rsv, &prison0); rsv = NULL; diff --git a/sys/kern/sysv_shm.c b/sys/kern/sysv_shm.c index eb6c57a77a08..ad5f0030b965 100644 --- a/sys/kern/sysv_shm.c +++ b/sys/kern/sysv_shm.c @@ -979,7 +979,7 @@ shminit(void) if (rsv == NULL) rsv = osd_reserve(shm_prison_slot); prison_lock(pr); - if ((pr->pr_allow & PR_ALLOW_SYSVIPC) && pr->pr_ref > 0) { + if (prison_isvalid(pr) && (pr->pr_allow & PR_ALLOW_SYSVIPC)) { (void)osd_jail_set_reserved(pr, shm_prison_slot, rsv, &prison0); rsv = NULL; diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c index 309fa3423fbd..dc94ce213d08 100644 --- a/sys/kern/uipc_mqueue.c +++ b/sys/kern/uipc_mqueue.c @@ -1569,7 +1569,8 @@ mqfs_prison_remove(void *obj, void *data __unused) found = 0; TAILQ_FOREACH(tpr, &allprison, pr_list) { prison_lock(tpr); - if (tpr->pr_root == pr->pr_root && tpr != pr && tpr->pr_ref > 0) + if (tpr != pr && prison_isvalid(tpr) && + tpr->pr_root == pr->pr_root) found = 1; prison_unlock(tpr); } |