Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 9 Feb 2012 10:22:08 +0000 (UTC)
From:      Martin Matuska <mm@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r231267 - in head: sys/fs/devfs sys/kern sys/sys usr.sbin/jail
Message-ID:  <201202091022.q19AM8VO093880@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mm
Date: Thu Feb  9 10:22:08 2012
New Revision: 231267
URL: http://svn.freebsd.org/changeset/base/231267

Log:
  Add support for mounting devfs inside jails.
  
  A new jail(8) option "devfs_ruleset" defines the ruleset enforcement for
  mounting devfs inside jails. A value of -1 disables mounting devfs in
  jails, a value of zero means no restrictions. Nested jails can only
  have mounting devfs disabled or inherit parent's enforcement as jails are
  not allowed to view or manipulate devfs(8) rules.
  
  Utilizes new functions introduced in r231265.
  
  Reviewed by:	jamie
  MFC after:	1 month

Modified:
  head/sys/fs/devfs/devfs_vfsops.c
  head/sys/kern/kern_jail.c
  head/sys/sys/jail.h
  head/usr.sbin/jail/jail.8

Modified: head/sys/fs/devfs/devfs_vfsops.c
==============================================================================
--- head/sys/fs/devfs/devfs_vfsops.c	Thu Feb  9 10:20:41 2012	(r231266)
+++ head/sys/fs/devfs/devfs_vfsops.c	Thu Feb  9 10:22:08 2012	(r231267)
@@ -44,6 +44,7 @@
 #include <sys/sx.h>
 #include <sys/vnode.h>
 #include <sys/limits.h>
+#include <sys/jail.h>
 
 #include <fs/devfs/devfs.h>
 
@@ -69,6 +70,7 @@ devfs_mount(struct mount *mp)
 	int error;
 	struct devfs_mount *fmp;
 	struct vnode *rvp;
+	struct thread *td = curthread;
 	int rsnum;
 
 	if (devfs_unr == NULL)
@@ -91,6 +93,16 @@ devfs_mount(struct mount *mp)
 			error = EINVAL;
 	}
 
