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
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to