Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 23 Feb 2012 18:51:24 +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: r232059 - in head: sys/fs/devfs sys/fs/nullfs sys/kern sys/sys usr.sbin/jail
Message-ID:  <201202231851.q1NIpOxH018329@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: mm
Date: Thu Feb 23 18:51:24 2012
New Revision: 232059
URL: http://svn.freebsd.org/changeset/base/232059

Log:
  To improve control over the use of mount(8) inside a jail(8), introduce
  a new jail parameter node with the following parameters:
  
  allow.mount.devfs:
  	allow mounting the devfs filesystem inside a jail
  
  allow.mount.nullfs:
  	allow mounting the nullfs filesystem inside a jail
  
  Both parameters are disabled by default (equals the behavior before
  devfs and nullfs in jails). Administrators have to explicitly allow
  mounting devfs and nullfs for each jail. The value "-1" of the
  devfs_ruleset parameter is removed in favor of the new allow setting.
  
  Reviewed by:	jamie
  Suggested by:	pjd
  MFC after:	2 weeks

Modified:
  head/sys/fs/devfs/devfs_vfsops.c
  head/sys/fs/nullfs/null_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 23 18:50:19 2012	(r232058)
+++ head/sys/fs/devfs/devfs_vfsops.c	Thu Feb 23 18:51:24 2012	(r232059)
@@ -71,7 +71,7 @@ devfs_mount(struct mount *mp)
 	struct devfs_mount *fmp;
 	struct vnode *rvp;
 	struct thread *td = curthread;
-	int rsnum;
+	int injail, rsnum;
 
 	if (devfs_unr == NULL)
 		devfs_unr = new_unrhdr(0, INT_MAX, NULL);
@@ -81,7 +81,11 @@ devfs_mount(struct mount *mp)
 	if (mp->mnt_flag & MNT_ROOTFS)
 		return (EOPNOTSUPP);
 
+	if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_DEVFS))
+		return (EPERM);
+
 	rsnum = 0;
+	injail = jailed(td->td_ucred);
 
 	if (mp->mnt_optnew != NULL) {
 		if (vfs_filteropt(mp->mnt_optnew, devfs_opts))
@@ -89,24 +93,20 @@ devfs_mount(struct mount *mp)
 
 		if (vfs_getopt(mp->mnt_optnew, "ruleset", NULL, NULL) == 0 &&
 		    (vfs_scanopt(mp->mnt_optnew, "ruleset", "%d",
-		    &rsnum) != 1 || rsnum < 0 || rsnum > 65535))
-			error = EINVAL;
-	}
+		    &rsnum) != 1 || rsnum < 0 || rsnum > 65535)) {
+			vfs_mount_error(mp, "%s",
+			    "invalid ruleset specification");
+			return (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)
+		if (injail && rsnum != 0 &&
+		    rsnum != td->td_ucred->cr_prison->pr_devfs_rsnum)
 			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);
