mirror of
https://github.com/opnsense/src.git
synced 2026-06-11 09:41:03 -04:00
MFC jail: Don't allow jails under dying parents
If a jail is created with jail_set(...JAIL_DYING), and it has a parent currently in a dying state, that will bring the parent jail back to life. Restrict that to require that the parent itself be explicitly brought back first, and not implicitly created along with the new child jail. Differential Revision: https://reviews.freebsd.org/D28515 (cherry picked from commit0a2a96f35a) MFC jail: Fix locking on an early jail_set error. I had locked allprison_lock without immediately setting PD_LIST_LOCKED. (cherry picked from commit108a9384e9)
This commit is contained in:
parent
2463395303
commit
d2bbfc3754
1 changed files with 17 additions and 23 deletions
|
|
@ -992,7 +992,6 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
|||
* This abuses the file error codes ENOENT and EEXIST.
|
||||
*/
|
||||
pr = NULL;
|
||||
ppr = mypr;
|
||||
inspr = NULL;
|
||||
if (cuflags == JAIL_CREATE && jid == 0 && name != NULL) {
|
||||
namelc = strrchr(name, '.');
|
||||
|
|
@ -1002,6 +1001,12 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
|||
}
|
||||
sx_xlock(&allprison_lock);
|
||||
drflags = PD_LIST_XLOCKED;
|
||||
ppr = mypr;
|
||||
if (!prison_isalive(ppr)) {
|
||||
/* This jail is dying. This process will surely follow. */
|
||||
error = EAGAIN;
|
||||
goto done_deref;
|
||||
}
|
||||
if (jid != 0) {
|
||||
if (jid < 0) {
|
||||
error = EINVAL;
|
||||
|
|
@ -1024,7 +1029,6 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
|||
break;
|
||||
}
|
||||
if (pr != NULL) {
|
||||
ppr = pr->pr_parent;
|
||||
/* Create: jid must not exist. */
|
||||
if (cuflags == JAIL_CREATE) {
|
||||
/*
|
||||
|
|
@ -1046,6 +1050,13 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
|||
vfs_opterror(opts, "jail %d not found", jid);
|
||||
goto done_deref;
|
||||
}
|
||||
ppr = pr->pr_parent;
|
||||
if (!prison_isalive(ppr)) {
|
||||
error = ENOENT;
|
||||
vfs_opterror(opts, "jail %d is dying",
|
||||
ppr->pr_id);
|
||||
goto done_deref;
|
||||
}
|
||||
if (!prison_isalive(pr)) {
|
||||
if (!(flags & JAIL_DYING)) {
|
||||
error = ENOENT;
|
||||
|
|
@ -1111,15 +1122,13 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
|||
"jail \"%s\" not found", name);
|
||||
goto done_deref;
|
||||
}
|
||||
if (!(flags & JAIL_DYING) &&
|
||||
!prison_isalive(ppr)) {
|
||||
mtx_unlock(&ppr->pr_mtx);
|
||||
mtx_unlock(&ppr->pr_mtx);
|
||||
if (!prison_isalive(ppr)) {
|
||||
error = ENOENT;
|
||||
vfs_opterror(opts,
|
||||
"jail \"%s\" is dying", name);
|
||||
goto done_deref;
|
||||
}
|
||||
mtx_unlock(&ppr->pr_mtx);
|
||||
*namelc = '.';
|
||||
}
|
||||
namelc++;
|
||||
|
|
@ -1198,26 +1207,9 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
|||
vfs_opterror(opts, "prison limit exceeded");
|
||||
goto done_deref;
|
||||
}
|
||||
prison_hold(ppr);
|
||||
if (!refcount_acquire_if_not_zero(&ppr->pr_uref)) {
|
||||
/* This brings the parent back to life. */
|
||||
mtx_lock(&ppr->pr_mtx);
|
||||
refcount_acquire(&ppr->pr_uref);
|
||||
ppr->pr_state = PRISON_STATE_ALIVE;
|
||||
mtx_unlock(&ppr->pr_mtx);
|
||||
error = osd_jail_call(ppr, PR_METHOD_CREATE, opts);
|
||||
if (error) {
|
||||
pr = ppr;
|
||||
drflags |= PD_DEREF | PD_DEUREF;
|
||||
goto done_deref;
|
||||
}
|
||||
}
|
||||
|
||||
if (jid == 0 && (jid = get_next_prid(&inspr)) == 0) {
|
||||
error = EAGAIN;
|
||||
vfs_opterror(opts, "no available jail IDs");
|
||||
pr = ppr;
|
||||
drflags |= PD_DEREF | PD_DEUREF;
|
||||
goto done_deref;
|
||||
}
|
||||
|
||||
|
|
@ -1237,6 +1229,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags)
|
|||
TAILQ_INSERT_TAIL(&allprison, pr, pr_list);
|
||||
|
||||
pr->pr_parent = ppr;
|
||||
prison_hold(ppr);
|
||||
prison_proc_hold(ppr);
|
||||
LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling);
|
||||
for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent)
|
||||
tpr->pr_childcount++;
|
||||
|
|
|
|||
Loading…
Reference in a new issue