Date: Tue, 23 Jun 2009 20:35:51 +0000 (UTC) From: Jamie Gritton <jamie@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r194762 - in head: lib/libc/sys sys/kern sys/sys usr.sbin/jail Message-ID: <200906232035.n5NKZpNX089292@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200906232035.n5NKZpNX089292>