+	/* jails enforce their ruleset, prison0 has no restrictions */
+	if (td->td_ucred->cr_prison->pr_devfs_rsnum != 0) {
+		rsnum = td->td_ucred->cr_prison->pr_devfs_rsnum;
+		if (rsnum == -1)
+			return (EPERM);
+		/* check rsnum for sanity, devfs_rsnum is uint16_t */
+		if (rsnum < 0 || rsnum > 65535)
+			error = EINVAL;
+	}
+
 	if (error) {
 		vfs_mount_error(mp, "%s", "invalid ruleset specification");
 		return (error);
@@ -227,4 +239,4 @@ static struct vfsops devfs_vfsops = {
 	.vfs_unmount =		devfs_unmount,
 };
 
-VFS_SET(devfs_vfsops, devfs, VFCF_SYNTHETIC);
+VFS_SET(devfs_vfsops, devfs, VFCF_SYNTHETIC | VFCF_JAIL);

Modified: head/sys/kern/kern_jail.c
==============================================================================
--- head/sys/kern/kern_jail.c	Thu Feb  9 10:20:41 2012	(r231266)
+++ head/sys/kern/kern_jail.c	Thu Feb  9 10:22:08 2012	(r231267)
@@ -103,6 +103,7 @@ struct prison prison0 = {
 	.pr_uref	= 1,
 	.pr_path	= "/",
 	.pr_securelevel	= -1,
+	.pr_devfs_rsnum = 0,
 	.pr_childmax	= JAIL_MAX,
 	.pr_hostuuid	= DEFAULT_HOSTUUID,
 	.pr_children	= LIST_HEAD_INITIALIZER(prison0.pr_children),
@@ -216,8 +217,10 @@ const size_t pr_allow_nonames_size = siz
 
 #define	JAIL_DEFAULT_ALLOW		PR_ALLOW_SET_HOSTNAME
 #define	JAIL_DEFAULT_ENFORCE_STATFS	2
+#define	JAIL_DEFAULT_DEVFS_RSNUM	-1
 static unsigned jail_default_allow = JAIL_DEFAULT_ALLOW;
 static int jail_default_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS;
+static int jail_default_devfs_rsnum = JAIL_DEFAULT_DEVFS_RSNUM;
 #if defined(INET) || defined(INET6)
 static unsigned jail_max_af_ips = 255;
 #endif
@@ -529,9 +532,9 @@ 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;
+	int gotchildmax, gotenforce, gothid, gotrsnum, gotslevel;
 	int fi, jid, jsys, len, level;
-	int childmax, slevel, vfslocked;
+	int childmax, rsnum, slevel, vfslocked;
 	int fullpath_disabled;
 #if defined(INET) || defined(INET6)
 	int ii, ij;
@@ -612,6 +615,14 @@ kern_jail_set(struct thread *td, struct 
 	} else
 		gotenforce = 1;
 
+	error = vfs_copyopt(opts, "devfs_ruleset", &rsnum, sizeof(rsnum));
+	if (error == ENOENT)
+		gotrsnum = 0;
+	else if (error != 0)
+		goto done_free;
+	else
+		gotrsnum = 1;
+
 	pr_flags = ch_flags = 0;
 	for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]);
 	    fi++) {
@@ -1268,6 +1279,7 @@ kern_jail_set(struct thread *td, struct 
 		pr->pr_securelevel = ppr->pr_securelevel;
 		pr->pr_allow = JAIL_DEFAULT_ALLOW & ppr->pr_allow;
 		pr->pr_enforce_statfs = JAIL_DEFAULT_ENFORCE_STATFS;
+		pr->pr_devfs_rsnum = JAIL_DEFAULT_DEVFS_RSNUM;
 
 		LIST_INIT(&pr->pr_children);
 		mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK);
@@ -1346,6 +1358,27 @@ kern_jail_set(struct thread *td, struct 
 			goto done_deref_locked;
 		}
 	}
