diff --git a/config/user-pam-sepolicy.m4 b/config/user-pam-sepolicy.m4 new file mode 100644 index 000000000000..f200e88e1792 --- /dev/null +++ b/config/user-pam-sepolicy.m4 @@ -0,0 +1,24 @@ +AC_DEFUN([ZFS_AC_CONFIG_USER_PAM_SELINUX], [ + AC_ARG_WITH([pam-selinux], + AS_HELP_STRING([--with-pam-selinux=@<:@/usr/share/selinux/devel@:>@], + [build pam_zfs_key module SELinux policy [[default: check]]]), + [ + AS_IF([test "x$with_pam_selinux" = xyes], + with_pam_selinux=/usr/share/selinux/devel) + ], + [with_pam_selinux=no]) + + AS_IF([test "x$with_pam_selinux" != "xno"], [ + AS_IF([test -f "$with_pam_selinux/Makefile"], + [selinux_makefile="$with_pam_selinux/Makefile"], + [ + AC_MSG_FAILURE([ + *** SELinux policy development tools missing. + ]) + with_pam_selinux=no + ] + ) + ]) + AC_SUBST(selinux_makefile) + AM_CONDITIONAL([WITH_PAM_SELINUX], [test "x$with_pam_selinux" != xno]) +]) diff --git a/config/user.m4 b/config/user.m4 index f450af47e04d..ecfe490070bf 100644 --- a/config/user.m4 +++ b/config/user.m4 @@ -26,6 +26,7 @@ AC_DEFUN([ZFS_AC_CONFIG_USER], [ ZFS_AC_CONFIG_USER_AIO_H ZFS_AC_CONFIG_USER_CLOCK_GETTIME ZFS_AC_CONFIG_USER_PAM + ZFS_AC_CONFIG_USER_PAM_SELINUX ZFS_AC_CONFIG_USER_RUNSTATEDIR ZFS_AC_CONFIG_USER_MAKEDEV_IN_SYSMACROS ZFS_AC_CONFIG_USER_MAKEDEV_IN_MKDEV diff --git a/configure.ac b/configure.ac index 990958bafa1e..555b0b7de3d8 100644 --- a/configure.ac +++ b/configure.ac @@ -101,6 +101,7 @@ AC_CONFIG_FILES([ contrib/initramfs/scripts/Makefile contrib/initramfs/scripts/local-top/Makefile contrib/pam_zfs_key/Makefile + contrib/pam_zfs_key/selinux/Makefile contrib/pyzfs/Makefile contrib/pyzfs/setup.py contrib/zcp/Makefile diff --git a/contrib/pam_zfs_key/Makefile.am b/contrib/pam_zfs_key/Makefile.am index f0f2550afccb..db30d0ca33f1 100644 --- a/contrib/pam_zfs_key/Makefile.am +++ b/contrib/pam_zfs_key/Makefile.am @@ -17,3 +17,9 @@ pam_zfs_key_la_LDFLAGS = -version-info 1:0:0 -avoid-version -module -shared pam_zfs_key_la_LIBADD += -lpam $(LIBCRYPTO_LIBS) dist_pamconfigs_DATA = zfs_key + +if WITH_PAM_SELINUX +SUBDIRS = selinux +endif + +DIST_SUBDIRS = selinux diff --git a/contrib/pam_zfs_key/selinux/.gitignore b/contrib/pam_zfs_key/selinux/.gitignore new file mode 100644 index 000000000000..823eb56ce055 --- /dev/null +++ b/contrib/pam_zfs_key/selinux/.gitignore @@ -0,0 +1,2 @@ +/*.pp +/tmp/ diff --git a/contrib/pam_zfs_key/selinux/Makefile.am b/contrib/pam_zfs_key/selinux/Makefile.am new file mode 100644 index 000000000000..f75977b2cdf8 --- /dev/null +++ b/contrib/pam_zfs_key/selinux/Makefile.am @@ -0,0 +1,16 @@ + +if WITH_PAM_SELINUX + +refpoldir = $(datadir)/selinux/packages +refpol_DATA = pam_zfs_key.pp + +refpolifdir = $(datadir)/selinux/devel/include/contrib +refpolif_DATA = pam_zfs_key.if + +pam_zfs_key.pp: pam_zfs_key.te pam_zfs_key.fc pam_zfs_key.if + $(MAKE) -f $(selinux_makefile) $@ + +clean-local: + rm -f *.tc *.pp + +endif diff --git a/contrib/pam_zfs_key/selinux/pam_zfs_key-selinux.spec b/contrib/pam_zfs_key/selinux/pam_zfs_key-selinux.spec new file mode 100644 index 000000000000..db6f5d28dfca --- /dev/null +++ b/contrib/pam_zfs_key/selinux/pam_zfs_key-selinux.spec @@ -0,0 +1,69 @@ + +%define relabel_files() \ +restorecon -R /usr/lib64/security/pam_zfs_key.so; \ +restorecon -R /dev/zfs; \ +restorecon -R /var/run/pam_zfs_key; \ + +%define selinux_policyver 34.23-1 + +Name: @PACKAGE@ +Version: @VERSION@ +Release: @RELEASE@%{?dist} +Summary: SELinux policy module for pam_zfs_key + +Name: pam_zfs_key-selinux +Version: 1.0 +Release: 1%{?dist} + + +License: @ZFS_META_LICENSE@ +URL: https://github.com/openzfs/zfs +Source0: pam_zfs_key.pp +Source1: pam_zfs_key.if + + +Requires: policycoreutils, libselinux-utils +Requires(post): selinux-policy-base >= %{selinux_policyver}, policycoreutils +Requires(postun): policycoreutils +BuildArch: noarch + +%description +This package installs and sets up the SELinux policy security module for +pam_zfs_key. + +%install +install -d %{buildroot}%{_datadir}/selinux/packages +install -m 644 %{SOURCE0} %{buildroot}%{_datadir}/selinux/packages +install -d %{buildroot}%{_datadir}/selinux/devel/include/contrib +install -m 644 %{SOURCE1} %{buildroot}%{_datadir}/selinux/devel/include/contrib/ +install -d %{buildroot}/etc/selinux/targeted/contexts/users/ + + +%post +semodule -n -i %{_datadir}/selinux/packages/pam_zfs_key.pp +if /usr/sbin/selinuxenabled ; then + /usr/sbin/load_policy + %relabel_files + +fi; +exit 0 + +%postun +if [ $1 -eq 0 ]; then + semodule -n -r pam_zfs_key + if /usr/sbin/selinuxenabled ; then + /usr/sbin/load_policy + %relabel_files + + fi; +fi; +exit 0 + +%files +%attr(0600,root,root) %{_datadir}/selinux/packages/pam_zfs_key.pp +%{_datadir}/selinux/devel/include/contrib/pam_zfs_key.if + + +%changelog +* Thu Jan 13 2022 YOUR NAME 1.0-1 +- Initial version diff --git a/contrib/pam_zfs_key/selinux/pam_zfs_key.fc b/contrib/pam_zfs_key/selinux/pam_zfs_key.fc new file mode 100644 index 000000000000..c42434a5b693 --- /dev/null +++ b/contrib/pam_zfs_key/selinux/pam_zfs_key.fc @@ -0,0 +1 @@ +/var/run/pam_zfs_key(/.*)? gen_context(system_u:object_r:pam_var_run_t,s0) diff --git a/contrib/pam_zfs_key/selinux/pam_zfs_key.if b/contrib/pam_zfs_key/selinux/pam_zfs_key.if new file mode 100644 index 000000000000..e3eb9e533735 --- /dev/null +++ b/contrib/pam_zfs_key/selinux/pam_zfs_key.if @@ -0,0 +1,101 @@ + +## policy for pam_zfs_key + +######################################## +## +## Allow domain to query datasets on ZFS. +## +## +## +## Domain allowed access. +## +## +# +interface(`pam_zfs_key_query',` + gen_require(` + type device_t; + ') + + dnl Using ifdef() keeps `sepolgen-ifgen' from complaining + define(`ZFS_IOC') + ifdef(`ZFS_IOC', ` + define(`ZFS_IOC_POOL_STATS', `0x5a05') + define(`ZFS_IOC_OBJSET_STATS', `0x5a12') + define(`ZFS_IOC_POOL_GET_PROPS', `0x5a27') + define(`ZFS_IOC_LOAD_KEY', `0x5a49') + define(`ZFS_IOC_UNLOAD_KEY', `0x5a4a') + define(`ZFS_IOC_CHANGE_KEY', `0x5a4b') + ') + + allow $1 device_t:chr_file { open ioctl }; + allowxperm $1 device_t:chr_file ioctl ZFS_IOC_OBJSET_STATS; + + # While /dev/zfs does not support read() or write(), libzfs opens it with + # O_RDWR, meaning we need these permissions. Remove these if ZFS changes + # to using the Linux specialization O_PATH (or O_EXEC). + allow $1 device_t:chr_file { read write }; +') + +######################################## +## +## Allow domain to open and close a session on the pam_zfs_key PAM module. +## +## +## +## Domain allowed access. +## +## +# +interface(`pam_zfs_key_session',` + gen_require(` + type device_t; + type fs_t; + type pam_var_run_t; + type user_home_dir_t; + ') + + files_pid_filetrans($1, pam_var_run_t, dir, "pam_zfs_key") + + pam_zfs_key_query($1) + allowxperm $1 device_t:chr_file ioctl { ZFS_IOC_LOAD_KEY ZFS_IOC_UNLOAD_KEY }; + + # The zfs_open() function returns both a zfs handle and a zpool handle for + # its containing pool; as part of the zpool fetching, the function grabs + # the pool stats. Despite marking the pool as unavailable, the library + # will still query the pool properties to check for read-only status. + dontauditxperm $1 device_t:chr_file ioctl ZFS_IOC_POOL_STATS; + + # Needed to determine if the zpool is read-only (if so, the dataset must be + # mounted read-only too). + allowxperm $1 device_t:chr_file ioctl ZFS_IOC_POOL_GET_PROPS; + + allow $1 fs_t:filesystem { mount unmount }; + allow $1 user_home_dir_t:dir mounton; +') + +######################################## +## +## Allow domain to change password on the pam_zfs_key PAM module. +## +## +## +## Domain allowed access. +## +## +# +interface(`pam_zfs_key_password',` + gen_require(` + type device_t; + ') + + pam_zfs_key_query($1) + + # The zfs_open() function returns both a zfs handle and a zpool handle for + # its containing pool; as part of the zpool fetching, the function grabs + # the pool stats. The zpool information does not appear to be used when + # changing the key, but cannot be skipped easily, so silence the denial. + dontauditxperm $1 device_t:chr_file ioctl ZFS_IOC_POOL_STATS; + + auditallowxperm $1 device_t:chr_file ioctl ZFS_IOC_CHANGE_KEY; + allowxperm $1 device_t:chr_file ioctl ZFS_IOC_CHANGE_KEY; +') diff --git a/contrib/pam_zfs_key/selinux/pam_zfs_key.te b/contrib/pam_zfs_key/selinux/pam_zfs_key.te new file mode 100644 index 000000000000..04d745803183 --- /dev/null +++ b/contrib/pam_zfs_key/selinux/pam_zfs_key.te @@ -0,0 +1,17 @@ +policy_module(pam_zfs_key, 1.0.0) + +######################################## +# +# pam_zfs_key local policy +# + +gen_require(` + type local_login_t; + type sshd_t; + + type passwd_t; +') +pam_zfs_key_session(local_login_t) +pam_zfs_key_session(sshd_t) + +pam_zfs_key_password(passwd_t)