Author: jamie Date: Tue Jun 23 20:35:51 2009 New Revision: 194762 URL: http://svn.freebsd.org/changeset/base/194762
Log: 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) Modified: head/lib/libc/sys/jail.2 head/sys/kern/kern_jail.c head/sys/sys/jail.h head/usr.sbin/jail/jail.8 Modified: head/lib/libc/sys/jail.2 ============================================================================== --- head/lib/libc/sys/jail.2 Tue Jun 23 20:22:34 2009 (r194761) +++ head/lib/libc/sys/jail.2 Tue Jun 23 20:35:51 2009 (r194762) @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 27, 2009 +.Dd June 23, 2009 .Dt JAIL 2 .Os .Sh NAME @@ -293,9 +293,9 @@ will fail if: .Bl -tag -width Er .It Bq Er EPERM This process is not allowed to create a jail, either because it is not -the super-user, or because it is in a jail where the -.Va allow.jails -parameter is not set. +the super-user, or because it would exceed the jail's +.Va children.max +limit. .It Bq Er EFAULT .Fa jail points to an address outside the allocated address space of the process. @@ -312,9 +312,9 @@ will fail if: .Bl -tag -width Er .It Bq Er EPERM This process is not allowed to create a jail, either because it is not -the super-user, or because it is in a jail where the -.Va allow.jails -parameter is not set. +the super-user, or because it would exceed the jail's +.Va children.max +limit. .It Bq Er EPERM A jail parameter was set to a less restrictive value then the current environment. Modified: head/sys/kern/kern_jail.c ============================================================================== --- head/sys/kern/kern_jail.c Tue Jun 23 20:22:34 2009 (r194761) +++ head/sys/kern/kern_jail.c Tue Jun 23 20:35:51 2009 (r194762) @@ -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 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 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 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 /* 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 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 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 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 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 flag 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 | 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 "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); Modified: head/sys/sys/jail.h ============================================================================== --- head/sys/sys/jail.h Tue Jun 23 20:22:34 2009 (r194761) +++ head/sys/sys/jail.h Tue Jun 23 20:35:51 2009 (r194762) @@ -165,13 +165,14 @@ struct prison { struct in6_addr *pr_ip6; /* (p) v6 IPs of jail */ LIST_HEAD(, prison) pr_children; /* (a) list of child jails */ LIST_ENTRY(prison) pr_sibling; /* (a) next in parent's list */ - int pr_prisoncount; /* (a) number of child jails */ + int pr_childcount; /* (a) number of child jails */ unsigned pr_allow; /* (p) PR_ALLOW_* flags */ int pr_enforce_statfs; /* (p) statfs permission */ char pr_domainname[MAXHOSTNAMELEN]; /* (p) jail domainname */ char pr_hostuuid[HOSTUUIDLEN]; /* (p) jail hostuuid */ unsigned long pr_hostid; /* (p) jail hostid */ struct vnet *pr_vnet; /* (c) network stack */ + int pr_childmax; /* (p) maximum child jails */ }; #endif /* _KERNEL || _WANT_PRISON */ @@ -197,9 +198,8 @@ struct prison { #define PR_ALLOW_CHFLAGS 0x0008 #define PR_ALLOW_MOUNT 0x0010 #define PR_ALLOW_QUOTAS 0x0020 -#define PR_ALLOW_JAILS 0x0040 -#define PR_ALLOW_SOCKET_AF 0x0080 -#define PR_ALLOW_ALL 0x00ff +#define PR_ALLOW_SOCKET_AF 0x0040 +#define PR_ALLOW_ALL 0x007f /* * OSD methods @@ -271,6 +271,23 @@ prison_unlock(struct prison *pr) else /* + * As above, but also keep track of the level descended to. + */ +#define FOREACH_PRISON_DESCENDANT_LOCKED_LEVEL(ppr, cpr, descend, level)\ + for ((cpr) = (ppr), (descend) = 1, (level) = 0; \ + ((cpr) = (((descend) && !LIST_EMPTY(&(cpr)->pr_children)) \ + ? (level++, LIST_FIRST(&(cpr)->pr_children)) \ + : ((cpr) == (ppr) \ + ? NULL \ + : ((prison_unlock(cpr), \ + (descend) = LIST_NEXT(cpr, pr_sibling) != NULL) \ + ? LIST_NEXT(cpr, pr_sibling) \ + : (level--, (cpr)->pr_parent)))));) \ + if ((descend) ? (prison_lock(cpr), 0) : 1) \ + ; \ + else + +/* * Attributes of the physical system, and the root of the jail tree. */ extern struct prison prison0; Modified: head/usr.sbin/jail/jail.8 ============================================================================== --- head/usr.sbin/jail/jail.8 Tue Jun 23 20:22:34 2009 (r194761) +++ head/usr.sbin/jail/jail.8 Tue Jun 23 20:35:51 2009 (r194762) @@ -34,7 +34,7 @@ .\" .\" $FreeBSD$ .\" -.Dd May 29, 2009 +.Dd June 23, 2009 .Dt JAIL 8 .Os .Sh NAME @@ -279,6 +279,17 @@ A jail never has a lower securelevel tha setting this parameter it may have a higher one. If the system securelevel is changed, any jail securelevels will be at least as secure. +.It Va children.max +The number of child jails allowed to be created by this jail (or by +other jails under this jail). +This limit is zero by default, indicating the jail is not allowed to +create child jails. +See the +.Va "Hierarchical Jails" +section for more information. +.It Va children.cur +The number of descendents of this jail, including its own child jails +and any jails created under them. .It Va enforce_statfs This determines which information processes in a jail are able to get about mount points. @@ -368,10 +379,6 @@ with non-jailed parts of the system. Sockets within a jail are normally restricted to IPv4, IPv6, local (UNIX), and route. This allows access to other protocol stacks that have not had jail functionality added to them. -.It Va allow.jails -The prison root may create child jails under this jail. See the -.Va "Hierarchical Jails" -section for more information. .El .El .Pp @@ -756,7 +763,7 @@ and .Va kern.hostuuid . .Ss "Hierarchical Jails" By setting a jail's -.Va allow.jails +.Va children.max parameter, processes within a jail may be able to create jails of their own. These child jails are kept in a hierarchy, with jails only able to see and/or modify the jails they created (or those jails' children). @@ -782,8 +789,8 @@ and may not be bypassed in child jails. .Pp A child jail may in turn create its own child jails if its own -.Va allow.jails -parameter is set (remember it is off by default). +.Va children.max +parameter is set (remember it is zero by default). These jails are visible to and can be modified by their parent and all ancestors. .Pp _______________________________________________ svn-src-all@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/svn-src-all To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"