-	}
+	/* jails enforce their ruleset */
+	if (injail)
+		rsnum = td->td_ucred->cr_prison->pr_devfs_rsnum;
 
 	if (mp->mnt_flag & MNT_UPDATE) {
 		if (rsnum != 0) {

Modified: head/sys/fs/nullfs/null_vfsops.c
==============================================================================
--- head/sys/fs/nullfs/null_vfsops.c	Thu Feb 23 18:50:19 2012	(r232058)
+++ head/sys/fs/nullfs/null_vfsops.c	Thu Feb 23 18:51:24 2012	(r232059)
@@ -50,6 +50,7 @@
 #include <sys/namei.h>
 #include <sys/proc.h>
 #include <sys/vnode.h>
+#include <sys/jail.h>
 
 #include <fs/nullfs/null.h>
 
@@ -75,12 +76,16 @@ nullfs_mount(struct mount *mp)
 	struct vnode *lowerrootvp, *vp;
 	struct vnode *nullm_rootvp;
 	struct null_mount *xmp;
+	struct thread *td = curthread;
 	char *target;
 	int isvnunlocked = 0, len;
 	struct nameidata nd, *ndp = &nd;
 
 	NULLFSDEBUG("nullfs_mount(mp = %p)\n", (void *)mp);
 
+	if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_NULLFS))
+		return (EPERM);
+
 	if (mp->mnt_flag & MNT_ROOTFS)
 		return (EOPNOTSUPP);
 	/*

Modified: head/sys/kern/kern_jail.c
==============================================================================
--- head/sys/kern/kern_jail.c	Thu Feb 23 18:50:19 2012	(r232058)
+++ head/sys/kern/kern_jail.c	Thu Feb 23 18:51:24 2012	(r232059)
@@ -201,6 +201,8 @@ static char *pr_allow_names[] = {
 	"allow.mount",
 	"allow.quotas",
 	"allow.socket_af",
+	"allow.mount.devfs",
+	"allow.mount.nullfs",
 };
 const size_t pr_allow_names_size = sizeof(pr_allow_names);
 
@@ -212,12 +214,14 @@ static char *pr_allow_nonames[] = {
 	"allow.nomount",
 	"allow.noquotas",
 	"allow.nosocket_af",
+	"allow.mount.nodevfs",
+	"allow.mount.nonullfs",
 };
 const size_t pr_allow_nonames_size = sizeof(pr_allow_nonames);
 
 #define	JAIL_DEFAULT_ALLOW		PR_ALLOW_SET_HOSTNAME
 #define	JAIL_DEFAULT_ENFORCE_STATFS	2
-#define	JAIL_DEFAULT_DEVFS_RSNUM	-1
+#define	JAIL_DEFAULT_DEVFS_RSNUM	0
 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;
@@ -1279,7 +1283,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;
+		pr->pr_devfs_rsnum = ppr->pr_devfs_rsnum;
 
 		LIST_INIT(&pr->pr_children);
 		mtx_init(&pr->pr_mtx, "jail mutex", NULL, MTX_DEF | MTX_DUPOK);
@@ -1361,21 +1365,19 @@ kern_jail_set(struct thread *td, struct 
 	if (gotrsnum) {
 		/*
 		 * devfs_rsnum is a uint16_t
-		 * value of -1 disables devfs mounts
 		 */
-		if (rsnum < -1 || rsnum > 65535) {
+		if (rsnum < 0 || rsnum > 65535) {
 			error = EINVAL;
 			goto done_deref_locked;
 		}
 		/*
-		 * Nested jails may inherit parent's devfs ruleset
-		 * or disable devfs
+		 * Nested jails always inherit parent's devfs ruleset
 		 */
 		if (jailed(td->td_ucred)) {
 			if (rsnum > 0 && rsnum != ppr->pr_devfs_rsnum) {
 				error = EPERM;
 				goto done_deref_locked;
-			} else if (rsnum == 0)
+			} else
 				rsnum = ppr->pr_devfs_rsnum;
 		}
 	}
