Skip site navigation (1)Skip section navigation (2)
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>