svn commit: r195870 - in head: lib/libjail sys/compat/linux sys/kern sys/sys usr.sbin/jail usr.sbin/jls

Jamie Gritton jamie at FreeBSD.org
Sat Jul 25 14:48:58 UTC 2009


Author: jamie
Date: Sat Jul 25 14:48:57 2009
New Revision: 195870
URL: http://svn.freebsd.org/changeset/base/195870

Log:
  Some jail parameters (in particular, "ip4" and "ip6" for IP address
  restrictions) were found to be inadequately described by a boolean.
  Define a new parameter type with three values (disable, new, inherit)
  to handle these and future cases.
  
  Approved by:	re (kib), bz (mentor)
  Discussed with:	rwatson

Modified:
  head/lib/libjail/jail.c
  head/lib/libjail/jail.h
  head/sys/compat/linux/linux_mib.c
  head/sys/kern/kern_jail.c
  head/sys/sys/jail.h
  head/usr.sbin/jail/jail.8
  head/usr.sbin/jls/jls.c

Modified: head/lib/libjail/jail.c
==============================================================================
--- head/lib/libjail/jail.c	Sat Jul 25 14:33:21 2009	(r195869)
+++ head/lib/libjail/jail.c	Sat Jul 25 14:48:57 2009	(r195870)
@@ -54,6 +54,8 @@ __FBSDID("$FreeBSD$");
 #define ARRAY_SLOP	5
 
 
+static int jailparam_import_enum(const char **values, int nvalues,
+    const char *valstr, size_t valsize, int *value);
 static int jailparam_vlist(struct jailparam **jpp, va_list ap);
 static int jailparam_type(struct jailparam *jp);
 static char *noname(const char *name);
@@ -61,6 +63,9 @@ static char *nononame(const char *name);
 
 char jail_errmsg[JAIL_ERRMSGLEN];
 
+static const char *bool_values[] = { "false", "true" };
+static const char *jailsys_values[] = { "disable", "new", "inherit" };
+
 
 /*
  * Import a null-terminated parameter list and set a jail with the flags
@@ -140,7 +145,6 @@ int
 jailparam_all(struct jailparam **jpp)
 {
 	struct jailparam *jp;
-	char *nname;
 	size_t mlen1, mlen2, buflen;
 	int njp, nlist;
 	int mib1[CTL_MAXNAME], mib2[CTL_MAXNAME - 2];
@@ -182,6 +186,8 @@ jailparam_all(struct jailparam **jpp)
 			    "sysctl(0.1): %s", strerror(errno));
 			goto error;
 		}
+		if (buf[buflen - 2] == '.')
+			buf[buflen - 2] = '\0';
 		/* Add the parameter to the list */
 		if (njp >= nlist) {
 			nlist *= 2;
@@ -197,17 +203,6 @@ jailparam_all(struct jailparam **jpp)
 			njp++;
 			goto error;
 		}
-		/* Convert nobool parameters to bool. */
-		if (jp[njp].jp_flags & JP_NOBOOL) {
-			nname = nononame(jp[njp].jp_name);
-			if (nname == NULL) {
-				njp++;
-				goto error;
-			}
-			free(jp[njp].jp_name);
-			jp[njp].jp_name = nname;
-			jp[njp].jp_flags ^= JP_BOOL | JP_NOBOOL;
-		}
 		mib1[1] = 2;
 	}
 	jp = realloc(jp, njp * sizeof(*jp));