@@ -1623,8 +1625,7 @@ kern_jail_set(struct thread *td, struct 
 		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;
+			tpr->pr_devfs_rsnum = rsnum;
 	}
 	if (name != NULL) {
 		if (ppr == &prison0)
@@ -4195,6 +4196,14 @@ SYSCTL_PROC(_security_jail, OID_AUTO, mo
     CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
     NULL, PR_ALLOW_MOUNT, sysctl_jail_default_allow, "I",
     "Processes in jail can mount/unmount jail-friendly file systems");
+SYSCTL_PROC(_security_jail, OID_AUTO, mount_devfs_allowed,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+    NULL, PR_ALLOW_MOUNT_DEVFS, sysctl_jail_default_allow, "I",
+    "Processes in jail can mount/unmount the devfs file system");
+SYSCTL_PROC(_security_jail, OID_AUTO, mount_nullfs_allowed,
+    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
+    NULL, PR_ALLOW_MOUNT_NULLFS, sysctl_jail_default_allow, "I",
+    "Processes in jail can mount/unmount the nullfs file system");
 
 static int
 sysctl_jail_default_level(SYSCTL_HANDLER_ARGS)
@@ -4329,13 +4338,19 @@ SYSCTL_JAIL_PARAM(_allow, raw_sockets, C
     "B", "Jail may create raw sockets");
 SYSCTL_JAIL_PARAM(_allow, chflags, CTLTYPE_INT | CTLFLAG_RW,
     "B", "Jail may alter system file flags");
-SYSCTL_JAIL_PARAM(_allow, mount, CTLTYPE_INT | CTLFLAG_RW,
-    "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, socket_af, CTLTYPE_INT | CTLFLAG_RW,
     "B", "Jail may create sockets other than just UNIX/IPv4/IPv6/route");
 
+SYSCTL_JAIL_PARAM_SUBNODE(allow, mount, "Jail mount/unmount permission flags");
+SYSCTL_JAIL_PARAM(_allow_mount, , CTLTYPE_INT | CTLFLAG_RW,
+    "B", "Jail may mount/unmount jail-friendly file systems in general");
+SYSCTL_JAIL_PARAM(_allow_mount, devfs, CTLTYPE_INT | CTLFLAG_RW,
+    "B", "Jail may mount/unmount the devfs file system");
+SYSCTL_JAIL_PARAM(_allow_mount, nullfs, CTLTYPE_INT | CTLFLAG_RW,
+    "B", "Jail may mount/unmount the nullfs file system");
+
 void
 prison_racct_foreach(void (*callback)(struct racct *racct,
     void *arg2, void *arg3), void *arg2, void *arg3)

Modified: head/sys/sys/jail.h
==============================================================================
--- head/sys/sys/jail.h	Thu Feb 23 18:50:19 2012	(r232058)
+++ head/sys/sys/jail.h	Thu Feb 23 18:51:24 2012	(r232059)
@@ -223,7 +223,9 @@ struct prison_racct {
 #define	PR_ALLOW_MOUNT			0x0010
 #define	PR_ALLOW_QUOTAS			0x0020
 #define	PR_ALLOW_SOCKET_AF		0x0040
-#define	PR_ALLOW_ALL			0x007f
+#define	PR_ALLOW_MOUNT_DEVFS		0x0080
+#define	PR_ALLOW_MOUNT_NULLFS		0x0100
+#define	PR_ALLOW_ALL			0x01ff
 
 /*
  * OSD methods
@@ -338,6 +340,8 @@ SYSCTL_DECL(_security_jail_param);
 	sysctl_jail_param, fmt, descr)
 #define	SYSCTL_JAIL_PARAM_NODE(module, descr)				\
     SYSCTL_NODE(_security_jail_param, OID_AUTO, module, 0, 0, descr)
+#define	SYSCTL_JAIL_PARAM_SUBNODE(parent, module, descr)		\
+    SYSCTL_NODE(_security_jail_param_##parent, 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",	\

Modified: head/usr.sbin/jail/jail.8
==============================================================================
--- head/usr.sbin/jail/jail.8	Thu Feb 23 18:50:19 2012	(r232058)
+++ head/usr.sbin/jail/jail.8	Thu Feb 23 18:51:24 2012	(r232059)
@@ -34,7 +34,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 9, 2012
+.Dd February 23, 2012
 .Dt JAIL 8
 .Os
 .Sh NAME
@@ -303,15 +303,16 @@ If the system securelevel is changed, an
 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
+this jail. A value of zero (default) means no ruleset is enforced. Descendant
+jails inherit the parent jail's devfs ruleset enforcement. Mounting devfs
+inside a jail is possible only if the
 .Va allow.mount
-permission is effective and
+and
+.Va allow.mount.devfs
+permissions are effective and
 .Va enforce_statfs
-is set to a value lower than 2.
+is set to a value lower than 2. Devfs rules and rulesets cannot be viewed or
+modified from inside a jail.
 .It Va children.max
 The number of child jails allowed to be created by this jail (or by
 other jails under this jail).
@@ -407,6 +408,25 @@ within a jail.
 This permission is effective only if
 .Va enforce_statfs
 is set to a value lower than 2.
+.It Va allow.mount.devfs
+privileged users inside the jail will be able to mount and unmount the
+devfs file system.
+This permission is effective only together with
+.Va allow.mount
+and if
+.Va enforce_statfs
+is set to a value lower than 2. Please consider restricting the devfs ruleset
+with the
+.Va devfs_ruleset
+option.
+.It Va allow.mount.nullfs
+privileged users inside the jail will be able to mount and unmount the
+nullfs file system.
+This permission is effective only together with
+.Va allow.mount
+and if
+.Va enforce_statfs
+is set to a value lower than 2.
 .It Va allow.quotas
 The prison root may administer quotas on the jail's filesystem(s).
 This includes filesystems that the jail may share with other jails or



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