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
This commit is contained in:
Martin Matuska 2012-02-23 18:51:24 +00:00
parent 0a50333302
commit bf3db8aa65
5 changed files with 79 additions and 35 deletions

View File

@ -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) {

View File

@ -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);
/*

View File

@ -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,7 +1625,6 @@ 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;
}
if (name != NULL) {
@ -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)

View File

@ -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", \

View File

@ -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