summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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