summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormm <mm@FreeBSD.org>2012-02-09 10:22:08 +0000
committermm <mm@FreeBSD.org>2012-02-09 10:22:08 +0000
commit1626913ed14bc2163e16ddb8e183c16020a65498 (patch)
tree3bd31b4e43a04f06056c6c020a90c80e37e4b08c
parentbdf6c01f6dc2ef7a36886ddf75d1be91cb6d8680 (diff)
downloadFreeBSD-src-1626913ed14bc2163e16ddb8e183c16020a65498.zip
FreeBSD-src-1626913ed14bc2163e16ddb8e183c16020a65498.tar.gz
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
-rw-r--r--sys/fs/devfs/devfs_vfsops.c14
-rw-r--r--sys/kern/kern_jail.c57
-rw-r--r--sys/sys/jail.h3
-rw-r--r--usr.sbin/jail/jail.813
4 files changed, 82 insertions, 5 deletions
diff --git a/sys/fs/devfs/devfs_vfsops.c b/sys/fs/devfs/devfs_vfsops.c
index bba4bfc..9606974 100644
--- a/sys/fs/devfs/devfs_vfsops.c
+++ b/sys/fs/devfs/devfs_vfsops.c
@@ -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);
diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c
index 9f5e8b8..b800eaa 100644
--- a/sys/kern/kern_jail.c
+++ b/sys/kern/kern_jail.c
@@ -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 = sizeof(pr_allow_nonames);
#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 uio *optuio, int flags)
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 uio *optuio, int flags)
} 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 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;
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 uio *optuio, int flags)
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 uio *optuio, int flags)
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 uio *optuio, int flags)
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, enforce_statfs,
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_INT | CTLFLAG_RW,
"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));
diff --git a/sys/sys/jail.h b/sys/sys/jail.h
index bbaf381..565efa8 100644
--- a/sys/sys/jail.h
+++ b/sys/sys/jail.h
@@ -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 */
diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8
index c5a2245..5cd77fc 100644
--- a/usr.sbin/jail/jail.8
+++ b/usr.sbin/jail/jail.8
@@ -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 than the default system, but by
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).
OpenPOWER on IntegriCloud