@@ -285,14 +280,31 @@ jailparam_import(struct jailparam *jp, c
 		switch (jp->jp_ctltype & CTLTYPE) {
 		case CTLTYPE_INT:
 			if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) {
-				if (!strncasecmp(avalue, "true", 4))
-					((int *)jp->jp_value)[i] = 1;
-				else if (!strncasecmp(avalue, "false", 5))
-					((int *)jp->jp_value)[i] = 0;
-				else {
+				if (!jailparam_import_enum(bool_values, 2,
+				    avalue, fw, &((int *)jp->jp_value)[i])) {
 					snprintf(jail_errmsg,
-					    JAIL_ERRMSGLEN,
-					   "%s: unknown boolean value \"%.*s\"",
+					    JAIL_ERRMSGLEN, "%s: "
+					    "unknown boolean value \"%.*s\"",
+					    jp->jp_name, fw, avalue);
+					errno = EINVAL;
+					goto error;
+				}
+				break;
+			}
+			if (jp->jp_flags & JP_JAILSYS) {
+				/*
+				 * Allow setting a jailsys parameter to "new"
+				 * in a booleanesque fashion.
+				 */
+				if (value[0] == '\0')
+					((int *)jp->jp_value)[i] = JAIL_SYS_NEW;
+				else if (!jailparam_import_enum(jailsys_values,
+				    sizeof(jailsys_values) /
+				    sizeof(jailsys_values[0]), avalue, fw,
+				    &((int *)jp->jp_value)[i])) {
+					snprintf(jail_errmsg,
+					    JAIL_ERRMSGLEN, "%s: "
+					    "unknown jailsys value \"%.*s\"",
 					    jp->jp_name, fw, avalue);
 					errno = EINVAL;
 					goto error;
@@ -373,6 +385,23 @@ jailparam_import(struct jailparam *jp, c
 	return (-1);
 }
 
+static int
+jailparam_import_enum(const char **values, int nvalues, const char *valstr,
+    size_t valsize, int *value)
+{
+	char *ep;
+	int i;
+
+	for (i = 0; i < nvalues; i++)
+		if (valsize == strlen(values[i]) &&
+		    !strncasecmp(valstr, values[i], valsize)) {
+			*value = i;
+			return 1;
+		}
+	*value = strtol(valstr, &ep, 10);
+	return (ep == valstr + valsize);
+}
+
 /*
  * Put a name and value into a jail parameter element, copying the value
  * but not altering it.
@@ -428,6 +457,15 @@ jailparam_set(struct jailparam *jp, unsi
 				
 			}
 		} else {
+			/*
+			 * Try to fill in missing values with an empty string.
+			 */
+			if (jp[j].jp_value == NULL && jp[j].jp_valuelen > 0 &&
+			    jailparam_import(jp + j, "") < 0) {
+				njp = j;
+				jid = -1;
+				goto done;
+			}
 			jiov[i].iov_base = jp[j].jp_value;
 			jiov[i].iov_len =
 			    (jp[j].jp_ctltype & CTLTYPE) == CTLTYPE_STRING
@@ -632,7 +670,7 @@ jailparam_export(struct jailparam *jp)
 {
 	char *value, *tvalue, **values;
 	size_t valuelen;
-	int i, nval;
+	int i, nval, ival;
 	char valbuf[INET6_ADDRSTRLEN];
 
 	if (!jp->jp_ctltype && jailparam_type(jp) < 0)
@@ -655,14 +693,21 @@ jailparam_export(struct jailparam *jp)
 	for (i = 0; i < nval; i++) {
 		switch (jp->jp_ctltype & CTLTYPE) {
 		case CTLTYPE_INT:
-			if (jp->jp_flags & (JP_BOOL | JP_NOBOOL)) {
-				strlcpy(valbuf,
-				    ((int *)jp->jp_value)[i] ? "true" : "false",
+			ival = ((int *)jp->jp_value)[i];
+			if ((jp->jp_flags & (JP_BOOL | JP_NOBOOL)) &&
+			    (unsigned)ival < 2) {
+				strlcpy(valbuf, bool_values[ival],
+				    sizeof(valbuf));
+				break;
+			}
+			if ((jp->jp_flags & JP_JAILSYS) &&
+			    (unsigned)ival < sizeof(jailsys_values) /
+			    sizeof(jailsys_values[0])) {
+				strlcpy(valbuf, jailsys_values[ival],
 				    sizeof(valbuf));
 				break;
 			}
-			snprintf(valbuf, sizeof(valbuf), "%d",
-			    ((int *)jp->jp_value)[i]);
+			snprintf(valbuf, sizeof(valbuf), "%d", ival);
 			break;
 		case CTLTYPE_UINT:
 			snprintf(valbuf, sizeof(valbuf), "%u",
@@ -688,7 +733,7 @@ jailparam_export(struct jailparam *jp)
 				    valbuf, sizeof(valbuf)) == NULL) {
 					strerror_r(errno, jail_errmsg,
 					    JAIL_ERRMSGLEN);
-					
+
 					return (NULL);
 				}
 				break;
@@ -698,7 +743,7 @@ jailparam_export(struct jailparam *jp)
 				    valbuf, sizeof(valbuf)) == NULL) {
 					strerror_r(errno, jail_errmsg,
 					    JAIL_ERRMSGLEN);
-					
+
 					return (NULL);
 				}
 				break;
@@ -846,11 +891,13 @@ jailparam_type(struct jailparam *jp)
 				}
 			}
 		}
+	unknown_parameter:
 		snprintf(jail_errmsg, JAIL_ERRMSGLEN,
 		    "unknown parameter: %s", jp->jp_name);
 		errno = ENOENT;
 		return (-1);
 	}
+ mib_desc:
 	mib[1] = 4;
 	desclen = sizeof(desc);
 	if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen,
@@ -873,8 +920,9 @@ jailparam_type(struct jailparam *jp)
 	switch (desc.i & CTLTYPE) {
 	case CTLTYPE_INT:
 		if (desc.s[0] == 'B')
-			jp->jp_flags |=
-			    (desc.s[1] == 'N') ? JP_NOBOOL : JP_BOOL;
+			jp->jp_flags |= JP_BOOL;
+		else if (!strcmp(desc.s, "E,jailsys"))
+			jp->jp_flags |= JP_JAILSYS;
 	case CTLTYPE_UINT:
 		jp->jp_valuelen = sizeof(int);
 		break;
@@ -916,41 +964,21 @@ jailparam_type(struct jailparam *jp)
 		}
 		break;
 	case CTLTYPE_NODE:
-		/*
-		 * A node isn't normally a parameter, but may be a boolean
-		 * if its "no" counterpart exists.
-		 */
-		nname = noname(jp->jp_name);
-		if (nname == NULL)
-			return (-1);
-		mib[1] = 3;
-		snprintf(desc.s, sizeof(desc.s), SJPARAM ".%s", nname);
-		free(nname);
-		miblen = sizeof(mib) - 2 * sizeof(int);
-		if (sysctl(mib, 2, mib + 2, &miblen, desc.s,
-		    strlen(desc.s)) < 0) {
-			snprintf(jail_errmsg, JAIL_ERRMSGLEN,
-				 "unknown parameter: %s", jp->jp_name);
-			return (-1);
-		}
-		mib[1] = 4;
-		desclen = sizeof(desc);
-		if (sysctl(mib, (miblen / sizeof(int)) + 2, &desc, &desclen,
+		/* A node might be described by an empty-named child. */
+		mib[1] = 1;
+		mib[(miblen / sizeof(int)) + 2] =
+		    mib[(miblen / sizeof(int)) + 1] - 1;
+		miblen += sizeof(int);
+		desclen = sizeof(desc.s);
+		if (sysctl(mib, (miblen / sizeof(int)) + 2, desc.s, &desclen,
 		    NULL, 0) < 0) {
 			snprintf(jail_errmsg, JAIL_ERRMSGLEN,
-			    "sysctl(0.4.%s): %s", desc.s, strerror(errno));
-			return (-1);
-		}
-		if ((desc.i & CTLTYPE) != CTLTYPE_INT || desc.s[0] != 'B') {
-			snprintf(jail_errmsg, JAIL_ERRMSGLEN,
-				 "unknown parameter: %s", jp->jp_name);
-			errno = ENOENT;
+			    "sysctl(0.1): %s", strerror(errno));
 			return (-1);
 		}
-		jp->jp_valuelen = sizeof(int);
-		jp->jp_ctltype = desc.i;
-		jp->jp_flags |= JP_BOOL;
-		break;
+		if (desc.s[desclen - 2] != '.')
+			goto unknown_parameter;
+		goto mib_desc;
 	default:
 		snprintf(jail_errmsg, JAIL_ERRMSGLEN,
 		    "unknown type for %s", jp->jp_name);

Modified: head/lib/libjail/jail.h
==============================================================================
--- head/lib/libjail/jail.h	Sat Jul 25 14:33:21 2009	(r195869)
+++ head/lib/libjail/jail.h	Sat Jul 25 14:48:57 2009	(r195870)
@@ -32,6 +32,7 @@
 #define	JP_RAWVALUE	0x01
 #define	JP_BOOL		0x02
 #define	JP_NOBOOL	0x04
+#define	JP_JAILSYS	0x08
 
 #define JAIL_ERRMSGLEN	1024
 

Modified: head/sys/compat/linux/linux_mib.c
==============================================================================
--- head/sys/compat/linux/linux_mib.c	Sat Jul 25 14:33:21 2009	(r195869)
+++ head/sys/compat/linux/linux_mib.c	Sat Jul 25 14:48:57 2009	(r195870)
@@ -237,12 +237,14 @@ linux_prison_create(void *obj, void *dat
 {
 	struct prison *pr = obj;
 	struct vfsoptlist *opts = data;
+	int jsys;
 
-	if (vfs_flagopt(opts, "nolinux", NULL, 0))
+	if (vfs_copyopt(opts, "linux", &jsys, sizeof(jsys)) == 0 &&
+	    jsys == JAIL_SYS_INHERIT)
 		return (0);
 	/*
 	 * Inherit a prison's initial values from its parent
-	 * (different from NULL which also inherits changes).
+	 * (different from JAIL_SYS_INHERIT which also inherits changes).
 	 */
 	return linux_alloc_prison(pr, NULL);
 }
@@ -252,11 +254,16 @@ linux_prison_check(void *obj __unused, v
 {
 	struct vfsoptlist *opts = data;
 	char *osname, *osrelease;
-	int error, len, osrel, oss_version;
+	int error, jsys, len, osrel, oss_version;
 
 	/* Check that the parameters are correct. */
-	(void)vfs_flagopt(opts, "linux", NULL, 0);
-	(void)vfs_flagopt(opts, "nolinux", NULL, 0);
+	error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
+	if (error != ENOENT) {
+		if (error != 0)
+			return (error);
+		if (jsys != JAIL_SYS_NEW && jsys != JAIL_SYS_INHERIT)
+			return (EINVAL);
+	}
 	error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len);
 	if (error != ENOENT) {
 		if (error != 0)
@@ -296,33 +303,40 @@ linux_prison_set(void *obj, void *data)
 	struct prison *pr = obj;
 	struct vfsoptlist *opts = data;
 	char *osname, *osrelease;
-	int error, gotversion, len, nolinux, oss_version, yeslinux;
+	int error, gotversion, jsys, len, oss_version;
 
 	/* Set the parameters, which should be correct. */
-	yeslinux = vfs_flagopt(opts, "linux", NULL, 0);
-	nolinux = vfs_flagopt(opts, "nolinux", NULL, 0);
+	error = vfs_copyopt(opts, "linux", &jsys, sizeof(jsys));
+	if (error == ENOENT)
+		jsys = -1;
 	error = vfs_getopt(opts, "linux.osname", (void **)&osname, &len);
 	if (error == ENOENT)
 		osname = NULL;
 	else
-		yeslinux = 1;
+		jsys = JAIL_SYS_NEW;
 	error = vfs_getopt(opts, "linux.osrelease", (void **)&osrelease, &len);
 	if (error == ENOENT)
 		osrelease = NULL;
 	else
-		yeslinux = 1;
+		jsys = JAIL_SYS_NEW;
 	error = vfs_copyopt(opts, "linux.oss_version", &oss_version,
 	    sizeof(oss_version));
-	gotversion = (error == 0);
-	yeslinux |= gotversion;
-	if (nolinux) {
-		/* "nolinux": inherit the parent's Linux info. */
+	if (error == ENOENT)
+		gotversion = 0;
+	else {
+		gotversion = 1;
+		jsys = JAIL_SYS_NEW;
+	}
+	switch (jsys) {
+	case JAIL_SYS_INHERIT:
+		/* "linux=inherit": inherit the parent's Linux info. */
 		mtx_lock(&pr->pr_mtx);
 		osd_jail_del(pr, linux_osd_jail_slot);
 		mtx_unlock(&pr->pr_mtx);
-	} else if (yeslinux) {
+		break;
+	case JAIL_SYS_NEW:
 		/*
-		 * "linux" or "linux.*":
+		 * "linux=new" or "linux.*":
 		 * the prison gets its own Linux info.
 		 */
 		error = linux_alloc_prison(pr, &lpr);
@@ -348,9 +362,7 @@ linux_prison_set(void *obj, void *data)
 	return (0);
 }
 
-SYSCTL_JAIL_PARAM_NODE(linux, "Jail Linux parameters");
-SYSCTL_JAIL_PARAM(, nolinux, CTLTYPE_INT | CTLFLAG_RW,
-    "BN", "Jail w/ no Linux parameters");
+SYSCTL_JAIL_PARAM_SYS_NODE(linux, CTLFLAG_RW, "Jail Linux parameters");
 SYSCTL_JAIL_PARAM_STRING(_linux, osname, CTLFLAG_RW, LINUX_MAX_UTSNAME,
     "Jail Linux kernel OS name");
 SYSCTL_JAIL_PARAM_STRING(_linux, osrelease, CTLFLAG_RW, LINUX_MAX_UTSNAME,
@@ -371,15 +383,22 @@ linux_prison_get(void *obj, void *data)
 
 	/* See if this prison is the one with the Linux info. */
 	lpr = linux_find_prison(pr, &ppr);
-	i = (ppr == pr);
+	i = (ppr == pr) ? JAIL_SYS_NEW : JAIL_SYS_INHERIT;
 	error = vfs_setopt(opts, "linux", &i, sizeof(i));
 	if (error != 0 && error != ENOENT)
 		goto done;
-	i = !i;
-	error = vfs_setopt(opts, "nolinux", &i, sizeof(i));
-	if (error != 0 && error != ENOENT)
-		goto done;
 	if (i) {
+		error = vfs_setopts(opts, "linux.osname", lpr->pr_osname);
+		if (error != 0 && error != ENOENT)
+			goto done;
+		error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease);
+		if (error != 0 && error != ENOENT)
+			goto done;
+		error = vfs_setopt(opts, "linux.oss_version",
+		    &lpr->pr_oss_version, sizeof(lpr->pr_oss_version));
+		if (error != 0 && error != ENOENT)
+			goto done;
+	} else {
 		/*
 		 * If this prison is inheriting its Linux info, report
 		 * empty/zero parameters.
@@ -394,17 +413,6 @@ linux_prison_get(void *obj, void *data)
 		    sizeof(lpr->pr_oss_version));
 		if (error != 0 && error != ENOENT)
 			goto done;
-	} else {
-		error = vfs_setopts(opts, "linux.osname", lpr->pr_osname);
-		if (error != 0 && error != ENOENT)
-			goto done;
-		error = vfs_setopts(opts, "linux.osrelease", lpr->pr_osrelease);
-		if (error != 0 && error != ENOENT)
-			goto done;
-		error = vfs_setopt(opts, "linux.oss_version",
-		    &lpr->pr_oss_version, sizeof(lpr->pr_oss_version));
-		if (error != 0 && error != ENOENT)
-			goto done;
 	}
 	error = 0;
 

Modified: head/sys/kern/kern_jail.c
==============================================================================
--- head/sys/kern/kern_jail.c	Sat Jul 25 14:33:21 2009	(r195869)
+++ head/sys/kern/kern_jail.c	Sat Jul 25 14:48:57 2009	(r195870)
@@ -120,29 +120,26 @@ static int prison_restrict_ip6(struct pr
  */
 static char *pr_flag_names[] = {
 	[0] = "persist",
-	"host",
-#ifdef INET
-	"ip4",
-#endif
-#ifdef INET6
-	[3] = "ip6",
-#endif
-#ifdef VIMAGE
-	[4] = "vnet",
-#endif
 };
 
 static char *pr_flag_nonames[] = {
 	[0] = "nopersist",
-	"nohost",
+};
+
+struct jailsys_flags {
+	const char	*name;
+	unsigned	 disable;
+	unsigned	 new;
+} pr_flag_jailsys[] = {
+	{ "host", 0, PR_HOST },
+#ifdef VIMAGE
+	{ "vnet", 0, PR_VNET },
+#endif
 #ifdef INET
-	"noip4",
+	{ "ip4", PR_IP4_USER | PR_IP4_DISABLE, PR_IP4_USER },
 #endif
 #ifdef INET6
-	[3] = "noip6",
-#endif
-#ifdef VIMAGE
-	[4] = "novnet",
+	{ "ip6", PR_IP6_USER | PR_IP6_DISABLE, PR_IP6_USER },
 #endif
 };
 
@@ -478,7 +475,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 gotchildmax, gotenforce, gothid, gotslevel, fi, jid, len, level;
+	int gotchildmax, gotenforce, gothid, gotslevel;
+	int fi, jid, jsys, len, level;
 	int childmax, slevel, vfslocked;
 #if defined(INET) || defined(INET6)
 	int ii, ij;
@@ -569,6 +567,34 @@ kern_jail_set(struct thread *td, struct 
 		vfs_flagopt(opts, pr_flag_nonames[fi], &ch_flags, 1 << fi);
 	}
 	ch_flags |= pr_flags;
+	for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]);
+	    fi++) {
+		error = vfs_copyopt(opts, pr_flag_jailsys[fi].name, &jsys,
+		    sizeof(jsys));
+		if (error == ENOENT)
+			continue;
+		if (error != 0)
+			goto done_free;
+		switch (jsys) {
+		case JAIL_SYS_DISABLE:
+			if (!pr_flag_jailsys[fi].disable) {
+				error = EINVAL;
+				goto done_free;
+			}
+			pr_flags |= pr_flag_jailsys[fi].disable;
+			break;
+		case JAIL_SYS_NEW:
+			pr_flags |= pr_flag_jailsys[fi].new;
+			break;
+		case JAIL_SYS_INHERIT:
+			break;
+		default:
+			error = EINVAL;
+			goto done_free;
+		}
+		ch_flags |=
+		    pr_flag_jailsys[fi].new | pr_flag_jailsys[fi].disable;
+	}
 	if ((flags & (JAIL_CREATE | JAIL_UPDATE | JAIL_ATTACH)) == JAIL_CREATE
 	    && !(pr_flags & PR_PERSIST)) {
 		error = EINVAL;
@@ -684,16 +710,18 @@ kern_jail_set(struct thread *td, struct 
 #ifdef INET
 	error = vfs_getopt(opts, "ip4.addr", &op, &ip4s);
 	if (error == ENOENT)
-		ip4s = -1;
+		ip4s = (pr_flags & PR_IP4_DISABLE) ? 0 : -1;
 	else if (error != 0)
 		goto done_free;
 	else if (ip4s & (sizeof(*ip4) - 1)) {
 		error = EINVAL;
 		goto done_free;
 	} else {
-		ch_flags |= PR_IP4_USER;
-		pr_flags |= PR_IP4_USER;
-		if (ip4s > 0) {
+		ch_flags |= PR_IP4_USER | PR_IP4_DISABLE;
+		if (ip4s == 0)
+			pr_flags |= PR_IP4_USER | PR_IP4_DISABLE;
+		else {
+			pr_flags = (pr_flags & ~PR_IP4_DISABLE) | PR_IP4_USER;
 			ip4s /= sizeof(*ip4);
 			if (ip4s > jail_max_af_ips) {
 				error = EINVAL;
@@ -745,16 +773,18 @@ kern_jail_set(struct thread *td, struct 
 #ifdef INET6
 	error = vfs_getopt(opts, "ip6.addr", &op, &ip6s);
 	if (error == ENOENT)
-		ip6s = -1;
+		ip6s = (pr_flags & PR_IP6_DISABLE) ? 0 : -1;
 	else if (error != 0)
 		goto done_free;
 	else if (ip6s & (sizeof(*ip6) - 1)) {
 		error = EINVAL;
 		goto done_free;
 	} else {
-		ch_flags |= PR_IP6_USER;
-		pr_flags |= PR_IP6_USER;
-		if (ip6s > 0) {
+		ch_flags |= PR_IP6_USER | PR_IP6_DISABLE;
+		if (ip6s == 0)
+			pr_flags |= PR_IP6_USER | PR_IP6_DISABLE;
+		else {
+			pr_flags = (pr_flags & ~PR_IP6_DISABLE) | PR_IP6_USER;
 			ip6s /= sizeof(*ip6);
 			if (ip6s > jail_max_af_ips) {
 				error = EINVAL;
@@ -1968,6 +1998,19 @@ kern_jail_get(struct thread *td, struct 
 		if (error != 0 && error != ENOENT)
 			goto done_deref;
 	}
+	for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]);
+	    fi++) {
+		i = pr->pr_flags &
+		    (pr_flag_jailsys[fi].disable | pr_flag_jailsys[fi].new);
+		i = pr_flag_jailsys[fi].disable &&
+		      (i == pr_flag_jailsys[fi].disable) ? JAIL_SYS_DISABLE
+		    : (i == pr_flag_jailsys[fi].new) ? JAIL_SYS_NEW
+		    : JAIL_SYS_INHERIT;
+		error =
+		    vfs_setopt(opts, pr_flag_jailsys[fi].name, &i, sizeof(i));
+		if (error != 0 && error != ENOENT)
+			goto done_deref;
+	}
 	for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]);
 	    fi++) {
 		if (pr_allow_names[fi] == NULL)
@@ -2614,6 +2657,7 @@ prison_restrict_ip4(struct prison *pr, s
 			}
 		}
 		if (pr->pr_ip4s == 0) {
+			pr->pr_flags |= PR_IP4_DISABLE;
 			free(pr->pr_ip4, M_PRISON);
 			pr->pr_ip4 = NULL;
 		}
@@ -2918,6 +2962,7 @@ prison_restrict_ip6(struct prison *pr, s
 			}
 		}
 		if (pr->pr_ip6s == 0) {
+			pr->pr_flags |= PR_IP6_DISABLE;
 			free(pr->pr_ip6, M_PRISON);
 			pr->pr_ip6 = NULL;
 		}
@@ -4035,7 +4080,7 @@ SYSCTL_JAIL_PARAM(, persist, CTLTYPE_INT
     "B", "Jail persistence");
 #ifdef VIMAGE
 SYSCTL_JAIL_PARAM(, vnet, CTLTYPE_INT | CTLFLAG_RDTUN,
-    "B", "Virtual network stack");
+    "E,jailsys", "Virtual network stack");
 #endif
 SYSCTL_JAIL_PARAM(, dying, CTLTYPE_INT | CTLFLAG_RD,
     "B", "Jail is in the process of shutting down");
@@ -4046,9 +4091,7 @@ SYSCTL_JAIL_PARAM(_children, cur, CTLTYP
 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");
+SYSCTL_JAIL_PARAM_SYS_NODE(host, CTLFLAG_RW, "Jail host info");
 SYSCTL_JAIL_PARAM_STRING(_host, hostname, CTLFLAG_RW, MAXHOSTNAMELEN,
     "Jail hostname");
 SYSCTL_JAIL_PARAM_STRING(_host, domainname, CTLFLAG_RW, MAXHOSTNAMELEN,
@@ -4062,16 +4105,12 @@ SYSCTL_JAIL_PARAM_NODE(cpuset, "Jail cpu
 SYSCTL_JAIL_PARAM(_cpuset, id, CTLTYPE_INT | CTLFLAG_RD, "I", "Jail cpuset ID");
 
 #ifdef INET
-SYSCTL_JAIL_PARAM_NODE(ip4, "Jail IPv4 address virtualization");
-SYSCTL_JAIL_PARAM(, noip4, CTLTYPE_INT | CTLFLAG_RW,
-    "BN", "Jail w/ no IP address virtualization");
+SYSCTL_JAIL_PARAM_SYS_NODE(ip4, CTLFLAG_RW, "Jail IPv4 address virtualization");
 SYSCTL_JAIL_PARAM_STRUCT(_ip4, addr, CTLFLAG_RW, sizeof(struct in_addr),
     "S,in_addr,a", "Jail IPv4 addresses");
 #endif
 #ifdef INET6
-SYSCTL_JAIL_PARAM_NODE(ip6, "Jail IPv6 address virtualization");
-SYSCTL_JAIL_PARAM(, noip6, CTLTYPE_INT | CTLFLAG_RW,
-    "BN", "Jail w/ no IP address virtualization");
+SYSCTL_JAIL_PARAM_SYS_NODE(ip6, CTLFLAG_RW, "Jail IPv6 address virtualization");
 SYSCTL_JAIL_PARAM_STRUCT(_ip6, addr, CTLFLAG_RW, sizeof(struct in6_addr),
     "S,in6_addr,a", "Jail IPv6 addresses");
 #endif
@@ -4102,6 +4141,7 @@ db_show_prison(struct prison *pr)
 #if defined(INET) || defined(INET6)
 	int ii;
 #endif
+	unsigned jsf;
 #ifdef INET6
 	char ip6buf[INET6_ADDRSTRLEN];
 #endif
@@ -4128,6 +4168,16 @@ db_show_prison(struct prison *pr)
 	    fi++)
 		if (pr_flag_names[fi] != NULL && (pr->pr_flags & (1 << fi)))
 			db_printf(" %s", pr_flag_names[fi]);
+	for (fi = 0; fi < sizeof(pr_flag_jailsys) / sizeof(pr_flag_jailsys[0]);
+	    fi++) {
+		jsf = pr->pr_flags &
+		    (pr_flag_jailsys[fi].disable | pr_flag_jailsys[fi].new);
+		db_printf(" %-16s= %s\n", pr_flag_jailsys[fi].name,
+		    pr_flag_jailsys[fi].disable && 
+		      (jsf == pr_flag_jailsys[fi].disable) ? "disable"
+		    : (jsf == pr_flag_jailsys[fi].new) ? "new"
+		    : "inherit");
+	}
 	db_printf(" allow           = %x", pr->pr_allow);
 	for (fi = 0; fi < sizeof(pr_allow_names) / sizeof(pr_allow_names[0]);
 	    fi++)

Modified: head/sys/sys/jail.h
==============================================================================
--- head/sys/sys/jail.h	Sat Jul 25 14:33:21 2009	(r195869)
+++ head/sys/sys/jail.h	Sat Jul 25 14:48:57 2009	(r195870)
@@ -100,6 +100,10 @@ struct xprison {
 #define	JAIL_SET_MASK	0x0f
 #define	JAIL_GET_MASK	0x08
 
+#define	JAIL_SYS_DISABLE	0
+#define	JAIL_SYS_NEW		1
+#define	JAIL_SYS_INHERIT	2
+
 #ifndef _KERNEL
 
 struct iovec;
@@ -182,16 +186,18 @@ struct prison {
 /* Flag bits set via options */
 #define	PR_PERSIST	0x00000001	/* Can exist without processes */
 #define	PR_HOST		0x00000002	/* Virtualize hostname et al */
-#define	PR_IP4_USER	0x00000004	/* Virtualize IPv4 addresses */
-#define	PR_IP6_USER	0x00000008	/* Virtualize IPv6 addresses */
+#define	PR_IP4_USER	0x00000004	/* Restrict IPv4 addresses */
+#define	PR_IP6_USER	0x00000008	/* Restrict IPv6 addresses */
 #define	PR_VNET		0x00000010	/* Virtual network stack */
+#define	PR_IP4_DISABLE	0x00000020	/* Disable IPv4 */
+#define	PR_IP6_DISABLE	0x00000040	/* Disable IPv6 */
 
 /* Internal flag bits */
 #define	PR_REMOVE	0x01000000	/* In process of being removed */
-#define	PR_IP4		0x02000000	/* IPv4 virtualized by this jail or */
-					/*  an ancestor			    */
-#define	PR_IP6		0x04000000	/* IPv6 virtualized by this jail or */
-					/*  an ancestor			    */
+#define	PR_IP4		0x02000000	/* IPv4 restricted or disabled */
+					/* by this jail or an ancestor */
+#define	PR_IP6		0x04000000	/* IPv6 restricted or disabled */
+					/* by this jail or an ancestor */
 
 /* Flags for pr_allow */
 #define	PR_ALLOW_SET_HOSTNAME		0x0001
@@ -315,7 +321,11 @@ SYSCTL_DECL(_security_jail_param);
 	CTLTYPE_STRUCT | CTLFLAG_MPSAFE | (access), NULL, len,		\
 	sysctl_jail_param, fmt, descr)
 #define	SYSCTL_JAIL_PARAM_NODE(module, descr)				\
-    SYSCTL_NODE(_security_jail_param, OID_AUTO, module, CTLFLAG_RW, 0, descr)
+    SYSCTL_NODE(_security_jail_param, OID_AUTO, module, 0, 0, descr)
+#define	SYSCTL_JAIL_PARAM_SYS_NODE(module, access, descr)		\
+    SYSCTL_JAIL_PARAM_NODE(module, descr);				\
+    SYSCTL_JAIL_PARAM(_##module, , CTLTYPE_INT | (access), "E,jailsys",	\
+	descr)
 
 /*
  * Kernel support functions for jail().

Modified: head/usr.sbin/jail/jail.8
==============================================================================
--- head/usr.sbin/jail/jail.8	Sat Jul 25 14:33:21 2009	(r195869)
+++ head/usr.sbin/jail/jail.8	Sat Jul 25 14:48:57 2009	(r195870)
@@ -34,7 +34,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 8, 2009
+.Dd July 25, 2009
 .Dt JAIL 8
 .Os
 .Sh NAME
@@ -252,14 +252,26 @@ match.
 It is only possible to start multiple jails with the same IP address,
 if none of the jails has more than this single overlapping IP address
 assigned to itself.
-.Pp
-A list of zero elements (an empty string) will stop the jail from using IPv4
-entirely; setting the boolean parameter
-.Ar noip4
-will not restrict the jail at all.
-.It Va ip6.addr
+.It Va ip4
+Control the availablity of IPv4 addresses.
+Possible values are
+.Dq inherit
+to allow unrestricted access to all system addresses,
+.Dq new
+to restrict addresses via
+.Va ip4.addr
+above, and
+.Dq disable
+to stop the jail from using IPv4 entirely.
+Setting the
+.Va ip4.addr
+parameter implies a value of
+.Dq new .
+.It Va ip6.addr , Va ip6
 A list of IPv6 addresses assigned to the prison, the counterpart to
-.Ar ip4.addr
+.Va ip4.addr
+and
+.Va ip4
 above.
 .It Va host.hostname
 Hostname of the prison.
@@ -268,9 +280,15 @@ Other similar parameters are
 .Va host.hostuuid
 and
 .Va host.hostid .
-Setting the boolean parameter
-.Va nohost
-will retain the system values of these settings.
+.It Va host
+Set the origin of hostname and related information.
+Possible values are
+.Dq inherit
+to use the system information and
+.Dq new
+for the jail to use the information from the above fields.
+Setting any of the above fields implies a value of
+.Dq new .
 .It Va securelevel
 The value of the jail's
 .Va kern.securelevel

Modified: head/usr.sbin/jls/jls.c
==============================================================================
--- head/usr.sbin/jls/jls.c	Sat Jul 25 14:33:21 2009	(r195869)
+++ head/usr.sbin/jls/jls.c	Sat Jul 25 14:48:57 2009	(r195870)
@@ -57,7 +57,7 @@ __FBSDID("$FreeBSD$");
 #define	PRINT_VERBOSE	0x20
 
 static struct jailparam *params;
-static int *param_noparent;
+static int *param_parent;
 static int nparams;
 
 static int add_param(const char *name, void *value, size_t valuelen,
@@ -71,7 +71,7 @@ static void quoted_print(char *str);
 int
 main(int argc, char **argv)
 {
-	char *dot, *ep, *jname, *nname;
+	char *dot, *ep, *jname;
 	int c, i, jflags, jid, lastjid, pflags, spc;
 
 	jname = NULL;
@@ -139,17 +139,14 @@ main(int argc, char **argv)
 			    JP_USER);
 
 	if (pflags & PRINT_SKIP) {
-		/* Check for parameters with boolean parents. */
+		/* Check for parameters with jailsys parents. */
 		for (i = 0; i < nparams; i++) {
 			if ((params[i].jp_flags & JP_USER) &&
 			    (dot = strchr(params[i].jp_name, '.'))) {
 				*dot = 0;
-				nname = noname(params[i].jp_name);
+				param_parent[i] = add_param(params[i].jp_name,
+				    NULL, (size_t)0, NULL, JP_OPT);
 				*dot = '.';
-				param_noparent[i] =
-				    add_param(nname, NULL, (size_t)0, NULL,
-					JP_OPT);
-				free(nname);
 			}
 		}
 	}
@@ -237,21 +234,20 @@ add_param(const char *name, void *value,
 	if (!nparams) {
 		paramlistsize = 32;
 		params = malloc(paramlistsize * sizeof(*params));
-		param_noparent =
-		    malloc(paramlistsize * sizeof(*param_noparent));
-		if (params == NULL || param_noparent == NULL)
+		param_parent = malloc(paramlistsize * sizeof(*param_parent));
+		if (params == NULL || param_parent == NULL)
 			err(1, "malloc");
 	} else if (nparams >= paramlistsize) {
 		paramlistsize *= 2;
 		params = realloc(params, paramlistsize * sizeof(*params));
-		param_noparent = realloc(param_noparent,
-		    paramlistsize * sizeof(*param_noparent));
-		if (params == NULL || param_noparent == NULL)
+		param_parent = realloc(param_parent,
+		    paramlistsize * sizeof(*param_parent));
+		if (params == NULL || param_parent == NULL)
 			err(1, "realloc");
 	}
 
 	/* Look up the parameter. */
-	param_noparent[nparams] = -1;
+	param_parent[nparams] = -1;
 	param = params + nparams++;
 	if (source != NULL) {
 		*param = *source;
@@ -387,8 +383,9 @@ print_jail(int pflags, int jflags)
 			if ((pflags & PRINT_SKIP) &&
 			    ((!(params[i].jp_ctltype &
 				(CTLFLAG_WR | CTLFLAG_TUN))) ||
-			     (param_noparent[i] >= 0 &&
-			      *(int *)params[param_noparent[i]].jp_value)))
+			     (param_parent[i] >= 0 &&
+			      *(int *)params[param_parent[i]].jp_value !=
+			      JAIL_SYS_NEW)))
 				continue;
 			if (spc)
 				putchar(' ');


More information about the svn-src-head mailing list