summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormm <mm@FreeBSD.org>2012-02-23 18:51:24 +0000
committermm <mm@FreeBSD.org>2012-02-23 18:51:24 +0000
commit4825085ea4c115cda3f658f509ee7eac649d4267 (patch)
tree9a2a88cb10722db25dcb45d3c1ae2c34dec88614
parentda3a5506b851a2db73c9386b1ec92a3eb991e0fd (diff)
downloadFreeBSD-src-4825085ea4c115cda3f658f509ee7eac649d4267.zip
FreeBSD-src-4825085ea4c115cda3f658f509ee7eac649d4267.tar.gz
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
-rw-r--r--sys/fs/devfs/devfs_vfsops.c30
-rw-r--r--sys/fs/nullfs/null_vfsops.c5
-rw-r--r--sys/kern/kern_jail.c37
-rw-r--r--sys/sys/jail.h6
-rw-r--r--usr.sbin/jail/jail.836
5 files changed, 79 insertions, 35 deletions
diff --git a/sys/fs/devfs/devfs_vfsops.c b/sys/fs/devfs/devfs_vfsops.c
index 9606974..f73b229 100644
--- a/sys/fs/devfs/devfs_vfsops.c
+++ b/sys/fs/devfs/devfs_vfsops.c
@@ -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) {
diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c
index 97874b3..b422077 100644
--- a/sys/fs/nullfs/null_vfsops.c
+++ b/sys/fs/nullfs/null_vfsops.c
@@ -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);
/*
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index b800eaa..3ba565b 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -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 uio *optuio, int flags)
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 uio *optuio, int flags)
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 uio *optuio, int flags)
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, mount_allowed,
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, CTLTYPE_INT | CTLFLAG_RW,
"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)
diff --git a/sys/sys/jail.h b/sys/sys/jail.h
index 565efa8..7d87b84 100644
--- a/sys/sys/jail.h
+++ b/sys/sys/jail.h
@@ -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", \
diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8
index 5cd77fc..e1d3b2d 100644
--- a/usr.sbin/jail/jail.8
+++ b/usr.sbin/jail/jail.8
@@ -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, 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
+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
OpenPOWER on IntegriCloud