Index: usr.sbin/jail/jail.8 =================================================================== --- usr.sbin/jail/jail.8 (revision 231939) +++ usr.sbin/jail/jail.8 (working copy) @@ -305,11 +305,12 @@ least as secure. 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 +ruleset enforcement is inherited. 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. .It Va children.max @@ -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 Index: sys/fs/nullfs/null_vfsops.c =================================================================== --- sys/fs/nullfs/null_vfsops.c (revision 231939) +++ sys/fs/nullfs/null_vfsops.c (working copy) @@ -50,6 +50,7 @@ #include #include #include +#include #include @@ -75,12 +76,17 @@ 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 (jailed(td->td_ucred) && !prison_allow(td->td_ucred, + PR_ALLOW_MOUNT_NULLFS)) + return (EPERM); + if (mp->mnt_flag & MNT_ROOTFS) return (EOPNOTSUPP); /* Index: sys/fs/devfs/devfs_vfsops.c =================================================================== --- sys/fs/devfs/devfs_vfsops.c (revision 231939) +++ sys/fs/devfs/devfs_vfsops.c (working copy) @@ -94,10 +94,10 @@ devfs_mount(struct mount *mp) } /* jails enforce their ruleset, prison0 has no restrictions */ - if (td->td_ucred->cr_prison->pr_devfs_rsnum != 0) { + if (jailed(td->td_ucred)) { + if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_DEVFS)) + return (EPERM); 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; Index: sys/sys/jail.h =================================================================== --- sys/sys/jail.h (revision 231939) +++ sys/sys/jail.h (working copy) @@ -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 0xffff /* * OSD methods @@ -343,6 +345,14 @@ SYSCTL_DECL(_security_jail_param); SYSCTL_JAIL_PARAM(_##module, , CTLTYPE_INT | (access), "E,jailsys", \ descr) +SYSCTL_DECL(_security_jail_param_allow); + +#define SYSCTL_JAIL_PARAM_ALLOW(module, param, type, fmt, descr) \ + SYSCTL_PROC(_security_jail_param_allow ## module, OID_AUTO, param, \ + (type) | CTLFLAG_MPSAFE, NULL, 0, sysctl_jail_param, fmt, descr) +#define SYSCTL_JAIL_PARAM_ALLOW_NODE(module, descr) \ + SYSCTL_NODE(_security_jail_param_allow, OID_AUTO, module, 0, 0, descr) + /* * Kernel support functions for jail(). */ Index: sys/kern/kern_jail.c =================================================================== --- sys/kern/kern_jail.c (revision 231939) +++ sys/kern/kern_jail.c (working copy) @@ -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; @@ -1361,9 +1365,8 @@ kern_jail_set(struct thread *td, struct uio *optui 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; } @@ -1372,10 +1375,10 @@ kern_jail_set(struct thread *td, struct uio *optui * or disable devfs */ if (jailed(td->td_ucred)) { - if (rsnum > 0 && rsnum != ppr->pr_devfs_rsnum) { + 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 +1626,7 @@ kern_jail_set(struct thread *td, struct uio *optui 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 +4197,14 @@ SYSCTL_PROC(_security_jail, OID_AUTO, mount_allowe 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 +4339,20 @@ SYSCTL_JAIL_PARAM(_allow, raw_sockets, CTLTYPE_INT "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_ALLOW_NODE(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)