From 0e5c6bd43646821dc676a6db03b7175f2668ec88 Mon Sep 17 00:00:00 2001 From: Jamie Gritton Date: Fri, 4 May 2018 20:54:27 +0000 Subject: [PATCH] Make it easier for filesystems to count themselves as jail-enabled, by doing most of the work in a new function prison_add_vfs in kern_jail.c Now a jail-enabled filesystem need only mark itself with VFCF_JAIL, and the rest is taken care of. This includes adding a jail parameter like allow.mount.foofs, and a sysctl like security.jail.mount_foofs_allowed. Both of these used to be a static list of known filesystems, with predefined permission bits. Reviewed by: kib Differential Revision: D14681 --- lib/libjail/jail.c | 8 +- .../uts/common/fs/zfs/zfs_vfsops.c | 3 - sys/compat/linprocfs/linprocfs.c | 2 +- sys/compat/linsysfs/linsysfs.c | 2 +- sys/fs/devfs/devfs_vfsops.c | 3 - sys/fs/fdescfs/fdesc_vfsops.c | 4 - sys/fs/nullfs/null_vfsops.c | 3 - sys/fs/procfs/procfs.c | 2 +- sys/fs/pseudofs/pseudofs.h | 6 +- sys/fs/tmpfs/tmpfs_vfsops.c | 4 - sys/kern/kern_jail.c | 177 +++++++++++------- sys/kern/vfs_init.c | 6 +- sys/kern/vfs_mount.c | 12 +- sys/kern/vfs_subr.c | 26 +-- sys/sys/jail.h | 17 +- sys/sys/mount.h | 4 +- usr.sbin/jail/jail.8 | 56 +++--- 17 files changed, 191 insertions(+), 144 deletions(-) diff --git a/lib/libjail/jail.c b/lib/libjail/jail.c index 5218568001fb..3dd87b1072d1 100644 --- a/lib/libjail/jail.c +++ b/lib/libjail/jail.c @@ -1048,7 +1048,13 @@ kldload_param(const char *name) else if (strcmp(name, "sysvmsg") == 0 || strcmp(name, "sysvsem") == 0 || strcmp(name, "sysvshm") == 0) kl = kldload(name); - else { + else if (strncmp(name, "allow.mount.", 12) == 0) { + /* Load the matching filesystem */ + kl = kldload(name + 12); + if (kl < 0 && errno == ENOENT && + strncmp(name + 12, "no", 2) == 0) + kl = kldload(name + 14); + } else { errno = ENOENT; return (-1); } diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c index 9cd31ee8b1d6..76ff79f17ffc 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vfsops.c @@ -1640,9 +1640,6 @@ zfs_mount(vfs_t *vfsp) osname = spn.pn_path; #else /* !illumos */ - if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_ZFS)) - return (SET_ERROR(EPERM)); - if (vfs_getopt(vfsp->mnt_optnew, "from", (void **)&osname, NULL)) return (SET_ERROR(EINVAL)); diff --git a/sys/compat/linprocfs/linprocfs.c b/sys/compat/linprocfs/linprocfs.c index 00de29d84064..d56f23e679e8 100644 --- a/sys/compat/linprocfs/linprocfs.c +++ b/sys/compat/linprocfs/linprocfs.c @@ -1652,7 +1652,7 @@ linprocfs_uninit(PFS_INIT_ARGS) return (0); } -PSEUDOFS(linprocfs, 1, PR_ALLOW_MOUNT_LINPROCFS); +PSEUDOFS(linprocfs, 1, VFCF_JAIL); #if defined(__amd64__) MODULE_DEPEND(linprocfs, linux_common, 1, 1, 1); #else diff --git a/sys/compat/linsysfs/linsysfs.c b/sys/compat/linsysfs/linsysfs.c index 1e66c17ee727..7ef2f2810a5c 100644 --- a/sys/compat/linsysfs/linsysfs.c +++ b/sys/compat/linsysfs/linsysfs.c @@ -556,7 +556,7 @@ linsysfs_uninit(PFS_INIT_ARGS) return (0); } -PSEUDOFS(linsysfs, 1, PR_ALLOW_MOUNT_LINSYSFS); +PSEUDOFS(linsysfs, 1, VFCF_JAIL); #if defined(__amd64__) MODULE_DEPEND(linsysfs, linux_common, 1, 1, 1); #else diff --git a/sys/fs/devfs/devfs_vfsops.c b/sys/fs/devfs/devfs_vfsops.c index 335c2103a9cd..c093cfb4c151 100644 --- a/sys/fs/devfs/devfs_vfsops.c +++ b/sys/fs/devfs/devfs_vfsops.c @@ -83,9 +83,6 @@ 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); diff --git a/sys/fs/fdescfs/fdesc_vfsops.c b/sys/fs/fdescfs/fdesc_vfsops.c index 2097ddcee4b1..6737bfb94f5e 100644 --- a/sys/fs/fdescfs/fdesc_vfsops.c +++ b/sys/fs/fdescfs/fdesc_vfsops.c @@ -81,13 +81,9 @@ static int fdesc_mount(struct mount *mp) { struct fdescmount *fmp; - struct thread *td = curthread; struct vnode *rvp; int error; - if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_FDESCFS)) - return (EPERM); - /* * Update is a no-op */ diff --git a/sys/fs/nullfs/null_vfsops.c b/sys/fs/nullfs/null_vfsops.c index 4def1cf522b4..8ea7b07575bf 100644 --- a/sys/fs/nullfs/null_vfsops.c +++ b/sys/fs/nullfs/null_vfsops.c @@ -78,15 +78,12 @@ 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/fs/procfs/procfs.c b/sys/fs/procfs/procfs.c index fdaf1141aaf0..cfc4f5e8eb24 100644 --- a/sys/fs/procfs/procfs.c +++ b/sys/fs/procfs/procfs.c @@ -215,4 +215,4 @@ procfs_uninit(PFS_INIT_ARGS) return (0); } -PSEUDOFS(procfs, 1, PR_ALLOW_MOUNT_PROCFS); +PSEUDOFS(procfs, 1, VFCF_JAIL); diff --git a/sys/fs/pseudofs/pseudofs.h b/sys/fs/pseudofs/pseudofs.h index a5bc1a3389ca..c60ed2fa3d07 100644 --- a/sys/fs/pseudofs/pseudofs.h +++ b/sys/fs/pseudofs/pseudofs.h @@ -272,7 +272,7 @@ int pfs_destroy (struct pfs_node *pn); /* * Now for some initialization magic... */ -#define PSEUDOFS(name, version, jflag) \ +#define PSEUDOFS(name, version, flags) \ \ static struct pfs_info name##_info = { \ #name, \ @@ -282,8 +282,6 @@ static struct pfs_info name##_info = { \ \ static int \ _##name##_mount(struct mount *mp) { \ - if (jflag && !prison_allow(curthread->td_ucred, jflag)) \ - return (EPERM); \ return (pfs_mount(&name##_info, mp)); \ } \ \ @@ -306,7 +304,7 @@ static struct vfsops name##_vfsops = { \ .vfs_uninit = _##name##_uninit, \ .vfs_unmount = pfs_unmount, \ }; \ -VFS_SET(name##_vfsops, name, VFCF_SYNTHETIC | (jflag ? VFCF_JAIL : 0)); \ +VFS_SET(name##_vfsops, name, VFCF_SYNTHETIC | flags); \ MODULE_VERSION(name, version); \ MODULE_DEPEND(name, pseudofs, 1, 1, 1); diff --git a/sys/fs/tmpfs/tmpfs_vfsops.c b/sys/fs/tmpfs/tmpfs_vfsops.c index 89a696e1a307..c0c74b01c7d3 100644 --- a/sys/fs/tmpfs/tmpfs_vfsops.c +++ b/sys/fs/tmpfs/tmpfs_vfsops.c @@ -141,7 +141,6 @@ tmpfs_mount(struct mount *mp) sizeof(struct tmpfs_dirent) + sizeof(struct tmpfs_node)); struct tmpfs_mount *tmp; struct tmpfs_node *root; - struct thread *td = curthread; int error; bool nonc; /* Size counters. */ @@ -155,9 +154,6 @@ tmpfs_mount(struct mount *mp) struct vattr va; - if (!prison_allow(td->td_ucred, PR_ALLOW_MOUNT_TMPFS)) - return (EPERM); - if (vfs_filteropt(mp->mnt_optnew, tmpfs_opts)) return (EINVAL); diff --git a/sys/kern/kern_jail.c b/sys/kern/kern_jail.c index 1287614ccef6..e2e7805caed4 100644 --- a/sys/kern/kern_jail.c +++ b/sys/kern/kern_jail.c @@ -111,7 +111,7 @@ struct prison prison0 = { #else .pr_flags = PR_HOST|_PR_IP_SADDRSEL, #endif - .pr_allow = PR_ALLOW_ALL, + .pr_allow = PR_ALLOW_ALL_STATIC, }; MTX_SYSINIT(prison0, &prison0.pr_mtx, "jail mutex", MTX_DEF); @@ -181,7 +181,8 @@ static struct jailsys_flags pr_flag_jailsys[] = { }; const size_t pr_flag_jailsys_size = sizeof(pr_flag_jailsys); -static struct bool_flags pr_flag_allow[] = { +/* Make this array full-size so dynamic parameters can be added. */ +static struct bool_flags pr_flag_allow[NBBY * NBPW] = { {"allow.set_hostname", "allow.noset_hostname", PR_ALLOW_SET_HOSTNAME}, {"allow.sysvipc", "allow.nosysvipc", PR_ALLOW_SYSVIPC}, {"allow.raw_sockets", "allow.noraw_sockets", PR_ALLOW_RAW_SOCKETS}, @@ -189,17 +190,6 @@ static struct bool_flags pr_flag_allow[] = { {"allow.mount", "allow.nomount", PR_ALLOW_MOUNT}, {"allow.quotas", "allow.noquotas", PR_ALLOW_QUOTAS}, {"allow.socket_af", "allow.nosocket_af", PR_ALLOW_SOCKET_AF}, - {"allow.mount.devfs", "allow.mount.nodevfs", PR_ALLOW_MOUNT_DEVFS}, - {"allow.mount.nullfs", "allow.mount.nonullfs", PR_ALLOW_MOUNT_NULLFS}, - {"allow.mount.zfs", "allow.mount.nozfs", PR_ALLOW_MOUNT_ZFS}, - {"allow.mount.procfs", "allow.mount.noprocfs", PR_ALLOW_MOUNT_PROCFS}, - {"allow.mount.tmpfs", "allow.mount.notmpfs", PR_ALLOW_MOUNT_TMPFS}, - {"allow.mount.fdescfs", "allow.mount.nofdescfs", - PR_ALLOW_MOUNT_FDESCFS}, - {"allow.mount.linprocfs", "allow.mount.nolinprocfs", - PR_ALLOW_MOUNT_LINPROCFS}, - {"allow.mount.linsysfs", "allow.mount.nolinsysfs", - PR_ALLOW_MOUNT_LINSYSFS}, {"allow.reserved_ports", "allow.noreserved_ports", PR_ALLOW_RESERVED_PORTS}, }; @@ -318,7 +308,8 @@ kern_jail(struct thread *td, struct jail *j) /* Set permissions for top-level jails from sysctls. */ if (!jailed(td->td_ucred)) { for (bf = pr_flag_allow; - bf < pr_flag_allow + nitems(pr_flag_allow); + bf < pr_flag_allow + nitems(pr_flag_allow) && + bf->flag != 0; bf++) { optiov[opt.uio_iovcnt].iov_base = __DECONST(char *, (jail_default_allow & bf->flag) @@ -654,7 +645,7 @@ kern_jail_set(struct thread *td, struct uio *optuio, int flags) pr_allow = ch_allow = 0; for (bf = pr_flag_allow; - bf < pr_flag_allow + nitems(pr_flag_allow); + bf < pr_flag_allow + nitems(pr_flag_allow) && bf->flag != 0; bf++) { vfs_flagopt(opts, bf->name, &pr_allow, bf->flag); vfs_flagopt(opts, bf->noname, &ch_allow, bf->flag); @@ -2115,7 +2106,7 @@ kern_jail_get(struct thread *td, struct uio *optuio, int flags) goto done_deref; } for (bf = pr_flag_allow; - bf < pr_flag_allow + nitems(pr_flag_allow); + bf < pr_flag_allow + nitems(pr_flag_allow) && bf->flag != 0; bf++) { i = (pr->pr_allow & bf->flag) ? 1 : 0; error = vfs_setopt(opts, bf->name, &i, sizeof(i)); @@ -3615,38 +3606,6 @@ 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 (deprecated)"); -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 the devfs file system (deprecated)"); -SYSCTL_PROC(_security_jail, OID_AUTO, mount_fdescfs_allowed, - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, - NULL, PR_ALLOW_MOUNT_FDESCFS, sysctl_jail_default_allow, "I", - "Processes in jail can mount the fdescfs file system (deprecated)"); -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 the nullfs file system (deprecated)"); -SYSCTL_PROC(_security_jail, OID_AUTO, mount_procfs_allowed, - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, - NULL, PR_ALLOW_MOUNT_PROCFS, sysctl_jail_default_allow, "I", - "Processes in jail can mount the procfs file system (deprecated)"); -SYSCTL_PROC(_security_jail, OID_AUTO, mount_linprocfs_allowed, - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, - NULL, PR_ALLOW_MOUNT_LINPROCFS, sysctl_jail_default_allow, "I", - "Processes in jail can mount the linprocfs file system (deprecated)"); -SYSCTL_PROC(_security_jail, OID_AUTO, mount_linsysfs_allowed, - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, - NULL, PR_ALLOW_MOUNT_LINSYSFS, sysctl_jail_default_allow, "I", - "Processes in jail can mount the linsysfs file system (deprecated)"); -SYSCTL_PROC(_security_jail, OID_AUTO, mount_tmpfs_allowed, - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, - NULL, PR_ALLOW_MOUNT_TMPFS, sysctl_jail_default_allow, "I", - "Processes in jail can mount the tmpfs file system (deprecated)"); -SYSCTL_PROC(_security_jail, OID_AUTO, mount_zfs_allowed, - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, - NULL, PR_ALLOW_MOUNT_ZFS, sysctl_jail_default_allow, "I", - "Processes in jail can mount the zfs file system (deprecated)"); static int sysctl_jail_default_level(SYSCTL_HANDLER_ARGS) @@ -3799,22 +3758,110 @@ SYSCTL_JAIL_PARAM(_allow, reserved_ports, CTLTYPE_INT | CTLFLAG_RW, 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 the devfs file system"); -SYSCTL_JAIL_PARAM(_allow_mount, fdescfs, CTLTYPE_INT | CTLFLAG_RW, - "B", "Jail may mount the fdescfs file system"); -SYSCTL_JAIL_PARAM(_allow_mount, nullfs, CTLTYPE_INT | CTLFLAG_RW, - "B", "Jail may mount the nullfs file system"); -SYSCTL_JAIL_PARAM(_allow_mount, procfs, CTLTYPE_INT | CTLFLAG_RW, - "B", "Jail may mount the procfs file system"); -SYSCTL_JAIL_PARAM(_allow_mount, linprocfs, CTLTYPE_INT | CTLFLAG_RW, - "B", "Jail may mount the linprocfs file system"); -SYSCTL_JAIL_PARAM(_allow_mount, linsysfs, CTLTYPE_INT | CTLFLAG_RW, - "B", "Jail may mount the linsysfs file system"); -SYSCTL_JAIL_PARAM(_allow_mount, tmpfs, CTLTYPE_INT | CTLFLAG_RW, - "B", "Jail may mount the tmpfs file system"); -SYSCTL_JAIL_PARAM(_allow_mount, zfs, CTLTYPE_INT | CTLFLAG_RW, - "B", "Jail may mount the zfs file system"); + +/* + * The VFS system will register jail-aware filesystems here. They each get + * a parameter allow.mount.xxxfs and a flag to check when a jailed user + * attempts to mount. + */ +void +prison_add_vfs(struct vfsconf *vfsp) +{ + char *allow_name, *allow_noname, *mount_allowed; + struct bool_flags *bf; +#ifndef NO_SYSCTL_DESCR + char *descr; +#endif + unsigned allow_flag; + + if (asprintf(&allow_name, M_PRISON, "allow.mount.%s", vfsp->vfc_name) < + 0 || asprintf(&allow_noname, M_PRISON, "allow.mount.no%s", + vfsp->vfc_name) < 0) { + free(allow_name, M_PRISON); + return; + } + + /* + * See if this parameter has already beed added, i.e. if the filesystem + * was previously loaded/unloaded. + */ + mtx_lock(&prison0.pr_mtx); + for (bf = pr_flag_allow; + bf < pr_flag_allow + nitems(pr_flag_allow) && bf->flag != 0; + bf++) { + if (strcmp(bf->name, allow_name) == 0) { + vfsp->vfc_prison_flag = bf->flag; + goto no_add; + } + } + + /* + * Find a free bit in prison0's pr_allow, failing if there are none + * (which shouldn't happen as long as we keep track of how many + * filesystems are jail-aware). + */ + for (allow_flag = 1;; allow_flag <<= 1) { + if (allow_flag == 0) + goto no_add; + if ((prison0.pr_allow & allow_flag) == 0) + break; + } + + /* + * Note the parameter in the next open slot in pr_flag_allow. + * Set the flag last so code that checks pr_flag_allow can do so + * without locking. + */ + for (bf = pr_flag_allow; bf->flag != 0; bf++) + if (bf == pr_flag_allow + nitems(pr_flag_allow)) { + /* This should never happen, but is not fatal. */ + goto no_add; + } + prison0.pr_allow |= allow_flag; + bf->name = allow_name; + bf->noname = allow_noname; + bf->flag = allow_flag; + vfsp->vfc_prison_flag = allow_flag; + mtx_unlock(&prison0.pr_mtx); + + /* + * Create sysctls for the paramter, and the back-compat global + * permission. + */ +#ifndef NO_SYSCTL_DESCR + (void)asprintf(&descr, M_TEMP, "Jail may mount the %s file system", + vfsp->vfc_name); +#endif + (void)SYSCTL_ADD_PROC(NULL, + SYSCTL_CHILDREN(&sysctl___security_jail_param_allow_mount), + OID_AUTO, vfsp->vfc_name, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, + NULL, 0, sysctl_jail_param, "B", descr); +#ifndef NO_SYSCTL_DESCR + free(descr, M_TEMP); +#endif + if (asprintf(&mount_allowed, M_TEMP, "mount_%s_allowed", + vfsp->vfc_name) >= 0) { +#ifndef NO_SYSCTL_DESCR + (void)asprintf(&descr, M_TEMP, + "Processes in jail can mount the %s file system (deprecated)", + vfsp->vfc_name); +#endif + (void)SYSCTL_ADD_PROC(NULL, + SYSCTL_CHILDREN(&sysctl___security_jail), OID_AUTO, + mount_allowed, CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, + NULL, allow_flag, sysctl_jail_default_allow, "I", descr); +#ifndef NO_SYSCTL_DESCR + free(descr, M_TEMP); +#endif + free(mount_allowed, M_TEMP); + } + return; + + no_add: + mtx_unlock(&prison0.pr_mtx); + free(allow_name, M_PRISON); + free(allow_noname, M_PRISON); +} #ifdef RACCT void @@ -4050,7 +4097,7 @@ db_show_prison(struct prison *pr) } db_printf(" allow = 0x%x", pr->pr_allow); for (bf = pr_flag_allow; - bf < pr_flag_allow + nitems(pr_flag_allow); + bf < pr_flag_allow + nitems(pr_flag_allow) && bf->flag != 0; bf++) if (pr->pr_allow & bf->flag) db_printf(" %s", bf->name); diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c index 92186bfb5aaa..5eb38e6d8f61 100644 --- a/sys/kern/vfs_init.c +++ b/sys/kern/vfs_init.c @@ -42,6 +42,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -276,7 +277,10 @@ vfs_register(struct vfsconf *vfc) vfsops->vfs_extattrctl = vfs_stdextattrctl; if (vfsops->vfs_sysctl == NULL) vfsops->vfs_sysctl = vfs_stdsysctl; - + + if (vfc->vfc_flags & VFCF_JAIL) + prison_add_vfs(vfc); + /* * Call init function for this VFS... */ diff --git a/sys/kern/vfs_mount.c b/sys/kern/vfs_mount.c index 40625253b56a..3e325ae7431e 100644 --- a/sys/kern/vfs_mount.c +++ b/sys/kern/vfs_mount.c @@ -842,6 +842,16 @@ vfs_domount_first( ASSERT_VOP_ELOCKED(vp, __func__); KASSERT((fsflags & MNT_UPDATE) == 0, ("MNT_UPDATE shouldn't be here")); + /* + * If the jail of the calling thread lacks permission for this type of + * file system, deny immediately. + */ + if (jailed(td->td_ucred) && !prison_allow(td->td_ucred, + vfsp->vfc_prison_flag)) { + vput(vp); + return (EPERM); + } + /* * If the user is not root, ensure that they own the directory * onto which we are attempting to mount. @@ -1149,8 +1159,6 @@ vfs_domount( vfsp = vfs_byname_kld(fstype, td, &error); if (vfsp == NULL) return (ENODEV); - if (jailed(td->td_ucred) && !(vfsp->vfc_flags & VFCF_JAIL)) - return (EPERM); } /* diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c index fe958cfbfea2..0f1bc60a62bf 100644 --- a/sys/kern/vfs_subr.c +++ b/sys/kern/vfs_subr.c @@ -683,19 +683,21 @@ vfs_suser(struct mount *mp, struct thread *td) { int error; - /* - * If the thread is jailed, but this is not a jail-friendly file - * system, deny immediately. - */ - if (!(mp->mnt_vfc->vfc_flags & VFCF_JAIL) && jailed(td->td_ucred)) - return (EPERM); + if (jailed(td->td_ucred)) { + /* + * If the jail of the calling thread lacks permission for + * this type of file system, deny immediately. + */ + if (!prison_allow(td->td_ucred, mp->mnt_vfc->vfc_prison_flag)) + return (EPERM); - /* - * If the file system was mounted outside the jail of the calling - * thread, deny immediately. - */ - if (prison_check(td->td_ucred, mp->mnt_cred) != 0) - return (EPERM); + /* + * If the file system was mounted outside the jail of the + * calling thread, deny immediately. + */ + if (prison_check(td->td_ucred, mp->mnt_cred) != 0) + return (EPERM); + } /* * If file system supports delegated administration, we don't check diff --git a/sys/sys/jail.h b/sys/sys/jail.h index f1564b6e99f1..1069e003587a 100644 --- a/sys/sys/jail.h +++ b/sys/sys/jail.h @@ -216,7 +216,10 @@ struct prison_racct { #define PR_IP6 0x04000000 /* IPv6 restricted or disabled */ /* by this jail or an ancestor */ -/* Flags for pr_allow */ +/* + * Flags for pr_allow + * Bits not noted here may be used for dynamic allow.mount.xxxfs. + */ #define PR_ALLOW_SET_HOSTNAME 0x00000001 #define PR_ALLOW_SYSVIPC 0x00000002 #define PR_ALLOW_RAW_SOCKETS 0x00000004 @@ -224,17 +227,9 @@ struct prison_racct { #define PR_ALLOW_MOUNT 0x00000010 #define PR_ALLOW_QUOTAS 0x00000020 #define PR_ALLOW_SOCKET_AF 0x00000040 -#define PR_ALLOW_MOUNT_DEVFS 0x00000080 -#define PR_ALLOW_MOUNT_NULLFS 0x00000100 -#define PR_ALLOW_MOUNT_ZFS 0x00000200 -#define PR_ALLOW_MOUNT_PROCFS 0x00000400 -#define PR_ALLOW_MOUNT_TMPFS 0x00000800 -#define PR_ALLOW_MOUNT_FDESCFS 0x00001000 -#define PR_ALLOW_MOUNT_LINPROCFS 0x00002000 -#define PR_ALLOW_MOUNT_LINSYSFS 0x00004000 #define PR_ALLOW_RESERVED_PORTS 0x00008000 #define PR_ALLOW_KMEM_ACCESS 0x00010000 /* reserved, not used yet */ -#define PR_ALLOW_ALL 0x0001ffff +#define PR_ALLOW_ALL_STATIC 0x0001807f /* * OSD methods @@ -364,6 +359,7 @@ struct ucred; struct mount; struct sockaddr; struct statfs; +struct vfsconf; int jailed(struct ucred *cred); int jailed_without_vnet(struct ucred *); void getcredhostname(struct ucred *, char *, size_t); @@ -413,6 +409,7 @@ int prison_if(struct ucred *cred, struct sockaddr *sa); char *prison_name(struct prison *, struct prison *); int prison_priv_check(struct ucred *cred, int priv); int sysctl_jail_param(SYSCTL_HANDLER_ARGS); +void prison_add_vfs(struct vfsconf *vfsp); void prison_racct_foreach(void (*callback)(struct racct *racct, void *arg2, void *arg3), void (*pre)(void), void (*post)(void), void *arg2, void *arg3); diff --git a/sys/sys/mount.h b/sys/sys/mount.h index 9d499004434f..c4f4bebfac64 100644 --- a/sys/sys/mount.h +++ b/sys/sys/mount.h @@ -516,6 +516,7 @@ struct vfsconf { int vfc_typenum; /* historic filesystem type number */ int vfc_refcount; /* number mounted of this type */ int vfc_flags; /* permanent flags */ + int vfc_prison_flag; /* prison allow.mount.* flag */ struct vfsoptdecl *vfc_opts; /* mount options */ TAILQ_ENTRY(vfsconf) vfc_list; /* list of vfscons */ }; @@ -851,7 +852,8 @@ vfs_statfs_t __vfs_statfs; */ #define VFS_VERSION_00 0x19660120 #define VFS_VERSION_01 0x20121030 -#define VFS_VERSION VFS_VERSION_01 +#define VFS_VERSION_02 0x20180504 +#define VFS_VERSION VFS_VERSION_02 #define VFS_SET(vfsops, fsname, flags) \ static struct vfsconf fsname ## _vfsconf = { \ diff --git a/usr.sbin/jail/jail.8 b/usr.sbin/jail/jail.8 index 7a6f1d7d0c38..c0ebe3b05371 100644 --- a/usr.sbin/jail/jail.8 +++ b/usr.sbin/jail/jail.8 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd June 5, 2017 +.Dd May 4, 2018 .Dt JAIL 8 .Os .Sh NAME @@ -545,6 +545,33 @@ is set to a value lower than 2. The devfs ruleset should be restricted from the default by using the .Va devfs_ruleset option. +.It Va allow.quotas +The jail root may administer quotas on the jail's filesystem(s). +This includes filesystems that the jail may share with other jails or +with non-jailed parts of the system. +.It Va allow.socket_af +Sockets within a jail are normally restricted to IPv4, IPv6, local +(UNIX), and route. This allows access to other protocol stacks that +have not had jail functionality added to them. +.It Va allow.reserved_ports +The jail root may bind to ports lower than 1024. +.El +.El +.Pp +Kernel modules may add their own parameters, which only exist when the +module is loaded. +These are typically headed under a parameter named after the module, +with values of +.Dq inherit +to give the jail full use of the module, +.Dq new +to encapsulate the jail in some module-specific way, +and +.Dq disable +to make the module unavailable to the jail. +There also may be other parameters to define jail behavior within the module. +Module-specific parameters include: +.Bl -tag -width indent .It Va allow.mount.fdescfs privileged users inside the jail will be able to mount and unmount the fdescfs file system. @@ -605,33 +632,6 @@ See .Xr zfs 8 for information on how to configure the ZFS filesystem to operate from within a jail. -.It Va allow.quotas -The jail root may administer quotas on the jail's filesystem(s). -This includes filesystems that the jail may share with other jails or -with non-jailed parts of the system. -.It Va allow.socket_af -Sockets within a jail are normally restricted to IPv4, IPv6, local -(UNIX), and route. This allows access to other protocol stacks that -have not had jail functionality added to them. -.It Va allow.reserved_ports -The jail root may bind to ports lower than 1024. -.El -.El -.Pp -Kernel modules may add their own parameters, which only exist when the -module is loaded. -These are typically headed under a parameter named after the module, -with values of -.Dq inherit -to give the jail full use of the module, -.Dq new -to encapsulate the jail in some module-specific way, -and -.Dq disable -to make the module unavailable to the jail. -There also may be other parameters to define jail behavior within the module. -Module-specific parameters include: -.Bl -tag -width indent .It Va linux Determine how a jail's Linux emulation environment appears. A value of