diff options
author | jamie <jamie@FreeBSD.org> | 2009-06-23 20:35:51 +0000 |
---|---|---|
committer | jamie <jamie@FreeBSD.org> | 2009-06-23 20:35:51 +0000 |
commit | eeafb36508ef6b5677597f46291958c39c792c19 (patch) | |
tree | d8a8a4f7a31ad5b55c33c6e090a31b4ca13703d4 /sys/kern/kern_jail.c | |
parent | 6f1a23c328f27fbb904a8a2629fef6cf83b62840 (diff) | |
download | FreeBSD-src-eeafb36508ef6b5677597f46291958c39c792c19.zip FreeBSD-src-eeafb36508ef6b5677597f46291958c39c792c19.tar.gz |
Add a limit for child jails via the "children.cur" and "children.max"
parameters. This replaces the simple "allow.jails" permission.
Approved by: bz (mentor)
Diffstat (limited to 'sys/kern/kern_jail.c')
-rw-r--r-- | sys/kern/kern_jail.c | 59 |
1 files changed, 50 insertions, 9 deletions
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 68d8dc2..fde77ce 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -80,6 +80,7 @@ struct prison prison0 = { .pr_uref = 1, .pr_path = "/", .pr_securelevel = -1, + .pr_childmax = JAIL_MAX, .pr_hostuuid = "00000000-0000-0000-0000-000000000000", .pr_children = LIST_HEAD_INITIALIZER(&prison0.pr_children), .pr_flags = PR_HOST, @@ -152,7 +153,6 @@ static char *pr_allow_names[] = { "allow.chflags", "allow.mount", "allow.quotas", - "allow.jails", "allow.socket_af", }; @@ -163,7 +163,6 @@ static char *pr_allow_nonames[] = { "allow.nochflags", "allow.nomount", "allow.noquotas", - "allow.nojails", "allow.nosocket_af", }; @@ -479,8 +478,8 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) unsigned long hid; size_t namelen, onamelen; int created, cuflags, descend, enforce, error, errmsg_len, errmsg_pos; - int gotenforce, gothid, gotslevel, fi, jid, len; - int slevel, vfslocked; + int gotchildmax, gotenforce, gothid, gotslevel, fi, jid, len, level; + int childmax, slevel, vfslocked; #if defined(INET) || defined(INET6) int ii, ij; #endif @@ -500,7 +499,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) if (error) return (error); mypr = ppr = td->td_ucred->cr_prison; - if ((flags & JAIL_CREATE) && !(mypr->pr_allow & PR_ALLOW_JAILS)) + if ((flags & JAIL_CREATE) && mypr->pr_childmax == 0) return (EPERM); if (flags & ~JAIL_SET_MASK) return (EINVAL); @@ -544,6 +543,15 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) else gotslevel = 1; + error = + vfs_copyopt(opts, "children.max", &childmax, sizeof(childmax)); + if (error == ENOENT) + gotchildmax = 0; + else if (error != 0) + goto done_free; + else + gotchildmax = 1; + error = vfs_copyopt(opts, "enforce_statfs", &enforce, sizeof(enforce)); gotenforce = (error == 0); if (gotenforce) { @@ -1023,6 +1031,12 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) /* If there's no prison to update, create a new one and link it in. */ if (pr == NULL) { + for (tpr = mypr; tpr != NULL; tpr = tpr->pr_parent) + if (tpr->pr_childcount >= tpr->pr_childmax) { + error = EPERM; + vfs_opterror(opts, "prison limit exceeded"); + goto done_unlock_list; + } created = 1; mtx_lock(&ppr->pr_mtx); if (ppr->pr_ref == 0 || (ppr->pr_flags & PR_REMOVE)) { @@ -1076,7 +1090,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) TAILQ_INSERT_TAIL(&allprison, pr, pr_list); LIST_INSERT_HEAD(&ppr->pr_children, pr, pr_sibling); for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) - tpr->pr_prisoncount++; + tpr->pr_childcount++; pr->pr_parent = ppr; pr->pr_id = jid; @@ -1163,6 +1177,12 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) goto done_deref_locked; } } + if (gotchildmax) { + if (childmax >= ppr->pr_childmax) { + error = EPERM; + goto done_deref_locked; + } + } if (gotenforce) { if (enforce < ppr->pr_enforce_statfs) { error = EPERM; @@ -1506,6 +1526,14 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) if (tpr->pr_securelevel < slevel) tpr->pr_securelevel = slevel; } + if (gotchildmax) { + pr->pr_childmax = childmax; + /* Set all child jails to under this limit. */ + FOREACH_PRISON_DESCENDANT_LOCKED_LEVEL(pr, tpr, descend, level) + if (tpr->pr_childmax > childmax - level) + tpr->pr_childmax = childmax > level + ? childmax - level : 0; + } if (gotenforce) { pr->pr_enforce_statfs = enforce; /* Pass this restriction on to the children. */ @@ -1895,6 +1923,14 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) sizeof(pr->pr_securelevel)); if (error != 0 && error != ENOENT) goto done_deref; + error = vfs_setopt(opts, "children.cur", &pr->pr_childcount, + sizeof(pr->pr_childcount)); + if (error != 0 && error != ENOENT) + goto done_deref; + error = vfs_setopt(opts, "children.max", &pr->pr_childmax, + sizeof(pr->pr_childmax)); + if (error != 0 && error != ENOENT) + goto done_deref; error = vfs_setopts(opts, "host.hostname", pr->pr_hostname); if (error != 0 && error != ENOENT) goto done_deref; @@ -2425,7 +2461,7 @@ prison_deref(struct prison *pr, int flags) LIST_REMOVE(pr, pr_sibling); ppr = pr->pr_parent; for (tpr = ppr; tpr != NULL; tpr = tpr->pr_parent) - tpr->pr_prisoncount--; + tpr->pr_childcount--; sx_downgrade(&allprison_lock); #ifdef VIMAGE @@ -3878,6 +3914,12 @@ SYSCTL_JAIL_PARAM(, vnet, CTLTYPE_INT | CTLFLAG_RDTUN, SYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD, "B", "Jail is in the process of shutting down"); +SYSCTL_JAIL_PARAM_NODE(children, "Number of child jails"); +SYSCTL_JAIL_PARAM(_children, cur, CTLTYPE_INT | CTLFLAG_RD, + "I", "Current number of child jails"); +SYSCTL_JAIL_PARAM(_children, max, CTLTYPE_INT | CTLFLAG_RW, + "I", "Maximum number of child jails"); + SYSCTL_JAIL_PARAM_NODE(host, "Jail host info"); SYSCTL_JAIL_PARAM(, nohost, CTLTYPE_INT | CTLFLAG_RW, "BN", "Jail w/ no host info"); @@ -3921,8 +3963,6 @@ SYSCTL_JAIL_PARAM(_allow, mount, CTLTYPE_INT | CTLFLAG_RW, "B", "Jail may mount/unmount jail-friendly file systems"); SYSCTL_JAIL_PARAM(_allow, quotas, CTLTYPE_INT | CTLFLAG_RW, "B", "Jail may set file quotas"); -SYSCTL_JAIL_PARAM(_allow, jails, CTLTYPE_INT | CTLFLAG_RW, - "B", "Jail may create child jails"); SYSCTL_JAIL_PARAM(_allow, socket_af, CTLTYPE_INT | CTLFLAG_RW, "B", "Jail may create sockets other than just UNIX/IPv4/IPv6/route"); @@ -3954,6 +3994,7 @@ db_show_prison(struct prison *pr) #endif db_printf(" root = %p\n", pr->pr_root); db_printf(" securelevel = %d\n", pr->pr_securelevel); + db_printf(" childcount = %d\n", pr->pr_childcount); db_printf(" child = %p\n", LIST_FIRST(&pr->pr_children)); db_printf(" sibling = %p\n", LIST_NEXT(pr, pr_sibling)); db_printf(" flags = %x", pr->pr_flags); |