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).
_______________________________________________
[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