+	if (gotrsnum) {
+		/*
+		 * devfs_rsnum is a uint16_t
+		 * value of -1 disables devfs mounts
+		 */
+		if (rsnum < -1 || rsnum > 65535) {
+			error = EINVAL;
+			goto done_deref_locked;
+		}
+		/*
+		 * Nested jails may inherit parent's devfs ruleset
+		 * or disable devfs
+		 */
+		if (jailed(td->td_ucred)) {
+			if (rsnum > 0 && rsnum != ppr->pr_devfs_rsnum) {
+				error = EPERM;
+				goto done_deref_locked;
+			} else if (rsnum == 0)
+				rsnum = ppr->pr_devfs_rsnum;
+		}
+	}
 #ifdef INET
 	if (ip4s > 0) {
 		if (ppr->pr_flags & PR_IP4) {
@@ -1586,6 +1619,13 @@ kern_jail_set(struct thread *td, struct 
 			if (tpr->pr_enforce_statfs < enforce)
 				tpr->pr_enforce_statfs = enforce;
 	}
+	if (gotrsnum) {
+		pr->pr_devfs_rsnum = rsnum;
+		/* Pass this restriction on to the children. */
+		FOREACH_PRISON_DESCENDANT_LOCKED(pr, tpr, descend)
+			if (tpr->pr_devfs_rsnum != -1)
+				tpr->pr_devfs_rsnum = rsnum;
+	}
 	if (name != NULL) {
 		if (ppr == &prison0)
 			strlcpy(pr->pr_name, name, sizeof(pr->pr_name));
@@ -2020,6 +2060,10 @@ kern_jail_get(struct thread *td, struct 
 	    sizeof(pr->pr_enforce_statfs));
 	if (error != 0 && error != ENOENT)
 		goto done_deref;
+	error = vfs_setopt(opts, "devfs_ruleset", &pr->pr_devfs_rsnum,
+	    sizeof(pr->pr_devfs_rsnum));
+	if (error != 0 && error != ENOENT)
+		goto done_deref;
 	for (fi = 0; fi < sizeof(pr_flag_names) / sizeof(pr_flag_names[0]);
 	    fi++) {
 		if (pr_flag_names[fi] == NULL)
@@ -4173,6 +4217,12 @@ SYSCTL_PROC(_security_jail, OID_AUTO, en
     sysctl_jail_default_level, "I",
     "Processes in jail cannot see all mounted file systems");
 
+SYSCTL_PROC(_security_jail, OID_AUTO, devfs_ruleset,
+    CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE,
+    &jail_default_devfs_rsnum, offsetof(struct prison, pr_devfs_rsnum),
+    sysctl_jail_default_level, "I",
+    "Ruleset for the devfs filesystem in jail");
+
 /*
  * Nodes to describe jail parameters.  Maximum length of string parameters
  * is returned in the string itself, and the other parameters exist merely
@@ -4221,6 +4271,8 @@ SYSCTL_JAIL_PARAM(, securelevel, CTLTYPE
     "I", "Jail secure level");
 SYSCTL_JAIL_PARAM(, enforce_statfs, CTLTYPE_INT | CTLFLAG_RW,
     "I", "Jail cannot see all mounted file systems");
+SYSCTL_JAIL_PARAM(, devfs_ruleset, CTLTYPE_INT | CTLFLAG_RW,
+    "I", "Ruleset for in-jail devfs mounts");
 SYSCTL_JAIL_PARAM(, persist, CTLTYPE_INT | CTLFLAG_RW,
     "B", "Jail persistence");
 #ifdef VIMAGE
@@ -4413,6 +4465,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(" devfs_rsnum     = %d\n", pr->pr_devfs_rsnum);
 	db_printf(" children.max    = %d\n", pr->pr_childmax);
 	db_printf(" children.cur    = %d\n", pr->pr_childcount);
 	db_printf(" child           = %p\n", LIST_FIRST(&pr->pr_children));

Modified: head/sys/sys/jail.h
==============================================================================
--- head/sys/sys/jail.h	Thu Feb  9 10:20:41 2012	(r231266)
+++ head/sys/sys/jail.h	Thu Feb  9 10:22:08 2012	(r231267)
@@ -176,7 +176,8 @@ struct prison {
 	unsigned	 pr_allow;			/* (p) PR_ALLOW_* flags */
 	int		 pr_securelevel;		/* (p) securelevel */
 	int		 pr_enforce_statfs;		/* (p) statfs permission */
-	int		 pr_spare[5];
+	int		 pr_devfs_rsnum;		/* (p) devfs ruleset */
+	int		 pr_spare[4];
 	unsigned long	 pr_hostid;			/* (p) jail hostid */
 	char		 pr_name[MAXHOSTNAMELEN];	/* (p) admin jail name */
 	char		 pr_path[MAXPATHLEN];		/* (c) chroot path */

Modified: head/usr.sbin/jail/jail.8
==============================================================================
--- head/usr.sbin/jail/jail.8	Thu Feb  9 10:20:41 2012	(r231266)
+++ head/usr.sbin/jail/jail.8	Thu Feb  9 10:22:08 2012	(r231267)
@@ -34,7 +34,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd July 23, 2011
+.Dd February 9, 2012
 .Dt JAIL 8
 .Os
 .Sh NAME
@@ -301,6 +301,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 devfs_ruleset
+The number of the devfs ruleset that is enforced for mounting devfs in
+this jail and its descendants. A value of zero means no ruleset is enforced
+or if set inside a jail for a descendant jail, the parent jails's devfs
+ruleset enforcement is inherited. A value of -1 (default) means mounting a
+devfs filesystem is not allowed. Mounting devfs inside a jail is possible
+only if the
+.Va allow.mount
+permission is effective and
+.Va enforce_statfs
+is set to a value lower than 2.
 .It Va children.max
 The number of child jails allowed to be created by this jail (or by
 other jails under this jail).



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201202091022.q19AM8VO093880>