Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/kern_jail.c
Show First 20 Lines • Show All 984 Lines • ▼ Show 20 Lines | else { | ||||
VOP_UNLOCK(root); | VOP_UNLOCK(root); | ||||
} | } | ||||
/* | /* | ||||
* Find the specified jail, or at least its parent. | * Find the specified jail, or at least its parent. | ||||
* This abuses the file error codes ENOENT and EEXIST. | * This abuses the file error codes ENOENT and EEXIST. | ||||
*/ | */ | ||||
pr = NULL; | pr = NULL; | ||||
ppr = mypr; | |||||
inspr = NULL; | inspr = NULL; | ||||
if (cuflags == JAIL_CREATE && jid == 0 && name != NULL) { | if (cuflags == JAIL_CREATE && jid == 0 && name != NULL) { | ||||
namelc = strrchr(name, '.'); | namelc = strrchr(name, '.'); | ||||
jid = strtoul(namelc != NULL ? namelc + 1 : name, &p, 10); | jid = strtoul(namelc != NULL ? namelc + 1 : name, &p, 10); | ||||
if (*p != '\0') | if (*p != '\0') | ||||
jid = 0; | jid = 0; | ||||
} | } | ||||
sx_xlock(&allprison_lock); | sx_xlock(&allprison_lock); | ||||
ppr = mypr; | |||||
if (!prison_isalive(ppr)) { | |||||
/* This jail is dying. This process will surely follow. */ | |||||
error = EAGAIN; | |||||
goto done_deref; | |||||
} | |||||
drflags = PD_LIST_XLOCKED; | drflags = PD_LIST_XLOCKED; | ||||
if (jid != 0) { | if (jid != 0) { | ||||
if (jid < 0) { | if (jid < 0) { | ||||
error = EINVAL; | error = EINVAL; | ||||
vfs_opterror(opts, "negative jid"); | vfs_opterror(opts, "negative jid"); | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
/* | /* | ||||
* See if a requested jid already exists. Keep track of | * See if a requested jid already exists. Keep track of | ||||
* where it can be inserted later. | * where it can be inserted later. | ||||
*/ | */ | ||||
TAILQ_FOREACH(inspr, &allprison, pr_list) { | TAILQ_FOREACH(inspr, &allprison, pr_list) { | ||||
if (inspr->pr_id < jid) | if (inspr->pr_id < jid) | ||||
continue; | continue; | ||||
if (inspr->pr_id > jid) | if (inspr->pr_id > jid) | ||||
break; | break; | ||||
pr = inspr; | pr = inspr; | ||||
mtx_lock(&pr->pr_mtx); | mtx_lock(&pr->pr_mtx); | ||||
drflags |= PD_LOCKED; | drflags |= PD_LOCKED; | ||||
inspr = NULL; | inspr = NULL; | ||||
break; | break; | ||||
} | } | ||||
if (pr != NULL) { | if (pr != NULL) { | ||||
ppr = pr->pr_parent; | |||||
/* Create: jid must not exist. */ | /* Create: jid must not exist. */ | ||||
if (cuflags == JAIL_CREATE) { | if (cuflags == JAIL_CREATE) { | ||||
/* | /* | ||||
* Even creators that cannot see the jail will | * Even creators that cannot see the jail will | ||||
* get EEXIST. | * get EEXIST. | ||||
*/ | */ | ||||
error = EEXIST; | error = EEXIST; | ||||
vfs_opterror(opts, "jail %d already exists", | vfs_opterror(opts, "jail %d already exists", | ||||
jid); | jid); | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
if (!prison_ischild(mypr, pr)) { | if (!prison_ischild(mypr, pr)) { | ||||
/* | /* | ||||
* 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; | ||||
} | } | ||||
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 (!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) || | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | else { | ||||
*namelc = '\0'; | *namelc = '\0'; | ||||
ppr = prison_find_name(mypr, name); | ppr = prison_find_name(mypr, name); | ||||
if (ppr == NULL) { | if (ppr == NULL) { | ||||
error = ENOENT; | error = ENOENT; | ||||
vfs_opterror(opts, | vfs_opterror(opts, | ||||
"jail \"%s\" not found", name); | "jail \"%s\" not found", name); | ||||
goto done_deref; | 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; | error = ENOENT; | ||||
vfs_opterror(opts, | vfs_opterror(opts, | ||||
"jail \"%s\" is dying", name); | "jail \"%s\" is dying", name); | ||||
goto done_deref; | goto done_deref; | ||||
} | } | ||||
mtx_unlock(&ppr->pr_mtx); | |||||
*namelc = '.'; | *namelc = '.'; | ||||
} | } | ||||
namelc++; | namelc++; | ||||
} | } | ||||
if (namelc[0] != '\0') { | if (namelc[0] != '\0') { | ||||
pnamelen = | pnamelen = | ||||
(ppr == &prison0) ? 0 : strlen(ppr->pr_name) + 1; | (ppr == &prison0) ? 0 : strlen(ppr->pr_name) + 1; | ||||
deadpr = NULL; | deadpr = NULL; | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | #endif | ||||
created = pr == NULL; | created = pr == NULL; | ||||
if (created) { | if (created) { | ||||
for (tpr = mypr; tpr != NULL; tpr = tpr->pr_parent) | for (tpr = mypr; tpr != NULL; tpr = tpr->pr_parent) | ||||
if (tpr->pr_childcount >= tpr->pr_childmax) { | if (tpr->pr_childcount >= tpr->pr_childmax) { | ||||
error = EPERM; | error = EPERM; | ||||
vfs_opterror(opts, "prison limit exceeded"); | vfs_opterror(opts, "prison limit exceeded"); | ||||
goto done_deref; | 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) { | 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; | |||||
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); | ||||
pr->pr_state = PRISON_STATE_INVALID; | pr->pr_state = PRISON_STATE_INVALID; | ||||
refcount_init(&pr->pr_ref, 1); | refcount_init(&pr->pr_ref, 1); | ||||
refcount_init(&pr->pr_uref, 0); | refcount_init(&pr->pr_uref, 0); | ||||
drflags |= PD_DEREF; | 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 | ||||
TAILQ_INSERT_TAIL(&allprison, pr, pr_list); | TAILQ_INSERT_TAIL(&allprison, pr, pr_list); | ||||
pr->pr_parent = ppr; | pr->pr_parent = ppr; | ||||
prison_hold(ppr); | |||||
prison_proc_hold(ppr); | |||||
LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling); | LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling); | ||||
for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) | for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) | ||||
tpr->pr_childcount++; | tpr->pr_childcount++; | ||||
/* Set some default values, and inherit some from the parent. */ | /* Set some default values, and inherit some from the parent. */ | ||||
if (namelc == NULL) | if (namelc == NULL) | ||||
namelc = ""; | namelc = ""; | ||||
if (path == NULL) { | if (path == NULL) { | ||||
▲ Show 20 Lines • Show All 3,348 Lines • Show Last 20 Lines |