From 11b9ec23b98eefe1e7bde0033dc8285f94cb0b90 Mon Sep 17 00:00:00 2001 From: Matthew Thode Date: Thu, 19 Dec 2013 00:24:14 -0600 Subject: [PATCH] Add full SELinux support Four new dataset properties have been added to support SELinux. They are 'context', 'fscontext', 'defcontext' and 'rootcontext' which map directly to the context options described in mount(8). When one of these properties is set to something other than 'none'. That string will be passed verbatim as a mount option for the given context when the filesystem is mounted. For example, if you wanted the rootcontext for a filesystem to be set to 'system_u:object_r:fs_t' you would set the property as follows: $ zfs set rootcontext="system_u:object_r:fs_t" storage-pool/media This will ensure the filesystem is automatically mounted with that rootcontext. It is equivalent to manually specifying the rootcontext with the -o option like this: $ zfs mount -o rootcontext=system_u:object_r:fs_t storage-pool/media By default all four contexts are set to 'none'. Further information on SELinux contexts is detailed in mount(8) and selinux(8) man pages. Signed-off-by: Matthew Thode Signed-off-by: Brian Behlendorf Signed-off-by: Richard Yao Closes #1504 --- cmd/mount_zfs/Makefile.am | 2 - cmd/mount_zfs/mount_zfs.c | 88 ++++++++++++++++++++++----------- config/user-selinux.m4 | 36 -------------- config/user.m4 | 1 - include/sys/fs/zfs.h | 4 ++ lib/libspl/include/sys/mntent.h | 2 - man/man8/mount.zfs.8 | 13 +++++ man/man8/zfs.8 | 46 +++++++++++++++++ module/zcommon/zfs_prop.c | 12 +++++ rpm/generic/zfs.spec.in | 12 +---- 10 files changed, 134 insertions(+), 82 deletions(-) delete mode 100644 config/user-selinux.m4 diff --git a/cmd/mount_zfs/Makefile.am b/cmd/mount_zfs/Makefile.am index fe34c96b76..e5f3d083b0 100644 --- a/cmd/mount_zfs/Makefile.am +++ b/cmd/mount_zfs/Makefile.am @@ -20,5 +20,3 @@ mount_zfs_LDADD = \ $(top_builddir)/lib/libzpool/libzpool.la \ $(top_builddir)/lib/libzfs/libzfs.la \ $(top_builddir)/lib/libzfs_core/libzfs_core.la - -mount_zfs_LDADD += $(LIBSELINUX) diff --git a/cmd/mount_zfs/mount_zfs.c b/cmd/mount_zfs/mount_zfs.c index 82fa67c932..6cb23d1c6d 100644 --- a/cmd/mount_zfs/mount_zfs.c +++ b/cmd/mount_zfs/mount_zfs.c @@ -31,9 +31,6 @@ #include #include #include -#ifdef HAVE_LIBSELINUX -#include -#endif /* HAVE_LIBSELINUX */ libzfs_handle_t *g_zfs; @@ -77,11 +74,10 @@ static const option_map_t option_map[] = { #ifdef MS_STRICTATIME { MNTOPT_DFRATIME, MS_STRICTATIME, ZS_COMMENT }, #endif - { MNTOPT_CONTEXT, MS_COMMENT, ZS_NOCONTEXT }, - { MNTOPT_NOCONTEXT, MS_COMMENT, ZS_NOCONTEXT }, - { MNTOPT_FSCONTEXT, MS_COMMENT, ZS_NOCONTEXT }, - { MNTOPT_DEFCONTEXT, MS_COMMENT, ZS_NOCONTEXT }, - { MNTOPT_ROOTCONTEXT, MS_COMMENT, ZS_NOCONTEXT }, + { MNTOPT_CONTEXT, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_FSCONTEXT, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_DEFCONTEXT, MS_COMMENT, ZS_COMMENT }, + { MNTOPT_ROOTCONTEXT, MS_COMMENT, ZS_COMMENT }, #ifdef MS_I_VERSION { MNTOPT_IVERSION, MS_I_VERSION, ZS_COMMENT }, #endif @@ -338,11 +334,35 @@ mtab_update(char *dataset, char *mntpoint, char *type, char *mntopts) return (MOUNT_SUCCESS); } +static void +__zfs_selinux_setcontext(const char *name, const char *context, char *mntopts, + char *mtabopt) +{ + char tmp[MNT_LINE_MAX]; + + snprintf(tmp, MNT_LINE_MAX, ",%s=\"%s\"", name, context); + strlcat(mntopts, tmp, MNT_LINE_MAX); + strlcat(mtabopt, tmp, MNT_LINE_MAX); +} + +static void +zfs_selinux_setcontext(zfs_handle_t *zhp, zfs_prop_t zpt, const char *name, + char *mntopts, char *mtabopt) +{ + char context[ZFS_MAXPROPLEN]; + + if (zfs_prop_get(zhp, zpt, context, sizeof (context), + NULL, NULL, 0, B_FALSE) == 0) { + if (strcmp(context, "none") != 0) + __zfs_selinux_setcontext(name, context, mntopts, mtabopt); + } +} + int main(int argc, char **argv) { zfs_handle_t *zhp; - char legacy[ZFS_MAXPROPLEN]; + char prop[ZFS_MAXPROPLEN]; char mntopts[MNT_LINE_MAX] = { '\0' }; char badopt[MNT_LINE_MAX] = { '\0' }; char mtabopt[MNT_LINE_MAX] = { '\0' }; @@ -437,22 +457,6 @@ main(int argc, char **argv) } } -#ifdef HAVE_LIBSELINUX - /* - * Automatically add the default zfs context when selinux is enabled - * and the caller has not specified their own context. This must be - * done until zfs is added to the default selinux policy configuration - * as a known filesystem type which supports xattrs. - */ - if (is_selinux_enabled() && !(zfsflags & ZS_NOCONTEXT)) { - (void) strlcat(mntopts, ",context=\"system_u:" - "object_r:file_t:s0\"", sizeof (mntopts)); - (void) strlcat(mtabopt, ",context=\"system_u:" - "object_r:file_t:s0\"", sizeof (mtabopt)); - } -#endif /* HAVE_LIBSELINUX */ - - if (verbose) (void) fprintf(stdout, gettext("mount.zfs:\n" " dataset: \"%s\"\n mountpoint: \"%s\"\n" @@ -480,12 +484,36 @@ main(int argc, char **argv) return (MOUNT_USAGE); } + /* + * Checks to see if the ZFS_PROP_SELINUX_CONTEXT exists + * if it does, create a tmp variable in case it's needed + * checks to see if the selinux context is set to the default + * if it is, allow the setting of the other context properties + * this is needed because the 'context' property overrides others + * if it is not the default, set the 'context' property + */ + if (zfs_prop_get(zhp, ZFS_PROP_SELINUX_CONTEXT, prop, sizeof (prop), + NULL, NULL, 0, B_FALSE) == 0) { + if (strcmp(prop, "none") == 0) { + zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_FSCONTEXT, + MNTOPT_FSCONTEXT, mntopts, mtabopt); + zfs_selinux_setcontext(zhp, ZFS_PROP_SELINUX_DEFCONTEXT, + MNTOPT_DEFCONTEXT, mntopts, mtabopt); + zfs_selinux_setcontext(zhp, + ZFS_PROP_SELINUX_ROOTCONTEXT, MNTOPT_ROOTCONTEXT, + mntopts, mtabopt); + } else { + __zfs_selinux_setcontext(MNTOPT_CONTEXT, + prop, mntopts, mtabopt); + } + } + /* treat all snapshots as legacy mount points */ if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) - (void) strlcpy(legacy, ZFS_MOUNTPOINT_LEGACY, ZFS_MAXPROPLEN); + (void) strlcpy(prop, ZFS_MOUNTPOINT_LEGACY, ZFS_MAXPROPLEN); else - (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, legacy, - sizeof (legacy), NULL, NULL, 0, B_FALSE); + (void) zfs_prop_get(zhp, ZFS_PROP_MOUNTPOINT, prop, + sizeof (prop), NULL, NULL, 0, B_FALSE); zfs_close(zhp); libzfs_fini(g_zfs); @@ -501,7 +529,7 @@ main(int argc, char **argv) * using zfs as your root file system both rc.sysinit/umountroot and * systemd depend on 'mount -o remount ' to work. */ - if (zfsutil && (strcmp(legacy, ZFS_MOUNTPOINT_LEGACY) == 0)) { + if (zfsutil && (strcmp(prop, ZFS_MOUNTPOINT_LEGACY) == 0)) { (void) fprintf(stderr, gettext( "filesystem '%s' cannot be mounted using 'zfs mount'.\n" "Use 'zfs set mountpoint=%s' or 'mount -t zfs %s %s'.\n" @@ -511,7 +539,7 @@ main(int argc, char **argv) } if (!zfsutil && !(remount || fake) && - strcmp(legacy, ZFS_MOUNTPOINT_LEGACY)) { + strcmp(prop, ZFS_MOUNTPOINT_LEGACY)) { (void) fprintf(stderr, gettext( "filesystem '%s' cannot be mounted using 'mount'.\n" "Use 'zfs set mountpoint=%s' or 'zfs mount %s'.\n" diff --git a/config/user-selinux.m4 b/config/user-selinux.m4 deleted file mode 100644 index 84df6ce7b9..0000000000 --- a/config/user-selinux.m4 +++ /dev/null @@ -1,36 +0,0 @@ -dnl # -dnl # Check to see if the selinux libraries are available. If they -dnl # are then they will be consulted during mount to determine if -dnl # selinux is enabled or disabled. -dnl # -AC_DEFUN([ZFS_AC_CONFIG_USER_LIBSELINUX], [ - AC_ARG_WITH([selinux], - [AS_HELP_STRING([--with-selinux], - [support selinux @<:@default=check@:>@])], - [], - [with_selinux=check]) - - LIBSELINUX= - AS_IF([test "x$with_selinux" != xno], [ - AC_CHECK_HEADER([selinux/selinux.h], [ - AC_CHECK_LIB([selinux], [is_selinux_enabled], [ - AC_SUBST([LIBSELINUX], ["-lselinux"]) - AC_DEFINE([HAVE_LIBSELINUX], 1, - [Define if you have selinux]) - ], [ - AS_IF([test "x$with_selinux" != xcheck], - [AC_MSG_FAILURE( - [--with-selinux given but unavailable]) - ]) - ]) - ], [ - AS_IF([test "x$with_selinux" != xcheck], - [AC_MSG_FAILURE( - [--with-selinux given but unavailable]) - ]) - ]) - ], [ - AC_MSG_CHECKING([for selinux support]) - AC_MSG_RESULT([no]) - ]) -]) diff --git a/config/user.m4 b/config/user.m4 index 6925e56f4b..4f9963787d 100644 --- a/config/user.m4 +++ b/config/user.m4 @@ -9,6 +9,5 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [ ZFS_AC_CONFIG_USER_ZLIB ZFS_AC_CONFIG_USER_LIBUUID ZFS_AC_CONFIG_USER_LIBBLKID - ZFS_AC_CONFIG_USER_LIBSELINUX ZFS_AC_CONFIG_USER_FRAME_LARGER_THAN ]) diff --git a/include/sys/fs/zfs.h b/include/sys/fs/zfs.h index cfcc78b80e..23303d7414 100644 --- a/include/sys/fs/zfs.h +++ b/include/sys/fs/zfs.h @@ -143,6 +143,10 @@ typedef enum { ZFS_PROP_INCONSISTENT, /* not exposed to the user */ ZFS_PROP_SNAPDEV, ZFS_PROP_ACLTYPE, + ZFS_PROP_SELINUX_CONTEXT, + ZFS_PROP_SELINUX_FSCONTEXT, + ZFS_PROP_SELINUX_DEFCONTEXT, + ZFS_PROP_SELINUX_ROOTCONTEXT, ZFS_NUM_PROPS } zfs_prop_t; diff --git a/lib/libspl/include/sys/mntent.h b/lib/libspl/include/sys/mntent.h index a4be01d754..b57ffee83d 100644 --- a/lib/libspl/include/sys/mntent.h +++ b/lib/libspl/include/sys/mntent.h @@ -47,7 +47,6 @@ #define MNTOPT_AUTO "auto" /* automount */ #define MNTOPT_NOAUTO "noauto" /* do not automount */ #define MNTOPT_CONTEXT "context" /* selinux context */ -#define MNTOPT_NOCONTEXT "nocontext" /* No selinux context (zfs-only) */ #define MNTOPT_FSCONTEXT "fscontext" /* selinux fscontext */ #define MNTOPT_DEFCONTEXT "defcontext" /* selinux defcontext */ #define MNTOPT_ROOTCONTEXT "rootcontext" /* selinux rootcontext */ @@ -99,6 +98,5 @@ #define ZS_COMMENT 0x00000000 /* comment */ #define ZS_ZFSUTIL 0x00000001 /* caller is zfs(8) */ -#define ZS_NOCONTEXT 0x00000002 /* do not add selinux context */ #endif /* _SYS_MNTENT_H */ diff --git a/man/man8/mount.zfs.8 b/man/man8/mount.zfs.8 index 60c36fe4e3..b4e2406a22 100644 --- a/man/man8/mount.zfs.8 +++ b/man/man8/mount.zfs.8 @@ -75,6 +75,19 @@ Increase verbosity. .BI "\-h" Print the usage message. .TP +.BI "\-o context" +This flag sets the SELinux context for all files in the filesytem +under that mountpoint. +.TP +.BI "\-o fscontext" +This flag sets the SELinux context for the filesytem being mounted. +.TP +.BI "\-o defcontext" +This flag sets the SELinux context for unlabled files. +.TP +.BI "\-o rootcontext" +This flag sets the SELinux context for the root inode of the filesystem. +.TP .BI "\-o legacy" This private flag indicates that the .I dataset diff --git a/man/man8/zfs.8 b/man/man8/zfs.8 index 321a297f27..2c540f0597 100644 --- a/man/man8/zfs.8 +++ b/man/man8/zfs.8 @@ -1298,6 +1298,52 @@ Indicates whether the file system should reject file names that include characte .sp .LP The \fBcasesensitivity\fR, \fBnormalization\fR, and \fButf8only\fR properties are also new permissions that can be assigned to non-privileged users by using the \fBZFS\fR delegated administration feature. +.RE + +.sp +.ne 2 +.mk +.na +\fB\fBcontext\fR=\fBSELinux_User:SElinux_Role:Selinux_Type:Sensitivity_Level\fR\fR +.ad +.sp .6 +.RS 4n +This flag sets the SELinux context for all files in the filesytem under the mountpoint for that filesystem. See \fBselinux\fR(8) for more information. +.RE + +.sp +.ne 2 +.mk +.na +\fB\fBfscontext\fR=\fBSELinux_User:SElinux_Role:Selinux_Type:Sensitivity_Level\fR\fR +.ad +.sp .6 +.RS 4n +This flag sets the SELinux context for the filesytem being mounted. See \fBselinux\fR(8) for more information. +.RE + +.sp +.ne 2 +.mk +.na +\fB\fBdefntext\fR=\fBSELinux_User:SElinux_Role:Selinux_Type:Sensitivity_Level\fR\fR +.ad +.sp .6 +.RS 4n +This flag sets the SELinux context for unlabeled files. See \fBselinux\fR(8) for more information. +.RE + +.sp +.ne 2 +.mk +.na +\fB\fBrootcontext\fR=\fBSELinux_User:SElinux_Role:Selinux_Type:Sensitivity_Level\fR\fR +.ad +.sp .6 +.RS 4n +This flag sets the SELinux context for the root inode of the filesystem. See \fBselinux\fR(8) for more information. +.RE + .SS "Temporary Mount Point Properties" .LP When a file system is mounted, either through \fBmount\fR(8) for legacy mounts or the \fBzfs mount\fR command for normal file systems, its mount options are set according to its properties. The correlation between properties and mount options is as follows: diff --git a/module/zcommon/zfs_prop.c b/module/zcommon/zfs_prop.c index 98d5bea96c..121b1eb57d 100644 --- a/module/zcommon/zfs_prop.c +++ b/module/zcommon/zfs_prop.c @@ -332,6 +332,18 @@ zfs_prop_init(void) zprop_register_string(ZFS_PROP_MLSLABEL, "mlslabel", ZFS_MLSLABEL_DEFAULT, PROP_INHERIT, ZFS_TYPE_DATASET, "", "MLSLABEL"); + zprop_register_string(ZFS_PROP_SELINUX_CONTEXT, "context", + "none", PROP_DEFAULT, ZFS_TYPE_DATASET, "", + "CONTEXT"); + zprop_register_string(ZFS_PROP_SELINUX_FSCONTEXT, "fscontext", + "none", PROP_DEFAULT, ZFS_TYPE_DATASET, "", + "FSCONTEXT"); + zprop_register_string(ZFS_PROP_SELINUX_DEFCONTEXT, "defcontext", + "none", PROP_DEFAULT, ZFS_TYPE_DATASET, "", + "DEFCONTEXT"); + zprop_register_string(ZFS_PROP_SELINUX_ROOTCONTEXT, "rootcontext", + "none", PROP_DEFAULT, ZFS_TYPE_DATASET, "", + "ROOTCONTEXT"); /* readonly number properties */ zprop_register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY, diff --git a/rpm/generic/zfs.spec.in b/rpm/generic/zfs.spec.in index 6425d1e011..1e64ac18ea 100644 --- a/rpm/generic/zfs.spec.in +++ b/rpm/generic/zfs.spec.in @@ -10,7 +10,6 @@ %bcond_with debug %bcond_with blkid -%bcond_with selinux Name: @PACKAGE@ @@ -38,9 +37,6 @@ BuildRequires: libuuid-devel %if %{with blkid} BuildRequires: libblkid-devel %endif -%if %{with selinux} -BuildRequires: libselinux-devel -%endif %endif %description @@ -89,11 +85,6 @@ image which is ZFS aware. %else %define blkid --without-blkid %endif -%if %{with selinux} - %define selinux --with-selinux -%else - %define selinux --without-selinux -%endif %setup -q @@ -104,8 +95,7 @@ image which is ZFS aware. --with-dracutdir=%{_dracutdir} \ --disable-static \ %{debug} \ - %{blkid} \ - %{selinux} + %{blkid} make %{?_smp_mflags} %install