svn commit: r194762 - in head: lib/libc/sys sys/kern sys/sys
usr.sbin/jail
Jamie Gritton
jamie at FreeBSD.org
Tue Jun 23 20:35:51 UTC 2009
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
More information about the svn-src-head
mailing list