All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/1] selinux-testsuite: Add filesystem tests
@ 2019-12-20 10:11 Richard Haines
  2019-12-20 10:11 ` [PATCH 1/1] " Richard Haines
  0 siblings, 1 reply; 6+ messages in thread
From: Richard Haines @ 2019-12-20 10:11 UTC (permalink / raw)
  To: selinux; +Cc: Richard Haines

These tests should cover all the areas in selinux/hooks.c that touch
the 'filesystem' class. Each hooks.c function is listed in the 'test'
script as there are some permissions that are checked in multiple places.

Tested on Fedora 31 and Rawhide (5.5 for the new watch perm).

To test fanotify fs watch perm on 5.5+:
1) Build the testsuite policy first:
make -C policy load

2) Add the following CIL statements to watch.cil and install:
semodule -i watch.cil

(common filesystem (watch))
(classcommon filesystem filesystem)
(allow test_filesystem_t self(filesystem (watch)))
; Until 'fs_watch_all_fs(test_filesystem_t)' in Policy use:
(allow test_filesystem_t fs_t (filesystem (watch)))
; Required if notify policy enabled
;(allow test_filesystem_t self (dir (watch_sb)))

3) Edit /usr/share/selinux/devel/include/support/all_perms.spt
   and insert the 'watch' permission at:

define(`all_filesystem_perms',`{ mount remount ..... watch }')

Changes from RFC Patch:
1) Rename mount to filesystem as it is testing the fs permissions
2) Add tests for context=, rootcontext=, fscontext= and defcontext=
3) Add setfscreatecon(3) tests
4) Add tests to build fanotify on 5.5 and travis (not tested)

Richard Haines (1):
  selinux-testsuite: Add filesystem tests

 defconfig                                     |   6 +
 policy/Makefile                               |   4 +
 policy/test_filesystem.te                     | 324 +++++++
 tests/Makefile                                |   7 +
 tests/filesystem/.gitignore                   |  11 +
 tests/filesystem/Makefile                     |  16 +
 tests/filesystem/check_file_context.c         |  75 ++
 tests/filesystem/check_mount_context.c        | 109 +++
 tests/filesystem/create_file.c                |  79 ++
 tests/filesystem/create_file_change_context.c | 143 +++
 tests/filesystem/fanotify_fs.c                |  79 ++
 tests/filesystem/fs_relabel.c                 |  72 ++
 tests/filesystem/grim_reaper.c                |  63 ++
 tests/filesystem/mount.c                      | 130 +++
 tests/filesystem/quotas_test.c                | 134 +++
 tests/filesystem/statfs_test.c                |  65 ++
 tests/filesystem/test                         | 830 ++++++++++++++++++
 tests/filesystem/umount.c                     |  84 ++
 18 files changed, 2231 insertions(+)
 create mode 100644 policy/test_filesystem.te
 create mode 100644 tests/filesystem/.gitignore
 create mode 100644 tests/filesystem/Makefile
 create mode 100644 tests/filesystem/check_file_context.c
 create mode 100644 tests/filesystem/check_mount_context.c
 create mode 100644 tests/filesystem/create_file.c
 create mode 100644 tests/filesystem/create_file_change_context.c
 create mode 100644 tests/filesystem/fanotify_fs.c
 create mode 100644 tests/filesystem/fs_relabel.c
 create mode 100644 tests/filesystem/grim_reaper.c
 create mode 100644 tests/filesystem/mount.c
 create mode 100644 tests/filesystem/quotas_test.c
 create mode 100644 tests/filesystem/statfs_test.c
 create mode 100755 tests/filesystem/test
 create mode 100644 tests/filesystem/umount.c

-- 
2.23.0


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [PATCH 1/1] selinux-testsuite: Add filesystem tests
  2019-12-20 10:11 [PATCH 0/1] selinux-testsuite: Add filesystem tests Richard Haines
@ 2019-12-20 10:11 ` Richard Haines
  2020-01-06 16:11   ` Ondrej Mosnacek
  2020-01-09 14:18   ` Stephen Smalley
  0 siblings, 2 replies; 6+ messages in thread
From: Richard Haines @ 2019-12-20 10:11 UTC (permalink / raw)
  To: selinux; +Cc: Richard Haines

Test filesystem permissions and setfscreatecon(3).

From kernels 5.5 filesystem { watch } is also tested.

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
---
 defconfig                                     |   6 +
 policy/Makefile                               |   4 +
 policy/test_filesystem.te                     | 324 +++++++
 tests/Makefile                                |   7 +
 tests/filesystem/.gitignore                   |  11 +
 tests/filesystem/Makefile                     |  16 +
 tests/filesystem/check_file_context.c         |  75 ++
 tests/filesystem/check_mount_context.c        | 109 +++
 tests/filesystem/create_file.c                |  79 ++
 tests/filesystem/create_file_change_context.c | 143 +++
 tests/filesystem/fanotify_fs.c                |  79 ++
 tests/filesystem/fs_relabel.c                 |  72 ++
 tests/filesystem/grim_reaper.c                |  63 ++
 tests/filesystem/mount.c                      | 130 +++
 tests/filesystem/quotas_test.c                | 134 +++
 tests/filesystem/statfs_test.c                |  65 ++
 tests/filesystem/test                         | 830 ++++++++++++++++++
 tests/filesystem/umount.c                     |  84 ++
 18 files changed, 2231 insertions(+)
 create mode 100644 policy/test_filesystem.te
 create mode 100644 tests/filesystem/.gitignore
 create mode 100644 tests/filesystem/Makefile
 create mode 100644 tests/filesystem/check_file_context.c
 create mode 100644 tests/filesystem/check_mount_context.c
 create mode 100644 tests/filesystem/create_file.c
 create mode 100644 tests/filesystem/create_file_change_context.c
 create mode 100644 tests/filesystem/fanotify_fs.c
 create mode 100644 tests/filesystem/fs_relabel.c
 create mode 100644 tests/filesystem/grim_reaper.c
 create mode 100644 tests/filesystem/mount.c
 create mode 100644 tests/filesystem/quotas_test.c
 create mode 100644 tests/filesystem/statfs_test.c
 create mode 100755 tests/filesystem/test
 create mode 100644 tests/filesystem/umount.c

diff --git a/defconfig b/defconfig
index 3bea332..7cb6a2c 100644
--- a/defconfig
+++ b/defconfig
@@ -88,3 +88,9 @@ CONFIG_TUN=m
 CONFIG_HAVE_PERF_EVENTS=y
 CONFIG_PERF_EVENTS=y
 CONFIG_TRACEPOINTS=y
+
+# Test filesystem permissions.
+# This is not required for SELinux operation itself.
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_LOOP_MIN_COUNT=0
+CONFIG_QFMT_V2=y
diff --git a/policy/Makefile b/policy/Makefile
index 6f1db03..30896d8 100644
--- a/policy/Makefile
+++ b/policy/Makefile
@@ -114,6 +114,10 @@ TARGETS += test_lockdown.te
 export M4PARAM += -Dlockdown_defined
 endif
 
+ifeq ($(shell grep -q filesystem $(POLDEV)/include/support/all_perms.spt && echo true),true)
+TARGETS += test_filesystem.te
+endif
+
 ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
 TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te test_ibpkey.te, $(TARGETS))
 endif
diff --git a/policy/test_filesystem.te b/policy/test_filesystem.te
new file mode 100644
index 0000000..2eee1fc
--- /dev/null
+++ b/policy/test_filesystem.te
@@ -0,0 +1,324 @@
+#
+######### Test filesystem permissions policy module ##########
+#
+attribute filesystemdomain;
+
+#################### Create a test file context ######################
+type test_filesystem_filecon_t;
+unconfined_runs_test(test_filesystem_filecon_t)
+
+################# Test all functions ##########################
+type test_filesystem_t;
+domain_type(test_filesystem_t)
+unconfined_runs_test(test_filesystem_t)
+typeattribute test_filesystem_t testdomain;
+typeattribute test_filesystem_t filesystemdomain;
+
+allow test_filesystem_t self:capability { sys_admin };
+allow test_filesystem_t self:filesystem { mount remount quotamod relabelfrom relabelto unmount quotaget };
+allow test_filesystem_t self:dir { mounton add_name write };
+allow test_filesystem_t test_file_t:dir { mounton write remove_name rmdir };
+# Create test file
+allow test_filesystem_t self:dir { add_name write };
+allow test_filesystem_t self:file { create relabelfrom relabelto };
+
+fs_mount_all_fs(test_filesystem_t)
+fs_remount_all_fs(test_filesystem_t)
+fs_unmount_all_fs(test_filesystem_t)
+fs_relabelfrom_all_fs(test_filesystem_t)
+fs_get_xattr_fs_quotas(test_filesystem_t)
+files_search_all(test_filesystem_t)
+# Required for mount opts "rootcontext=system_u:object_r:test_filesystem_t:s0";
+fs_associate(test_filesystem_t)
+fs_getattr_xattr_fs(test_filesystem_t)
+
+# For running quotacheck(8)
+files_type(test_filesystem_t)
+# Update quotas
+fs_set_all_quotas(test_filesystem_t)
+allow test_filesystem_t self:file { quotaon };
+# Create test file and change context:
+fs_associate(test_filesystem_filecon_t)
+allow test_filesystem_t test_filesystem_filecon_t:file { open read getattr relabelto write };
+dontaudit test_filesystem_t kernel_t:process { setsched };
+
+#################### Deny filesystem { getattr } ######################
+type test_filesystem_no_getattr_t;
+domain_type(test_filesystem_no_getattr_t)
+unconfined_runs_test(test_filesystem_no_getattr_t)
+typeattribute test_filesystem_no_getattr_t testdomain;
+typeattribute test_filesystem_no_getattr_t filesystemdomain;
+
+allow test_filesystem_no_getattr_t self:capability { sys_admin };
+fs_mount_all_fs(test_filesystem_no_getattr_t)
+fs_unmount_all_fs(test_filesystem_no_getattr_t)
+fs_relabelfrom_all_fs(test_filesystem_no_getattr_t)
+fs_associate(test_filesystem_no_getattr_t)
+allow test_filesystem_no_getattr_t self:dir { mounton };
+allow test_filesystem_no_getattr_t test_file_t:dir { mounton write remove_name rmdir };
+dontaudit test_filesystem_no_getattr_t kernel_t:process { setsched };
+
+#################### Deny filesystem { remount } ######################
+type test_filesystem_no_remount_t;
+domain_type(test_filesystem_no_remount_t)
+unconfined_runs_test(test_filesystem_no_remount_t)
+typeattribute test_filesystem_no_remount_t testdomain;
+typeattribute test_filesystem_no_remount_t filesystemdomain;
+
+allow test_filesystem_no_remount_t self:capability { sys_admin };
+fs_mount_all_fs(test_filesystem_no_remount_t)
+fs_unmount_all_fs(test_filesystem_no_remount_t)
+fs_relabelfrom_all_fs(test_filesystem_no_remount_t)
+fs_associate(test_filesystem_no_remount_t)
+allow test_filesystem_no_remount_t self:dir { mounton };
+allow test_filesystem_no_remount_t test_file_t:dir { mounton write remove_name rmdir };
+dontaudit test_filesystem_no_remount_t kernel_t:process { setsched };
+
+#################### Deny filesystem { mount } ######################
+type test_filesystem_no_mount_t;
+domain_type(test_filesystem_no_mount_t)
+unconfined_runs_test(test_filesystem_no_mount_t)
+typeattribute test_filesystem_no_mount_t testdomain;
+typeattribute test_filesystem_no_mount_t filesystemdomain;
+
+allow test_filesystem_no_mount_t self:capability { sys_admin };
+fs_relabelfrom_all_fs(test_filesystem_no_mount_t)
+fs_associate(test_filesystem_no_mount_t)
+allow test_filesystem_no_mount_t self:dir { mounton };
+allow test_filesystem_no_mount_t test_file_t:dir { mounton write remove_name rmdir };
+dontaudit test_filesystem_no_mount_t kernel_t:process { setsched };
+
+#################### Deny filesystem { unmount } ######################
+type test_filesystem_no_unmount_t;
+domain_type(test_filesystem_no_unmount_t)
+unconfined_runs_test(test_filesystem_no_unmount_t)
+typeattribute test_filesystem_no_unmount_t testdomain;
+typeattribute test_filesystem_no_unmount_t filesystemdomain;
+
+allow test_filesystem_no_unmount_t self:capability { sys_admin };
+fs_mount_all_fs(test_filesystem_no_unmount_t)
+fs_relabelfrom_all_fs(test_filesystem_no_unmount_t)
+fs_associate(test_filesystem_no_unmount_t)
+allow test_filesystem_no_unmount_t self:dir { mounton };
+allow test_filesystem_no_unmount_t test_file_t:dir { mounton write remove_name rmdir };
+dontaudit test_filesystem_no_unmount_t kernel_t:process { setsched };
+
+#################### Deny filesystem { relabelfrom } ######################
+type test_filesystem_no_relabelfrom_t;
+domain_type(test_filesystem_no_relabelfrom_t)
+unconfined_runs_test(test_filesystem_no_relabelfrom_t)
+typeattribute test_filesystem_no_relabelfrom_t testdomain;
+typeattribute test_filesystem_no_relabelfrom_t filesystemdomain;
+
+allow test_filesystem_no_relabelfrom_t self:capability { sys_admin };
+fs_associate(test_filesystem_no_relabelfrom_t)
+allow test_filesystem_no_relabelfrom_t self:dir { mounton };
+allow test_filesystem_no_relabelfrom_t test_file_t:dir { mounton write remove_name rmdir };
+dontaudit test_filesystem_no_relabelfrom_t kernel_t:process { setsched };
+
+#################### Deny filesystem { relabelto } ######################
+type test_filesystem_no_relabelto_t;
+domain_type(test_filesystem_no_relabelto_t)
+unconfined_runs_test(test_filesystem_no_relabelto_t)
+typeattribute test_filesystem_no_relabelto_t testdomain;
+typeattribute test_filesystem_no_relabelto_t filesystemdomain;
+
+allow test_filesystem_no_relabelto_t self:capability { sys_admin };
+fs_mount_all_fs(test_filesystem_no_relabelto_t)
+fs_relabelfrom_all_fs(test_filesystem_no_relabelto_t)
+fs_associate(test_filesystem_no_relabelto_t)
+allow test_filesystem_no_relabelto_t self:dir { mounton };
+allow test_filesystem_no_relabelto_t test_file_t:dir { mounton write remove_name rmdir };
+dontaudit test_filesystem_no_relabelto_t kernel_t:process { setsched };
+
+#################### Deny filesystem { associate } ######################
+type test_filesystem_no_associate_t;
+type test_filesystem_no_associate1_t;
+domain_type(test_filesystem_no_associate_t)
+unconfined_runs_test(test_filesystem_no_associate_t)
+typeattribute test_filesystem_no_associate_t testdomain;
+typeattribute test_filesystem_no_associate_t filesystemdomain;
+
+allow test_filesystem_no_associate_t self:capability { sys_admin };
+allow test_filesystem_no_associate_t self:filesystem { relabelto mount relabelfrom };
+fs_mount_all_fs(test_filesystem_no_associate_t)
+fs_relabelfrom_all_fs(test_filesystem_no_associate_t)
+allow test_filesystem_no_associate_t self:dir { mounton };
+allow test_filesystem_no_associate_t test_file_t:dir { mounton write remove_name rmdir };
+dontaudit test_filesystem_no_associate_t kernel_t:process { setsched };
+
+########## Deny filesystem { associate } for create file ################
+type test_filesystem_no_associate_file_t;
+domain_type(test_filesystem_no_associate_file_t)
+unconfined_runs_test(test_filesystem_no_associate_file_t)
+typeattribute test_filesystem_no_associate_file_t testdomain;
+typeattribute test_filesystem_no_associate_file_t filesystemdomain;
+
+allow test_filesystem_no_associate_file_t self:capability { sys_admin };
+allow test_filesystem_no_associate_file_t self:filesystem { mount relabelfrom relabelto unmount associate };
+allow test_filesystem_no_associate_file_t self:dir { mounton add_name write };
+allow test_filesystem_no_associate_file_t test_file_t:dir { mounton write remove_name rmdir };
+
+fs_mount_all_fs(test_filesystem_no_associate_file_t)
+fs_unmount_all_fs(test_filesystem_no_associate_file_t)
+fs_relabelfrom_all_fs(test_filesystem_no_associate_file_t)
+fs_associate(test_filesystem_no_associate_file_t)
+fs_getattr_xattr_fs(test_filesystem_no_associate_file_t)
+dontaudit test_filesystem_no_associate_file_t kernel_t:process { setsched };
+
+# Create test file
+allow test_filesystem_no_associate_file_t self:file { create relabelfrom relabelto };
+############ hooks.c may_create() FILESYSTEM__ASSOCIATE #############
+# FOR: neverallow unlabeled_t test_filesystem_no_associate_file_t:filesystem { associate };
+allow test_filesystem_no_associate_file_t unconfined_t:file { open read write };
+allow test_filesystem_no_associate_file_t unlabeled_t:dir { add_name search write };
+allow test_filesystem_no_associate_file_t unlabeled_t:file { create open relabelfrom write };
+############ hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE ##########
+# FOR: neverallow unconfined_t test_filesystem_no_associate_file_t:filesystem { associate };
+dontaudit unconfined_t test_filesystem_filecon_t:file { getattr read };
+allow test_filesystem_no_associate_file_t unconfined_t:dir { add_name write };
+allow test_filesystem_no_associate_file_t unconfined_t:file { create relabelfrom relabelto };
+
+#################### Deny filesystem { quotamod } ######################
+type test_filesystem_no_quotamod_t;
+domain_type(test_filesystem_no_quotamod_t)
+unconfined_runs_test(test_filesystem_no_quotamod_t)
+typeattribute test_filesystem_no_quotamod_t testdomain;
+typeattribute test_filesystem_no_quotamod_t filesystemdomain;
+
+allow test_filesystem_no_quotamod_t self:capability { sys_admin };
+allow test_filesystem_no_quotamod_t self:filesystem { quotaget relabelto mount unmount};
+fs_mount_all_fs(test_filesystem_no_quotamod_t)
+fs_relabelfrom_all_fs(test_filesystem_no_quotamod_t)
+fs_associate(test_filesystem_no_quotamod_t)
+# Required as $private_path to quota files
+files_search_all(test_filesystem_no_quotamod_t)
+allow test_filesystem_no_quotamod_t self:dir { mounton };
+allow test_filesystem_no_quotamod_t test_file_t:dir { mounton write remove_name rmdir };
+dontaudit test_filesystem_no_quotamod_t kernel_t:process { setsched };
+
+#################### Deny filesystem { quotaget } ######################
+type test_filesystem_no_quotaget_t;
+domain_type(test_filesystem_no_quotaget_t)
+unconfined_runs_test(test_filesystem_no_quotaget_t)
+typeattribute test_filesystem_no_quotaget_t testdomain;
+typeattribute test_filesystem_no_quotaget_t filesystemdomain;
+
+allow test_filesystem_no_quotaget_t self:capability { sys_admin };
+allow test_filesystem_no_quotaget_t self:filesystem { quotamod relabelto mount unmount relabelfrom };
+allow test_filesystem_no_quotaget_t self:dir { mounton };
+allow test_filesystem_no_quotaget_t test_file_t:dir { mounton write remove_name rmdir };
+allow test_filesystem_no_quotaget_t self:file { quotaon };
+fs_mount_all_fs(test_filesystem_no_quotaget_t)
+fs_relabelfrom_all_fs(test_filesystem_no_quotaget_t)
+fs_associate(test_filesystem_no_quotaget_t)
+# Required as $private_path to quota files
+files_search_all(test_filesystem_no_quotaget_t)
+# For running quotacheck(8)
+files_type(test_filesystem_no_quotaget_t)
+dontaudit test_filesystem_no_quotaget_t kernel_t:process { setsched };
+
+#################### Deny filesystem { watch } ######################
+type test_filesystem_no_watch_t;
+domain_type(test_filesystem_no_watch_t)
+unconfined_runs_test(test_filesystem_no_watch_t)
+typeattribute test_filesystem_no_watch_t testdomain;
+typeattribute test_filesystem_no_watch_t filesystemdomain;
+
+allow test_filesystem_no_watch_t self:capability { sys_admin };
+allow test_filesystem_no_watch_t self:filesystem { associate relabelto mount unmount relabelfrom };
+allow test_filesystem_no_watch_t self:dir { mounton };
+allow test_filesystem_no_watch_t test_file_t:dir { mounton write remove_name rmdir };
+fs_mount_all_fs(test_filesystem_no_watch_t)
+fs_relabelfrom_all_fs(test_filesystem_no_watch_t)
+fs_associate(test_filesystem_no_watch_t)
+dontaudit test_filesystem_no_watch_t kernel_t:process { setsched };
+
+################# Test process { setfscreate } #############
+type test_setfscreatecon_t;
+domain_type(test_setfscreatecon_t)
+unconfined_runs_test(test_setfscreatecon_t)
+typeattribute test_setfscreatecon_t testdomain;
+typeattribute test_setfscreatecon_t filesystemdomain;
+
+allow test_setfscreatecon_t self:capability { sys_admin };
+allow test_setfscreatecon_t self:process { setfscreate };
+
+# Set new context on fs:
+type test_setfscreatecon_newcon_t;
+domain_type(test_setfscreatecon_newcon_t)
+typeattribute test_setfscreatecon_newcon_t testdomain;
+
+################# deny process { setfscreate } #############
+type test_no_setfscreatecon_t;
+domain_type(test_no_setfscreatecon_t)
+unconfined_runs_test(test_no_setfscreatecon_t)
+typeattribute test_no_setfscreatecon_t testdomain;
+typeattribute test_no_setfscreatecon_t filesystemdomain;
+
+allow test_no_setfscreatecon_t self:capability { sys_admin };
+# neverallow test_no_setfscreatecon_t self:process { setfscreate };
+
+################# Test fscontext= ##########################
+type test_filesystem_fscontext_t;
+domain_type(test_filesystem_fscontext_t)
+unconfined_runs_test(test_filesystem_fscontext_t)
+typeattribute test_filesystem_fscontext_t testdomain;
+typeattribute test_filesystem_fscontext_t filesystemdomain;
+
+allow test_filesystem_fscontext_t self:capability { sys_admin };
+allow test_filesystem_fscontext_t self:filesystem { associate mount relabelfrom relabelto unmount };
+allow test_filesystem_fscontext_t self:dir { mounton add_name write };
+allow test_filesystem_fscontext_t test_file_t:dir { mounton write remove_name rmdir };
+# Create test file
+allow test_filesystem_fscontext_t self:dir { add_name write };
+allow test_filesystem_fscontext_t self:file { create relabelfrom relabelto };
+allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { relabelto };
+allow test_filesystem_filecon_t test_filesystem_fscontext_t:filesystem { associate };
+allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { open getattr read write };
+
+fs_mount_all_fs(test_filesystem_fscontext_t)
+fs_unmount_all_fs(test_filesystem_fscontext_t)
+fs_relabelfrom_all_fs(test_filesystem_fscontext_t)
+files_search_all(test_filesystem_fscontext_t)
+
+########### Test context=, rootcontext= and defcontext #################
+type test_filesystem_context_t;
+domain_type(test_filesystem_context_t)
+unconfined_runs_test(test_filesystem_context_t)
+typeattribute test_filesystem_context_t testdomain;
+typeattribute test_filesystem_context_t filesystemdomain;
+
+allow test_filesystem_context_t self:capability { sys_admin };
+allow test_filesystem_context_t self:filesystem { associate mount relabelfrom relabelto unmount };
+allow test_filesystem_context_t self:dir { mounton add_name write };
+allow test_filesystem_context_t test_file_t:dir { mounton write remove_name rmdir };
+# Create test file
+allow test_filesystem_context_t self:dir { add_name write };
+allow test_filesystem_context_t self:file { create relabelfrom relabelto };
+allow test_filesystem_context_t test_filesystem_filecon_t:file { open getattr read write relabelto };
+allow test_filesystem_filecon_t test_filesystem_context_t:filesystem { associate };
+
+fs_mount_all_fs(test_filesystem_context_t)
+fs_unmount_all_fs(test_filesystem_context_t)
+fs_relabelfrom_all_fs(test_filesystem_context_t)
+files_search_all(test_filesystem_context_t)
+fs_associate(test_filesystem_context_t)
+allow test_filesystem_context_t test_file_t:dir { add_name };
+dontaudit test_filesystem_context_t kernel_t:process { setsched };
+
+# For testing rootcontext= Set mountpoint to unlabeled first
+allow test_filesystem_context_t test_file_t:dir { relabelfrom };
+allow test_filesystem_context_t unlabeled_t:dir { mounton relabelto };
+
+# For testing defcontext=
+allow test_filesystem_context_t test_filesystem_filecon_t:dir { search };
+allow test_filesystem_fscontext_t test_filesystem_context_t:dir { add_name search write };
+allow test_filesystem_fscontext_t test_filesystem_context_t:file { create getattr open write };
+dontaudit unconfined_t test_filesystem_filecon_t:dir { read search };
+
+#
+########### Allow these domains to be entered from sysadm domain ############
+#
+miscfiles_domain_entry_test_files(filesystemdomain)
+userdom_sysadm_entry_spec_domtrans_to(filesystemdomain)
diff --git a/tests/Makefile b/tests/Makefile
index e19ea2f..a1478f1 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -91,6 +91,13 @@ ifeq ($(shell grep -q lockdown $(POLDEV)/include/support/all_perms.spt && echo t
 SUBDIRS += lockdown
 endif
 
+ifeq ($(shell grep -q filesystem $(POLDEV)/include/support/all_perms.spt && echo true),true)
+SUBDIRS += filesystem
+ifeq ($(shell grep -q all_filesystem_perms.*watch $(POLDEV)/include/support/all_perms.spt && echo true),true)
+export CFLAGS += -DHAVE_FS_WATCH_PERM
+endif
+endif
+
 ifeq ($(DISTRO),RHEL4)
     SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp_nosuid overlay unix_socket, $(SUBDIRS))
 endif
diff --git a/tests/filesystem/.gitignore b/tests/filesystem/.gitignore
new file mode 100644
index 0000000..5ac18d0
--- /dev/null
+++ b/tests/filesystem/.gitignore
@@ -0,0 +1,11 @@
+mount
+umount
+quotas_test
+statfs_test
+fanotify_fs
+create_file_change_context
+fs_relabel
+check_file_context
+check_mount_context
+create_file
+grim_reaper
diff --git a/tests/filesystem/Makefile b/tests/filesystem/Makefile
new file mode 100644
index 0000000..d2fad63
--- /dev/null
+++ b/tests/filesystem/Makefile
@@ -0,0 +1,16 @@
+# Required for local building
+#export CFLAGS += -DHAVE_FS_WATCH_PERM
+
+TARGETS = mount umount quotas_test statfs_test create_file_change_context \
+fs_relabel check_file_context grim_reaper check_mount_context create_file
+
+LDLIBS += -lselinux
+
+ifneq (,$(findstring -DHAVE_FS_WATCH_PERM,$(CFLAGS)))
+	TARGETS += fanotify_fs
+endif
+
+all: $(TARGETS)
+
+clean:
+	rm -f $(TARGETS)
diff --git a/tests/filesystem/check_file_context.c b/tests/filesystem/check_file_context.c
new file mode 100644
index 0000000..1380f16
--- /dev/null
+++ b/tests/filesystem/check_file_context.c
@@ -0,0 +1,75 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <linux/unistd.h>
+#include <selinux/selinux.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] -f -e -n\n"
+		"Where:\n\t"
+		"-f  File to check its context\n\t"
+		"-e  Expected context\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+	int opt, result, fd;
+	char *context = NULL, *expected = NULL, *file = NULL;
+	bool verbose = false;
+
+	while ((opt = getopt(argc, argv, "f:e:v")) != -1) {
+		switch (opt) {
+		case 'f':
+			file = optarg;
+			break;
+		case 'e':
+			expected = optarg;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!file || !expected)
+		print_usage(argv[0]);
+
+	fd = open(file, O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "open(2) Failed: %s\n", strerror(errno));
+		return -1;
+	}
+
+	result = fgetfilecon(fd, &context);
+	if (result < 0) {
+		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
+			strerror(errno));
+		result = -1;
+		goto err;
+	}
+	result = 0;
+
+	if (strcmp(expected, context)) {
+		fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n",
+			expected, context);
+		result = -1;
+	} else {
+		if (verbose)
+			printf("Pass - File contexts match: %s\n", context);
+	}
+err:
+	free(context);
+	close(fd);
+
+	return result;
+}
diff --git a/tests/filesystem/check_mount_context.c b/tests/filesystem/check_mount_context.c
new file mode 100644
index 0000000..dbe0fb8
--- /dev/null
+++ b/tests/filesystem/check_mount_context.c
@@ -0,0 +1,109 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <linux/unistd.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] -m [-e] -r\n"
+		"Where:\n\t"
+		"-m  Mountpoint\n\t"
+		"-e  Expected MP context\n\t"
+		"-r  Reset MP context to 'unlabeled_t'\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+	int opt, result, save_err;
+	char *context = NULL, *expected = NULL, *mount = NULL, *newcon = NULL;
+	bool verbose = false, reset = false;
+	const char *type = "unlabeled_t";
+	context_t con_t;
+
+	while ((opt = getopt(argc, argv, "m:e:rv")) != -1) {
+		switch (opt) {
+		case 'm':
+			mount = optarg;
+			break;
+		case 'e':
+			expected = optarg;
+			break;
+		case 'r':
+			reset = true;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!mount)
+		print_usage(argv[0]);
+
+	result = getfilecon(mount, &context);
+	if (result < 0) {
+		fprintf(stderr, "getfilecon(3) Failed: %s\n", strerror(errno));
+		result = -1;
+		goto err;
+	}
+	if (verbose)
+		printf("Current MP context: %s\n", context);
+
+	result = 0;
+
+	if (reset) {
+		/* Set context to unlabeled_t */
+		con_t = context_new(context);
+		if (!con_t) {
+			fprintf(stderr, "Unable to create context structure\n");
+			exit(-1);
+		}
+
+		if (context_type_set(con_t, type)) {
+			fprintf(stderr, "Unable to set new type\n");
+			exit(-1);
+		}
+
+		newcon = context_str(con_t);
+		if (!newcon) {
+			fprintf(stderr, "Unable to obtain new context string\n");
+			exit(-1);
+		}
+
+		result = setfilecon(mount, newcon);
+		save_err = errno;
+		if (result < 0) {
+			fprintf(stderr, "setfilecon(3) Failed: %s\n",
+				strerror(errno));
+			result = save_err;
+			goto err;
+		}
+		if (verbose)
+			printf("Set new MP context: %s\n", newcon);
+	} else {
+		if (strcmp(expected, context)) {
+			fprintf(stderr, "Mount context error, expected:\n\t%s\ngot:\n\t%s\n",
+				expected, context);
+			result = -1;
+		} else {
+			if (verbose)
+				printf("Pass - Mountpoint contexts match: %s\n",
+				       context);
+		}
+	}
+
+err:
+	free(context);
+	return result;
+}
diff --git a/tests/filesystem/create_file.c b/tests/filesystem/create_file.c
new file mode 100644
index 0000000..3d73067
--- /dev/null
+++ b/tests/filesystem/create_file.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <sys/types.h>
+#include <linux/unistd.h>
+#include <selinux/selinux.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] -f\n"
+		"Where:\n\t"
+		"-f  File to create\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+	int opt, result, fd, save_err;
+	char *context, *file = NULL;
+	bool verbose = false;
+
+	while ((opt = getopt(argc, argv, "f:v")) != -1) {
+		switch (opt) {
+		case 'f':
+			file = optarg;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!file)
+		print_usage(argv[0]);
+
+	if (verbose) {
+		result = getcon(&context);
+		if (result < 0) {
+			fprintf(stderr, "Failed to obtain process context\n");
+			exit(-1);
+		}
+		printf("Process context:\n\t%s\n", context);
+		free(context);
+	}
+
+	fd = creat(file, O_RDWR);
+	save_err = errno;
+	if (fd < 0) {
+		fprintf(stderr, "creat(2) Failed: %s\n", strerror(errno));
+		return save_err;
+	}
+
+	context = NULL;
+	result = fgetfilecon(fd, &context);
+	if (result < 0) {
+		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
+			strerror(errno));
+		result = -1;
+		goto err;
+	}
+	result = 0;
+
+	if (verbose)
+		printf("File context is: %s\n", context);
+
+err:
+	free(context);
+	close(fd);
+
+	return result;
+}
diff --git a/tests/filesystem/create_file_change_context.c b/tests/filesystem/create_file_change_context.c
new file mode 100644
index 0000000..2a3b995
--- /dev/null
+++ b/tests/filesystem/create_file_change_context.c
@@ -0,0 +1,143 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <linux/unistd.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] -t -f\n"
+		"Where:\n\t"
+		"-t  Type for context of created file\n\t"
+		"-f  File to create\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+	int opt, result, fd, save_err;
+	char *context, *newfcon, *orgfcon, *type = NULL, *file = NULL;
+	bool verbose = false;
+	context_t con_t;
+
+	while ((opt = getopt(argc, argv, "t:f:v")) != -1) {
+		switch (opt) {
+		case 't':
+			type = optarg;
+			break;
+		case 'f':
+			file = optarg;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!type || !file)
+		print_usage(argv[0]);
+
+	result = getcon(&context);
+	if (result < 0) {
+		fprintf(stderr, "Failed to obtain process context\n");
+		exit(-1);
+	}
+
+	/* Build new file context */
+	con_t = context_new(context);
+	if (!con_t) {
+		fprintf(stderr, "Unable to create context structure\n");
+		exit(-1);
+	}
+
+	if (context_type_set(con_t, type)) {
+		fprintf(stderr, "Unable to set new type\n");
+		exit(-1);
+	}
+
+	newfcon = context_str(con_t);
+	if (!newfcon) {
+		fprintf(stderr, "Unable to obtain new context string\n");
+		exit(-1);
+	}
+
+	if (verbose) {
+		printf("Process context:\n\t%s\n", context);
+		printf("is creating test file:\n\t%s\n", file);
+		printf("and changing its context to:\n\t%s\n", newfcon);
+	}
+
+	free(context);
+	context = NULL;
+
+	/* hooks.c may_create() FILESYSTEM__ASSOCIATE */
+	fd = creat(file, O_RDWR);
+	save_err = errno;
+	if (fd < 0) {
+		fprintf(stderr, "creat(2) Failed: %s\n", strerror(errno));
+		result = save_err;
+		goto err;
+	}
+
+	result = fgetfilecon(fd, &orgfcon);
+	if (result < 0) {
+		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
+			strerror(errno));
+		result = -1;
+		goto err;
+	}
+
+	if (verbose)
+		printf("Current test file context is: %s\n", orgfcon);
+
+	free(orgfcon);
+
+	/* hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE */
+	result = fsetfilecon(fd, newfcon);
+	save_err = errno;
+	if (result < 0) {
+		fprintf(stderr, "fsetfilecon(3) Failed: %s\n",
+			strerror(errno));
+		result = save_err;
+		goto err;
+	}
+
+	fd = open(file, O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "open(2) Failed: %s\n", strerror(errno));
+		result = -1;
+	}
+
+	result = fgetfilecon(fd, &context);
+	if (result < 0) {
+		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
+			strerror(errno));
+		result = -1;
+		goto err;
+	}
+
+	if (verbose)
+		printf("New test file context is: %s\n", context);
+
+	result = 0;
+	if (strcmp(newfcon, context)) {
+		fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n",
+			newfcon, context);
+		result = -1;
+	}
+err:
+	free(context);
+	free(newfcon);
+	close(fd);
+
+	return result;
+}
diff --git a/tests/filesystem/fanotify_fs.c b/tests/filesystem/fanotify_fs.c
new file mode 100644
index 0000000..1f8f165
--- /dev/null
+++ b/tests/filesystem/fanotify_fs.c
@@ -0,0 +1,79 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/fanotify.h>
+#include <selinux/selinux.h>
+
+#ifndef FAN_MARK_FILESYSTEM
+#define FAN_MARK_FILESYSTEM	0x00000100
+#endif
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] -t\n"
+		"Where:\n\t"
+		"-t  Target path\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	int mask = FAN_OPEN, flags = FAN_MARK_ADD | FAN_MARK_FILESYSTEM;
+	int fd, result, opt, save_err;
+	char *context, *tgt = NULL;
+	bool verbose = false;
+
+	while ((opt = getopt(argc, argv, "t:v")) != -1) {
+		switch (opt) {
+		case 't':
+			tgt = optarg;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!tgt)
+		print_usage(argv[0]);
+
+	if (verbose) {
+		result = getcon(&context);
+		if (result < 0) {
+			fprintf(stderr, "Failed to obtain process context\n");
+			exit(-1);
+		}
+		printf("Process context:\n\t%s\n", context);
+		free(context);
+	}
+
+	fd = fanotify_init(FAN_CLASS_CONTENT, O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "fanotify_init(2) Failed: %s\n",
+			strerror(errno));
+		exit(-1);
+	}
+
+	result = fanotify_mark(fd, flags, mask, AT_FDCWD, tgt);
+	save_err = errno;
+	if (result < 0) {
+		fprintf(stderr, "fanotify_mark(2) Failed: %s\n",
+			strerror(errno));
+		close(fd);
+		return save_err;
+	}
+
+	if (verbose)
+		printf("Set fanotify_mark(2) on filesystem: %s\n", tgt);
+
+	close(fd);
+	return 0;
+}
diff --git a/tests/filesystem/fs_relabel.c b/tests/filesystem/fs_relabel.c
new file mode 100644
index 0000000..25b1781
--- /dev/null
+++ b/tests/filesystem/fs_relabel.c
@@ -0,0 +1,72 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <linux/unistd.h>
+#include <selinux/selinux.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] -n\n"
+		"Where:\n\t"
+		"-n  New fs context\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+	int opt, result, save_err;
+	char *context, *fscreate_con, *newcon = NULL;
+	bool verbose = false;
+
+	while ((opt = getopt(argc, argv, "n:v")) != -1) {
+		switch (opt) {
+		case 'n':
+			newcon = optarg;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!newcon)
+		print_usage(argv[0]);
+
+	if (verbose) {
+		result = getcon(&context);
+		if (result < 0) {
+			fprintf(stderr, "Failed to obtain process context\n");
+			exit(-1);
+		}
+		printf("Process context:\n\t%s\n", context);
+		free(context);
+	}
+
+	result = setfscreatecon(newcon);
+	save_err = errno;
+	if (result < 0) {
+		fprintf(stderr, "Failed setfscreatecon(3): %s\n",
+			strerror(errno));
+		return save_err;
+	}
+
+	result = getfscreatecon(&fscreate_con);
+	if (result < 0) {
+		fprintf(stderr, "Failed getfscreatecon(3): %s\n",
+			strerror(errno));
+		exit(-1);
+	}
+	if (verbose)
+		printf("New fscreate context: %s\n", fscreate_con);
+
+	free(fscreate_con);
+	return 0;
+}
diff --git a/tests/filesystem/grim_reaper.c b/tests/filesystem/grim_reaper.c
new file mode 100644
index 0000000..0105ab6
--- /dev/null
+++ b/tests/filesystem/grim_reaper.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/mount.h>
+#include <selinux/selinux.h>
+
+#define WAIT_COUNT 60
+#define USLEEP_TIME 10000
+
+/* Remove any mounts associated with the loop device in argv[1] */
+int main(int argc, char *argv[])
+{
+	FILE *fp;
+	size_t len;
+	ssize_t num;
+	int index = 0, i, result = 0;
+	char *mount_info[2];
+	char *buf = NULL, *item;
+
+	if (!argv[1])
+		return -1;
+
+	fp = fopen("/proc/mounts", "re");
+	if (!fp) {
+		fprintf(stderr, "Failed to open /proc/mounts: %s\n",
+			strerror(errno));
+		return -1;
+	}
+
+	while ((num = getline(&buf, &len, fp)) != -1) {
+		index = 0;
+		item = strtok(buf, " ");
+		while (item != NULL) {
+			mount_info[index] = item;
+			index++;
+			if (index == 2)
+				break;
+			item = strtok(NULL, " ");
+		}
+
+		if (strcmp(mount_info[0], argv[1]) == 0) {
+			for (i = 0; i < WAIT_COUNT; i++) {
+				result = umount(mount_info[1]);
+				if (!result)
+					break;
+
+				if (errno != EBUSY) {
+					fprintf(stderr, "Failed umount(2): %s\n",
+						strerror(errno));
+					break;
+				}
+				usleep(USLEEP_TIME);
+			}
+		}
+	}
+
+	free(buf);
+	fclose(fp);
+	return result;
+}
diff --git a/tests/filesystem/mount.c b/tests/filesystem/mount.c
new file mode 100644
index 0000000..034f0ec
--- /dev/null
+++ b/tests/filesystem/mount.c
@@ -0,0 +1,130 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/mount.h>
+#include <selinux/selinux.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-s src] -t tgt [-f fs_type] [-o options] [-bmprv]\n"
+		"Where:\n\t"
+		"-s  Source path\n\t"
+		"-t  Target path\n\t"
+		"-f  Filesystem type\n\t"
+		"-o  Options list (comma separated list)\n\t"
+		"Zero or one of the following flags:\n\t"
+		"\t-b  MS_BIND\n\t"
+		"\t-m  MS_MOVE\n\t"
+		"\t-p  MS_PRIVATE\n\t"
+		"\t-r  MS_REMOUNT\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+static int ck_mount(char *mntpoint)
+{
+	int result = 0;
+	FILE *fp;
+	size_t len;
+	ssize_t num;
+	char *buf = NULL;
+
+	fp = fopen("/proc/mounts", "re");
+	if (fp == NULL) {
+		fprintf(stderr, "Failed to open /proc/mounts: %s\n",
+			strerror(errno));
+		return -1;
+	}
+
+	while ((num = getline(&buf, &len, fp)) != -1) {
+		if (strstr(buf, mntpoint) != NULL) {
+			result = 1;
+			break;
+		}
+	}
+
+	free(buf);
+	fclose(fp);
+	return result;
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, result, save_err, flags = 0;
+	char *context, *src = NULL, *tgt = NULL, *fs_type = NULL, *opts = NULL;
+	bool verbose = false;
+
+	while ((opt = getopt(argc, argv, "s:t:f:o:pbmrv")) != -1) {
+		switch (opt) {
+		case 's':
+			src = optarg;
+			break;
+		case 't':
+			tgt = optarg;
+			break;
+		case 'f':
+			fs_type = optarg;
+			break;
+		case 'o':
+			opts = optarg;
+			break;
+		case 'b':
+			flags = MS_BIND;
+			break;
+		case 'p':
+			flags = MS_PRIVATE;
+			break;
+		case 'm':
+			flags = MS_MOVE;
+			break;
+		case 'r':
+			flags = MS_REMOUNT;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!tgt)
+		print_usage(argv[0]);
+
+	if (verbose) {
+		result = getcon(&context);
+		if (result < 0) {
+			fprintf(stderr, "Failed to obtain process context\n");
+			return -1;
+		}
+		printf("Process context:\n\t%s\n", context);
+		free(context);
+	}
+
+	if (verbose)
+		printf("Mounting\n\tsrc: %s\n\ttgt: %s\n\tfs_type: %s flags: 0x%x\n\topts: %s\n",
+		       src, tgt, fs_type, flags, opts);
+
+	result = mount(src, tgt, fs_type, flags, opts);
+	save_err = errno;
+	if (result < 0) {
+		fprintf(stderr, "Failed mount(2): %s\n", strerror(errno));
+		return save_err;
+	}
+
+	if (flags == MS_MOVE) {
+		if (!ck_mount(src) && ck_mount(tgt)) {
+			if (verbose)
+				printf("MS_MOVE: Moved mountpoint\n");
+		} else {
+			fprintf(stderr, "MS_MOVE: Move mountpoint failed\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
diff --git a/tests/filesystem/quotas_test.c b/tests/filesystem/quotas_test.c
new file mode 100644
index 0000000..34aaca9
--- /dev/null
+++ b/tests/filesystem/quotas_test.c
@@ -0,0 +1,134 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/quota.h>
+#include <selinux/selinux.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s -s src -t tgt\n"
+		"Where:\n\t"
+		"-s  Source path (e.g. /dev/loop0)\n\t"
+		"-t  Target quota file (Full path with either 'aquota.user'\n\t"
+		"    or 'aquota.group' appended)\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, result, qcmd, save_err, test_id = geteuid();
+	char *context, *src = NULL, *tgt = NULL;
+	bool verbose = false;
+	char fmt_buf[2];
+
+	while ((opt = getopt(argc, argv, "s:t:v")) != -1) {
+		switch (opt) {
+		case 's':
+			src = optarg;
+			break;
+		case 't':
+			tgt = optarg;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!src || !tgt)
+		print_usage(argv[0]);
+
+	if (verbose) {
+		result = getcon(&context);
+		if (result < 0) {
+			fprintf(stderr, "Failed to obtain process context\n");
+			return -1;
+		}
+		printf("Process context:\n\t%s\n", context);
+		free(context);
+	}
+
+	if (strstr(tgt, "aquota.user") != NULL) {
+		qcmd = QCMD(Q_QUOTAON, USRQUOTA);
+		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
+		save_err = errno;
+		if (result < 0) {
+			fprintf(stderr, "quotactl(Q_QUOTAON, USRQUOTA) Failed: %s\n",
+				strerror(errno));
+			return save_err;
+		}
+		if (verbose)
+			printf("User Quota - ON\n");
+
+		qcmd = QCMD(Q_GETFMT, USRQUOTA);
+		result = quotactl(qcmd, src, test_id, fmt_buf);
+		save_err = errno;
+		if (result < 0) {
+			fprintf(stderr, "quotactl(Q_GETFMT, USRQUOTA) Failed: %s\n",
+				strerror(errno));
+			return save_err;
+		}
+		if (verbose)
+			printf("User Format: 0x%x\n", fmt_buf[0]);
+
+		qcmd = QCMD(Q_QUOTAOFF, USRQUOTA);
+		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
+		save_err = errno;
+		if (result < 0) {
+			fprintf(stderr, "quotactl(Q_QUOTAOFF, USRQUOTA) Failed: %s\n",
+				strerror(errno));
+			return save_err;
+		}
+		if (verbose)
+			printf("User Quota - OFF\n");
+
+		return 0;
+
+	} else if (strstr(tgt, "aquota.group") != NULL) {
+		qcmd = QCMD(Q_QUOTAON, GRPQUOTA);
+		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
+		save_err = errno;
+		if (result < 0) {
+			fprintf(stderr, "quotactl(Q_QUOTAON, GRPQUOTA) Failed: %s\n",
+				strerror(errno));
+			return save_err;
+		}
+		if (verbose)
+			printf("Group Quota - ON\n");
+
+		qcmd = QCMD(Q_GETFMT, GRPQUOTA);
+		result = quotactl(qcmd, src, test_id, fmt_buf);
+		save_err = errno;
+		if (result < 0) {
+			fprintf(stderr, "quotactl(Q_GETFMT, GRPQUOTA) Failed: %s\n",
+				strerror(errno));
+			return save_err;
+		}
+		if (verbose)
+			printf("Group Format: 0x%x\n", fmt_buf[0]);
+
+		qcmd = QCMD(Q_QUOTAOFF, GRPQUOTA);
+		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
+		save_err = errno;
+		if (result < 0) {
+			fprintf(stderr, "quotactl(Q_QUOTAOFF, GRPQUOTA) Failed: %s\n",
+				strerror(errno));
+			return save_err;
+		}
+		if (verbose)
+			printf("Group Quota - OFF\n");
+
+		return 0;
+	}
+
+	fprintf(stderr, "Required %s to specify 'aquota.user' or 'aquota.group' file\n",
+		tgt);
+	return -1;
+}
diff --git a/tests/filesystem/statfs_test.c b/tests/filesystem/statfs_test.c
new file mode 100644
index 0000000..5de49b1
--- /dev/null
+++ b/tests/filesystem/statfs_test.c
@@ -0,0 +1,65 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/statfs.h>
+#include <selinux/selinux.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] -t\n"
+		"Where:\n\t"
+		"-t  Target path\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	int opt, result, save_err;
+	char *context, *tgt = NULL;
+	bool verbose = false;
+	struct statfs statfs_t;
+
+	while ((opt = getopt(argc, argv, "t:v")) != -1) {
+		switch (opt) {
+		case 't':
+			tgt = optarg;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!tgt)
+		print_usage(argv[0]);
+
+	if (verbose) {
+		result = getcon(&context);
+		if (result < 0) {
+			fprintf(stderr, "Failed to obtain process context\n");
+			return -1;
+		}
+		printf("Process context:\n\t%s\n", context);
+		free(context);
+	}
+
+	result = statfs(tgt, &statfs_t);
+	save_err = errno;
+	if (result < 0) {
+		fprintf(stderr, "statfs(2) Failed: %s\n", strerror(errno));
+		return save_err;
+	}
+
+	if (verbose)
+		printf("statfs(2) returned magic filesystem: 0x%lx\n",
+		       statfs_t.f_type);
+
+	return 0;
+}
diff --git a/tests/filesystem/test b/tests/filesystem/test
new file mode 100755
index 0000000..00c69e1
--- /dev/null
+++ b/tests/filesystem/test
@@ -0,0 +1,830 @@
+#!/usr/bin/perl
+use Test::More;
+
+BEGIN {
+    $basedir = $0;
+    $basedir =~ s|(.*)/[^/]*|$1|;
+
+    $test_count = 63;
+
+    # Allow info to be shown.
+    $v = $ARGV[0];
+    if ($v) {
+        if ( $v ne "-v" ) {
+            plan skip_all => "Invalid option (use -v)";
+        }
+    }
+    else {
+        $v = " ";
+    }
+
+    # From kernel 5.5 support for fanotify(7) with filesystem { watch }
+    $kvercur = `uname -r`;
+    chomp($kvercur);
+    $kverminstream = "5.5";
+
+    $result = `$basedir/../kvercmp $kvercur $kverminstream`;
+    if ( $result > 0 && -e "$basedir/fanotify_fs" ) {
+        $test_watch = 1;
+        $test_count += 4;
+    }
+
+    plan tests => $test_count;
+}
+
+# mount(2) MS_BIND | MS_PRIVATE requires an absolute path to a private mount
+# point before MS_MOVE
+$cwd = `pwd 2>/dev/null`;
+chomp($cwd);
+$private_path = "$cwd";
+if ( $basedir eq "." ) {
+    $private_path = "$cwd/mntpoint";
+}
+else {
+    $private_path = "$cwd/$basedir/mntpoint";
+}
+
+# Set initial filesystem type
+$fs_type = "ext4";
+
+# For list of devices used
+$device_count = 0;
+
+sub get_loop_dev {
+    print "Finding free /dev/loop entry\n";
+    $dev = `losetup -f 2>/dev/null`;
+    chomp($dev);
+    if ( $dev eq "" ) {
+        print "losetup failed to obtain /dev/loop entry\n";
+        cleanup();
+        exit -1;
+    }
+
+    # Keep list of devices for cleanup later
+    if ( $device_count eq 0 ) {
+        $device_list[$device_count] = $dev;
+        $device_count += 1;
+    }
+    elsif ( $dev ne $device_list[ $device_count - 1 ] ) {
+        $device_list[$device_count] = $dev;
+        $device_count += 1;
+    }
+}
+
+sub attach_dev {
+    print "Attaching $basedir/fstest to $dev\n";
+    $result = system("losetup $dev $basedir/fstest 2>/dev/null");
+    if ( $result != 0 ) {
+        print "Failed to attach $basedir/fstest to $dev\n";
+        cleanup();
+        exit -1;
+    }
+}
+
+sub make_fs {
+    my ($mk_type) = @_;
+
+    get_loop_dev();
+
+    if ( $mk_type eq "tmpfs" ) {
+        return;
+    }
+
+    print "Create $basedir/fstest with dd\n";
+    $result = system(
+        "dd if=/dev/zero of=$basedir/fstest bs=1024 count=10240 2>/dev/null");
+    if ( $result != 0 ) {
+        print "dd failed to create fstest\n";
+        exit -1;
+    }
+
+    attach_dev();
+
+    print "Make $mk_type filesystem on $dev\n";
+    $result = system("mkfs.$mk_type $dev >& /dev/null");
+    if ( $result != 0 ) {
+        system("losetup -d $dev 2>/dev/null");
+        cleanup();
+        print "mkfs.$mk_type failed to create filesystem on $dev\n";
+        exit -1;
+    }
+}
+
+sub mk_mntpoint_1 {
+    system("rm -rf $private_path/mp1 2>/dev/null");
+    system("mkdir -p $private_path/mp1 2>/dev/null");
+}
+
+sub mk_mntpoint_2 {
+    system("rm -rf $private_path/mp2 2>/dev/null");
+    system("mkdir -p $private_path/mp2 2>/dev/null");
+}
+
+sub cleanup {
+    system("rm -rf $basedir/fstest 2>/dev/null");
+    system("rm -rf $basedir/mntpoint 2>/dev/null");
+}
+
+sub cleanup1 {
+    system("losetup -d $dev 2>/dev/null");
+    system("rm -rf $basedir/fstest 2>/dev/null");
+    system("rm -rf $basedir/mntpoint 2>/dev/null");
+}
+
+############### Test setfscreatecon(3) ##########################
+print "Test setfscreatecon(3)\n";
+$result = system
+"runcon -t test_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0";
+ok( $result eq 0 );
+
+$result = system
+"runcon -t test_no_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0 2>&1";
+ok( $result >> 8 eq 13 );
+
+############### Test Basic Mount/Unmount ##########################
+cleanup();
+mk_mntpoint_1();
+make_fs($fs_type);
+$mount_opts1 =
+  "quota,usrquota,grpquota,defcontext=system_u:object_r:test_filesystem_t:s0";
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$mount_opts1\n";
+$result = system(
+"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v"
+);
+ok( $result eq 0 );
+
+print "Then remount\n";
+$result = system(
+"runcon -t test_filesystem_t $basedir/mount -r -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v"
+);
+ok( $result eq 0 );
+
+print "Running quotacheck(8) to init user/group quota files\n";
+$result = system("quotacheck -ugF vfsv0 $private_path/mp1");
+ok( $result eq 0 );
+
+print "Toggle User & Group quotas on/off\n";
+$result = system(
+"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v"
+);
+ok( $result eq 0 );
+$result = system(
+"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.group $v"
+);
+ok( $result eq 0 );
+
+print "Get statfs(2)\n";
+$result =
+  system(
+    "runcon -t test_filesystem_t $basedir/statfs_test -t $basedir/mntpoint $v");
+ok( $result eq 0 );
+
+print "Creating test file $basedir/mntpoint/mp1/test_file\n";
+$result =
+  system(
+"runcon -t test_filesystem_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v"
+  );
+ok( $result eq 0 );
+
+if ($test_watch) {
+    print "fanotify(7) test\n";
+    $result = system(
+"runcon -t test_filesystem_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1"
+    );
+    ok( $result eq 0 );
+}
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result =
+  system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp1 $v");
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Test Move Mount ##########################
+make_fs($fs_type);
+$mount_opts2 =
+  "quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_t:s0";
+system("mkdir -p $private_path 2>/dev/null");
+
+print "Set mount MS_BIND on filesystem\n";
+$result = system(
+"runcon -t test_filesystem_t $basedir/mount -s $private_path -t $private_path -b $v"
+);
+ok( $result eq 0 );
+
+print "Set mount MS_PRIVATE on filesystem\n";
+$result =
+  system("runcon -t test_filesystem_t $basedir/mount -t $private_path -p $v");
+ok( $result eq 0 );
+
+mk_mntpoint_1();
+mk_mntpoint_2();
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$mount_opts2\n";
+$result = system(
+"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts2 $v"
+);
+ok( $result eq 0 );
+
+print "Set mount MS_MOVE on filesystem\n";
+$result = system(
+"runcon -t test_filesystem_t $basedir/mount -s $private_path/mp1 -t $private_path/mp2 -m  $v"
+);
+ok( $result eq 0 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp2\n";
+$result =
+  system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp2 $v");
+ok( $result eq 0 );
+
+print "Unmount filesystem from $basedir/mntpoint\n";
+$result =
+  system("runcon -t test_filesystem_t $basedir/umount -t $private_path $v");
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { relabelfrom } ##########################
+# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM
+
+$opts_no_relabelfrom =
+"defcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0,fscontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0";
+mk_mntpoint_1();
+make_fs($fs_type);
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_relabelfrom\n";
+$result = system(
+"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1"
+);
+ok( $result >> 8 eq 13 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { relabelto } ##########################
+# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO
+
+$opts_no_relabelto =
+  "fscontext=system_u:object_r:test_filesystem_no_relabelto_t:s0";
+mk_mntpoint_1();
+make_fs($fs_type);
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_relabelto\n";
+$result = system(
+"runcon -t test_filesystem_no_relabelto_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelto $v 2>&1"
+);
+ok( $result >> 8 eq 13 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { relabelfrom } ##########################
+# hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM
+
+$opts_no_relabelfrom =
+  "rootcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0";
+mk_mntpoint_1();
+make_fs($fs_type);
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_relabelfrom\n";
+$result = system(
+"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1"
+);
+ok( $result >> 8 eq 13 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { associate } ##########################
+# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE
+
+$opts_no_associate =
+"defcontext=system_u:object_r:test_filesystem_no_associate_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_t:s0";
+mk_mntpoint_1();
+make_fs($fs_type);
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_associate\n";
+$result = system(
+"runcon -t test_filesystem_no_associate_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate $v 2>&1"
+);
+ok( $result >> 8 eq 13 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { associate } ##########################
+# hooks.c may_create() FILESYSTEM__ASSOCIATE
+cleanup();
+mk_mntpoint_1();
+make_fs($fs_type);
+$opts_no_associate_file =
+  "fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0";
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_associate_file\n";
+$result = system(
+"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v"
+);
+ok( $result eq 0 );
+
+print "Creating test file $basedir/mntpoint/mp1/test_file\n";
+$result =
+  system(
+"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1"
+  );
+ok( $result >> 8 eq 13 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result =
+  system(
+"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+  );
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { quotamod } ##########################
+# hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD
+
+$opts_no_quotamod =
+"quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesystem_no_quotamod_t:s0";
+mk_mntpoint_1();
+make_fs($fs_type);
+system("mkdir -p $private_path 2>/dev/null");
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_quotamod\n";
+$result = system(
+"runcon -t test_filesystem_no_quotamod_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotamod $v 2>&1"
+);
+ok( $result eq 0 );
+
+# No need to run quotacheck(8) as never gets far enough to read quota file
+print "Toggle User & Group quotas on/off\n";    # Must have full path
+$result = system(
+"runcon -t test_filesystem_no_quotamod_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1"
+);
+ok( $result >> 8 eq 13 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result = system(
+"runcon -t test_filesystem_no_quotamod_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+);
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { quotaget } ##########################
+# hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET
+
+$opts_no_quotaget =
+"quota,usrquota,grpquota,context=system_u:object_r:test_filesystem_no_quotaget_t:s0";
+mk_mntpoint_1();
+make_fs($fs_type);
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_quotaget\n";
+$result = system(
+"runcon -t test_filesystem_no_quotaget_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotaget $v"
+);
+ok( $result eq 0 );
+
+print "Running quotacheck(8) to init user/group quota files\n";
+$result = system("quotacheck -ugF vfsv0 $private_path/mp1");
+ok( $result eq 0 );
+
+print "Toggle User & Group quotas on/off\n";    # Must have full path
+$result = system(
+"runcon -t test_filesystem_no_quotaget_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1"
+);
+ok( $result >> 8 eq 13 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result = system(
+"runcon -t test_filesystem_no_quotaget_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+);
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { mount } ##########################
+# hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT
+
+$opts_no_mount = "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0";
+mk_mntpoint_1();
+make_fs($fs_type);
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_mount\n";
+$result = system(
+"runcon -t test_filesystem_no_mount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_mount $v 2>&1"
+);
+ok( $result >> 8 eq 13 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { getattr } ##########################
+# hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR
+
+$opts_no_getattr =
+  "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0";
+mk_mntpoint_1();
+make_fs($fs_type);
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_getattr\n";
+$result = system(
+"runcon -t test_filesystem_no_getattr_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_getattr $v"
+);
+ok( $result eq 0 );
+
+$result = system(
+"runcon -t test_filesystem_no_getattr_t $basedir/statfs_test -t $basedir/mntpoint $v 2>&1"
+);
+ok( $result >> 8 eq 13 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result = system(
+"runcon -t test_filesystem_no_getattr_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+);
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { remount } ##########################
+# hooks.c selinux_mount() FILESYSTEM__REMOUNT
+
+$opts_no_remount =
+  "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0";
+mk_mntpoint_1();
+make_fs($fs_type);
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_remount\n";
+$result = system(
+"runcon -t test_filesystem_no_remount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v"
+);
+ok( $result eq 0 );
+
+print "Then remount\n";
+$result = system(
+"runcon -t test_filesystem_no_remount_t $basedir/mount -r -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v 2>&1"
+);
+ok( $result >> 8 eq 13 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result = system(
+"runcon -t test_filesystem_no_remount_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+);
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { unmount } ##########################
+# hooks.c selinux_umount() FILESYSTEM__UNMOUNT
+
+$opts_no_unmount =
+  "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0";
+mk_mntpoint_1();
+make_fs($fs_type);
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_unmount\n";
+$result = system(
+"runcon -t test_filesystem_no_unmount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_unmount $v"
+);
+ok( $result eq 0 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result = system(
+"runcon -t test_filesystem_no_unmount_t $basedir/umount -t $basedir/mntpoint/mp1 $v 2>&1"
+);
+ok( $result >> 8 eq 13 );
+
+# Make sure it does get unmounted
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result =
+  system(
+    "runcon -t test_filesystem_t $basedir/umount -t $basedir/mntpoint/mp1 $v");
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { associate }  ##########################
+# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE
+cleanup();
+mk_mntpoint_1();
+make_fs($fs_type);
+$opts_no_associate_file =
+"defcontext=system_u:object_r:test_filesystem_no_associate_file_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0";
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_associate_file\n";
+$result = system(
+"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v"
+);
+ok( $result eq 0 );
+
+print "Creating test file $basedir/mntpoint/mp1/test_file\n";
+$result =
+  system(
+"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1"
+  );
+ok( $result >> 8 eq 13 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result =
+  system(
+"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+  );
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+############### Deny filesystem { watch }  ##########################
+# hooks.c selinux_path_notify() FILESYSTEM__WATCH
+if ($test_watch) {
+    cleanup();
+    mk_mntpoint_1();
+    make_fs($fs_type);
+    $opts_no_watch = "context=system_u:object_r:test_filesystem_no_watch_t:s0";
+
+    print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+    print "Using mount options:\n\t$opts_no_watch\n";
+    $result = system(
+"runcon -t test_filesystem_no_watch_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_watch $v"
+    );
+    ok( $result eq 0 );
+
+    print "test_fanotify\n";
+    $result = system(
+"runcon -t test_filesystem_no_watch_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1 2>&1"
+    );
+    ok( $result >> 8 eq 13 );
+
+    print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+    $result = system(
+"runcon -t test_filesystem_no_watch_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+    );
+    ok( $result eq 0 );
+
+    print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+    cleanup1();
+}
+
+##########################################################################
+# context     - Useful when mounting filesystems that do not support extended
+#               attributes.
+#   Tested by - Creating a filesystem that has xattrs set to a different value,
+#               then mount with context= and confirm that the files have that
+#               context as well as any newly created files (even if fscreate
+#               was set to something else), and that setfilecon/setxattr() on
+#               files within the mount fails with errno EOPNOTSUPP.
+##########################################################################
+cleanup();
+mk_mntpoint_1();
+make_fs($fs_type);
+
+# Mount with xttrs to create a file with specific context.
+$context1_opts = "defcontext=system_u:object_r:test_filesystem_context_t:s0";
+
+print "Testing 'context=' mount option\n";
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$context1_opts\n";
+$result = system(
+"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context1_opts $v"
+);
+ok( $result eq 0 );
+
+# Create file with 'test_filesystem_filecon_t' context
+print "Creating test file $basedir/mntpoint/mp1/test_file\n";
+$result =
+  system(
+"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v"
+  );
+ok( $result eq 0 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result = system(
+"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+);
+ok( $result eq 0 );
+
+# Need to free the loop device, then get new dev one and attach
+system("losetup -d $dev 2>/dev/null");
+get_loop_dev();
+attach_dev();
+
+# Mount again with no xttr support
+$context2_opts = "context=system_u:object_r:test_filesystem_context_t:s0";
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$context2_opts\n";
+$result = system(
+"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context2_opts $v"
+);
+ok( $result eq 0 );
+
+# Now check the context on file is system_u:object_r:test_filesystem_context_t:s0
+print "Check test file context $basedir/mntpoint/mp1/test_file\n";
+$result =
+  system(
+"runcon -t test_filesystem_context_t $basedir/check_file_context -f $private_path/mp1/test_file -e system_u:object_r:test_filesystem_context_t:s0 $v"
+  );
+ok( $result eq 0 );
+
+# Then create a file with 'test_filesystem_filecon_t' context, this should fail with EOPNOTSUPP
+print "Creating test file $basedir/mntpoint/mp1/test_file\n";
+$result =
+  system(
+"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v 2>/dev/null"
+  );
+ok( $result >> 8 eq 95 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result =
+  system(
+"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+  );
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+##########################################################################
+# rootcontext - Explicitly label the root inode of the filesystem being
+#               mounted before that filesystem or inode becomes visible
+#               to userspace.
+#   Tested by - Set mountpoint to unlabeled_t and then check that the
+#               context of the root directory matches rootcontext= after
+#               the mount operation.
+##########################################################################
+cleanup();
+mk_mntpoint_1();
+make_fs($fs_type);
+$root_opts = "rootcontext=system_u:object_r:test_filesystem_context_t:s0";
+
+print "Testing 'rootcontext=' mount option\n";
+
+# Reset mountpoint to 'unlabeled_t' so it is different to any other possible test values.
+print "Resetting MP to unlabeled_t $basedir/mntpoint/mp1\n";
+$result =
+  system(
+"runcon -t test_filesystem_context_t $basedir/check_mount_context -r -m $basedir/mntpoint/mp1 $v"
+  );
+ok( $result eq 0 );
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$root_opts\n";
+$result = system(
+"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $root_opts $v"
+);
+ok( $result eq 0 );
+
+# Now check the mountpoint is the 'rootcontext=' value
+print "Check MP context $basedir/mntpoint/mp1\n";
+$result =
+  system(
+"runcon -t test_filesystem_context_t $basedir/check_mount_context -m $basedir/mntpoint/mp1 -e system_u:object_r:test_filesystem_context_t:s0 $v"
+  );
+ok( $result eq 0 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result = system(
+"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+);
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+##########################################################################
+# defcontext  - Set default security context for unlabeled files.
+#               This overrides the value set for unlabeled files in policy
+#               and requires a filesystem that supports xattr labeling.
+#   Tested by - Create filesystem that has files w/o xattrs and then confirm
+#               that they are mapped to the specified defcontext upon mount,
+#               where defcontext differs from the policy default.
+##########################################################################
+cleanup();
+mk_mntpoint_1();
+make_fs($fs_type);
+
+$test_opts = "context=system_u:object_r:test_filesystem_context_t:s0";
+
+print "Testing 'defcontext=' mount option\n";
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$test_opts\n";
+$result = system(
+"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $test_opts $v"
+);
+ok( $result eq 0 );
+
+# Create file, its context will be system_u:object_r:test_filesystem_context_t:s0 from $test_opts
+print "Creating test file $basedir/mntpoint/mp1/test_file\n";
+$result =
+  system(
+"runcon -u system_u -t test_filesystem_fscontext_t $basedir/create_file -f $basedir/mntpoint/mp1/test_file $v"
+  );
+ok( $result eq 0 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result = system(
+"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+);
+ok( $result eq 0 );
+
+# Need to free the loop device, then get new dev one and attach
+system("losetup -d $dev 2>/dev/null");
+get_loop_dev();
+attach_dev();
+
+# Mount again with defcontext=
+$defcontext_opts = "defcontext=system_u:object_r:test_filesystem_filecon_t:s0";
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$defcontext_opts\n";
+$result = system(
+"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $defcontext_opts $v"
+);
+ok( $result eq 0 );
+
+# Now check the file context is now system_u:object_r:test_filesystem_filecon_t:s0
+print "Check test file context $basedir/mntpoint/mp1/test_file\n";
+$result =
+  system(
+"runcon -t test_filesystem_context_t $basedir/check_file_context -f $basedir/mntpoint/mp1/test_file -e system_u:object_r:test_filesystem_filecon_t:s0 $v"
+  );
+ok( $result eq 0 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result =
+  system(
+"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+  );
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+##########################################################################
+# fscontext   - Sets the overarching filesystem label to a specific security
+#               context. This filesystem label is separate from the individual
+#               labels on the files.
+#   Tested by - Mount a tmpfs (fs_use_trans) filesystem with fscontext= and
+#               then create a file within it, checking its context.
+##########################################################################
+$fs_type = "tmpfs";
+cleanup();
+mk_mntpoint_1();
+make_fs($fs_type);
+$fscontext_opts =
+"fscontext=system_u:object_r:test_filesystem_fscontext_t:s0,size=10M,mode=0770";
+
+print "Testing 'fscontext=' mount option\n";
+print "Mount tmpfs filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$fscontext_opts\n";
+$result = system(
+"runcon -t test_filesystem_fscontext_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $fscontext_opts $v"
+);
+ok( $result eq 0 );
+
+print "Creating test file $basedir/mntpoint/mp1/test_file\n";
+$result =
+  system(
+"runcon -t test_filesystem_fscontext_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v"
+  );
+ok( $result eq 0 );
+
+print "Unmount filesystem from $basedir/mntpoint/mp1\n";
+$result =
+  system(
+"runcon -t test_filesystem_fscontext_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+  );
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1();
+
+# Cleanup any attached /dev/loop entries
+foreach my $n (@device_list) {
+    system("$basedir/grim_reaper $n 2>/dev/null");
+}
+
+exit;
diff --git a/tests/filesystem/umount.c b/tests/filesystem/umount.c
new file mode 100644
index 0000000..4a20448
--- /dev/null
+++ b/tests/filesystem/umount.c
@@ -0,0 +1,84 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/mount.h>
+#include <selinux/selinux.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v] [-t]\n"
+		"Where:\n\t"
+		"-t  Target path\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+#define WAIT_COUNT 60
+#define USLEEP_TIME 100000
+
+int main(int argc, char *argv[])
+{
+	char *context, *tgt = NULL;
+	int opt, result, i, save_err;
+	bool verbose = false;
+
+	while ((opt = getopt(argc, argv, "t:v")) != -1) {
+		switch (opt) {
+		case 't':
+			tgt = optarg;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!tgt)
+		print_usage(argv[0]);
+
+	if (verbose) {
+		result = getcon(&context);
+		if (result < 0) {
+			fprintf(stderr, "Failed to obtain process context\n");
+			exit(-1);
+		}
+		printf("Process context:\n\t%s\n", context);
+		free(context);
+	}
+
+	/*
+	 * umount(2) will sometimes return EBUSY when other tasks are
+	 * checking mounts so wait around before bailing out.
+	 */
+	for (i = 0; i < WAIT_COUNT; i++) {
+		result = umount(tgt);
+		save_err = errno;
+		if (!result) {
+			if (verbose)
+				printf("Unmounted: %s\n", tgt);
+
+			return 0;
+		}
+
+		if (verbose && save_err == EBUSY)
+			printf("umount(2) returned EBUSY %d times\n", i + 1);
+
+		if (save_err != EBUSY) {
+			fprintf(stderr, "Failed umount(2): %s\n",
+				strerror(save_err));
+			return save_err;
+		}
+		usleep(USLEEP_TIME);
+	}
+
+	fprintf(stderr, "Failed to umount(2) after %d retries with: %s\n",
+		WAIT_COUNT, strerror(save_err));
+
+	return save_err;
+}
-- 
2.23.0


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/1] selinux-testsuite: Add filesystem tests
  2019-12-20 10:11 ` [PATCH 1/1] " Richard Haines
@ 2020-01-06 16:11   ` Ondrej Mosnacek
  2020-01-07 15:30     ` Richard Haines
  2020-01-09 14:18   ` Stephen Smalley
  1 sibling, 1 reply; 6+ messages in thread
From: Ondrej Mosnacek @ 2020-01-06 16:11 UTC (permalink / raw)
  To: Richard Haines; +Cc: SElinux list

On Fri, Dec 20, 2019 at 11:11 AM Richard Haines
<richard_c_haines@btinternet.com> wrote:
> Test filesystem permissions and setfscreatecon(3).
>
> From kernels 5.5 filesystem { watch } is also tested.
>
> Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>

Please see a few inline comments below.

[...]

> diff --git a/tests/filesystem/create_file_change_context.c b/tests/filesystem/create_file_change_context.c
> new file mode 100644
> index 0000000..2a3b995
> --- /dev/null
> +++ b/tests/filesystem/create_file_change_context.c
> @@ -0,0 +1,143 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <linux/unistd.h>
> +#include <selinux/selinux.h>
> +#include <selinux/context.h>
> +
> +static void print_usage(char *progname)
> +{
> +       fprintf(stderr,
> +               "usage:  %s [-v] -t -f\n"
> +               "Where:\n\t"
> +               "-t  Type for context of created file\n\t"
> +               "-f  File to create\n\t"
> +               "-v  Print information.\n", progname);
> +       exit(-1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +       int opt, result, fd, save_err;
> +       char *context, *newfcon, *orgfcon, *type = NULL, *file = NULL;
> +       bool verbose = false;
> +       context_t con_t;
> +
> +       while ((opt = getopt(argc, argv, "t:f:v")) != -1) {
> +               switch (opt) {
> +               case 't':
> +                       type = optarg;
> +                       break;
> +               case 'f':
> +                       file = optarg;
> +                       break;
> +               case 'v':
> +                       verbose = true;
> +                       break;
> +               default:
> +                       print_usage(argv[0]);
> +               }
> +       }
> +
> +       if (!type || !file)
> +               print_usage(argv[0]);
> +
> +       result = getcon(&context);
> +       if (result < 0) {
> +               fprintf(stderr, "Failed to obtain process context\n");
> +               exit(-1);
> +       }
> +
> +       /* Build new file context */
> +       con_t = context_new(context);
> +       if (!con_t) {
> +               fprintf(stderr, "Unable to create context structure\n");
> +               exit(-1);
> +       }
> +
> +       if (context_type_set(con_t, type)) {
> +               fprintf(stderr, "Unable to set new type\n");
> +               exit(-1);
> +       }

Shouldn't you rather build the new context from the original file's
context? If you build it from the process context, then the role and
MLS/MCS range will be wrong. Somehow this code works on recent
systems, but on RHEL-6 it causes the test to fail.

> +
> +       newfcon = context_str(con_t);
> +       if (!newfcon) {
> +               fprintf(stderr, "Unable to obtain new context string\n");
> +               exit(-1);
> +       }
> +
> +       if (verbose) {
> +               printf("Process context:\n\t%s\n", context);
> +               printf("is creating test file:\n\t%s\n", file);
> +               printf("and changing its context to:\n\t%s\n", newfcon);
> +       }
> +
> +       free(context);
> +       context = NULL;
> +
> +       /* hooks.c may_create() FILESYSTEM__ASSOCIATE */
> +       fd = creat(file, O_RDWR);
> +       save_err = errno;
> +       if (fd < 0) {
> +               fprintf(stderr, "creat(2) Failed: %s\n", strerror(errno));
> +               result = save_err;
> +               goto err;
> +       }
> +
> +       result = fgetfilecon(fd, &orgfcon);
> +       if (result < 0) {
> +               fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> +                       strerror(errno));
> +               result = -1;
> +               goto err;
> +       }
> +
> +       if (verbose)
> +               printf("Current test file context is: %s\n", orgfcon);
> +
> +       free(orgfcon);
> +
> +       /* hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE */
> +       result = fsetfilecon(fd, newfcon);
> +       save_err = errno;
> +       if (result < 0) {
> +               fprintf(stderr, "fsetfilecon(3) Failed: %s\n",
> +                       strerror(errno));
> +               result = save_err;
> +               goto err;
> +       }
> +
> +       fd = open(file, O_RDWR);
> +       if (fd < 0) {
> +               fprintf(stderr, "open(2) Failed: %s\n", strerror(errno));
> +               result = -1;
> +       }
> +
> +       result = fgetfilecon(fd, &context);
> +       if (result < 0) {
> +               fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> +                       strerror(errno));
> +               result = -1;
> +               goto err;
> +       }
> +
> +       if (verbose)
> +               printf("New test file context is: %s\n", context);
> +
> +       result = 0;
> +       if (strcmp(newfcon, context)) {
> +               fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n",
> +                       newfcon, context);
> +               result = -1;
> +       }
> +err:
> +       free(context);
> +       free(newfcon);
> +       close(fd);
> +
> +       return result;
> +}

[...]

> diff --git a/tests/filesystem/quotas_test.c b/tests/filesystem/quotas_test.c
> new file mode 100644
> index 0000000..34aaca9
> --- /dev/null
> +++ b/tests/filesystem/quotas_test.c
> @@ -0,0 +1,134 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <sys/quota.h>
> +#include <selinux/selinux.h>

Could you please add:

#ifndef QFMT_VFS_V0
#define QFMT_VFS_V0 2
#endif

so that the code compiles on RHEL/CentOS 7 and below? (There
<sys/quota.h> doesn't contain the definition and it conflicts with
<linux/quota.h> so I don't see any better way to fix it...)

> +
> +static void print_usage(char *progname)
> +{
> +       fprintf(stderr,
> +               "usage:  %s -s src -t tgt\n"
> +               "Where:\n\t"
> +               "-s  Source path (e.g. /dev/loop0)\n\t"
> +               "-t  Target quota file (Full path with either 'aquota.user'\n\t"
> +               "    or 'aquota.group' appended)\n\t"
> +               "-v  Print information.\n", progname);
> +       exit(-1);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +       int opt, result, qcmd, save_err, test_id = geteuid();
> +       char *context, *src = NULL, *tgt = NULL;
> +       bool verbose = false;
> +       char fmt_buf[2];
> +
> +       while ((opt = getopt(argc, argv, "s:t:v")) != -1) {
> +               switch (opt) {
> +               case 's':
> +                       src = optarg;
> +                       break;
> +               case 't':
> +                       tgt = optarg;
> +                       break;
> +               case 'v':
> +                       verbose = true;
> +                       break;
> +               default:
> +                       print_usage(argv[0]);
> +               }
> +       }
> +
> +       if (!src || !tgt)
> +               print_usage(argv[0]);
> +
> +       if (verbose) {
> +               result = getcon(&context);
> +               if (result < 0) {
> +                       fprintf(stderr, "Failed to obtain process context\n");
> +                       return -1;
> +               }
> +               printf("Process context:\n\t%s\n", context);
> +               free(context);
> +       }
> +
> +       if (strstr(tgt, "aquota.user") != NULL) {
> +               qcmd = QCMD(Q_QUOTAON, USRQUOTA);
> +               result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> +               save_err = errno;
> +               if (result < 0) {
> +                       fprintf(stderr, "quotactl(Q_QUOTAON, USRQUOTA) Failed: %s\n",
> +                               strerror(errno));
> +                       return save_err;
> +               }
> +               if (verbose)
> +                       printf("User Quota - ON\n");
> +
> +               qcmd = QCMD(Q_GETFMT, USRQUOTA);
> +               result = quotactl(qcmd, src, test_id, fmt_buf);
> +               save_err = errno;
> +               if (result < 0) {
> +                       fprintf(stderr, "quotactl(Q_GETFMT, USRQUOTA) Failed: %s\n",
> +                               strerror(errno));
> +                       return save_err;
> +               }
> +               if (verbose)
> +                       printf("User Format: 0x%x\n", fmt_buf[0]);
> +
> +               qcmd = QCMD(Q_QUOTAOFF, USRQUOTA);
> +               result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> +               save_err = errno;
> +               if (result < 0) {
> +                       fprintf(stderr, "quotactl(Q_QUOTAOFF, USRQUOTA) Failed: %s\n",
> +                               strerror(errno));
> +                       return save_err;
> +               }
> +               if (verbose)
> +                       printf("User Quota - OFF\n");
> +
> +               return 0;
> +
> +       } else if (strstr(tgt, "aquota.group") != NULL) {
> +               qcmd = QCMD(Q_QUOTAON, GRPQUOTA);
> +               result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> +               save_err = errno;
> +               if (result < 0) {
> +                       fprintf(stderr, "quotactl(Q_QUOTAON, GRPQUOTA) Failed: %s\n",
> +                               strerror(errno));
> +                       return save_err;
> +               }
> +               if (verbose)
> +                       printf("Group Quota - ON\n");
> +
> +               qcmd = QCMD(Q_GETFMT, GRPQUOTA);
> +               result = quotactl(qcmd, src, test_id, fmt_buf);
> +               save_err = errno;
> +               if (result < 0) {
> +                       fprintf(stderr, "quotactl(Q_GETFMT, GRPQUOTA) Failed: %s\n",
> +                               strerror(errno));
> +                       return save_err;
> +               }
> +               if (verbose)
> +                       printf("Group Format: 0x%x\n", fmt_buf[0]);
> +
> +               qcmd = QCMD(Q_QUOTAOFF, GRPQUOTA);
> +               result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> +               save_err = errno;
> +               if (result < 0) {
> +                       fprintf(stderr, "quotactl(Q_QUOTAOFF, GRPQUOTA) Failed: %s\n",
> +                               strerror(errno));
> +                       return save_err;
> +               }
> +               if (verbose)
> +                       printf("Group Quota - OFF\n");
> +
> +               return 0;
> +       }
> +
> +       fprintf(stderr, "Required %s to specify 'aquota.user' or 'aquota.group' file\n",
> +               tgt);
> +       return -1;
> +}

[...]

> diff --git a/tests/filesystem/test b/tests/filesystem/test
> new file mode 100755
> index 0000000..00c69e1
> --- /dev/null
> +++ b/tests/filesystem/test
> @@ -0,0 +1,830 @@
> +#!/usr/bin/perl
> +use Test::More;
> +
> +BEGIN {
> +    $basedir = $0;
> +    $basedir =~ s|(.*)/[^/]*|$1|;
> +
> +    $test_count = 63;
> +
> +    # Allow info to be shown.
> +    $v = $ARGV[0];
> +    if ($v) {
> +        if ( $v ne "-v" ) {
> +            plan skip_all => "Invalid option (use -v)";
> +        }
> +    }
> +    else {
> +        $v = " ";
> +    }
> +
> +    # From kernel 5.5 support for fanotify(7) with filesystem { watch }
> +    $kvercur = `uname -r`;
> +    chomp($kvercur);
> +    $kverminstream = "5.5";
> +
> +    $result = `$basedir/../kvercmp $kvercur $kverminstream`;
> +    if ( $result > 0 && -e "$basedir/fanotify_fs" ) {
> +        $test_watch = 1;
> +        $test_count += 4;
> +    }
> +
> +    plan tests => $test_count;
> +}
> +
> +# mount(2) MS_BIND | MS_PRIVATE requires an absolute path to a private mount
> +# point before MS_MOVE
> +$cwd = `pwd 2>/dev/null`;
> +chomp($cwd);
> +$private_path = "$cwd";
> +if ( $basedir eq "." ) {
> +    $private_path = "$cwd/mntpoint";
> +}
> +else {
> +    $private_path = "$cwd/$basedir/mntpoint";
> +}
> +
> +# Set initial filesystem type
> +$fs_type = "ext4";
> +
> +# For list of devices used
> +$device_count = 0;
> +
> +sub get_loop_dev {
> +    print "Finding free /dev/loop entry\n";
> +    $dev = `losetup -f 2>/dev/null`;
> +    chomp($dev);
> +    if ( $dev eq "" ) {
> +        print "losetup failed to obtain /dev/loop entry\n";
> +        cleanup();
> +        exit -1;
> +    }
> +
> +    # Keep list of devices for cleanup later
> +    if ( $device_count eq 0 ) {
> +        $device_list[$device_count] = $dev;
> +        $device_count += 1;
> +    }
> +    elsif ( $dev ne $device_list[ $device_count - 1 ] ) {
> +        $device_list[$device_count] = $dev;
> +        $device_count += 1;
> +    }
> +}
> +
> +sub attach_dev {
> +    print "Attaching $basedir/fstest to $dev\n";
> +    $result = system("losetup $dev $basedir/fstest 2>/dev/null");
> +    if ( $result != 0 ) {
> +        print "Failed to attach $basedir/fstest to $dev\n";
> +        cleanup();
> +        exit -1;
> +    }
> +}
> +
> +sub make_fs {
> +    my ($mk_type) = @_;
> +
> +    get_loop_dev();
> +
> +    if ( $mk_type eq "tmpfs" ) {
> +        return;
> +    }
> +
> +    print "Create $basedir/fstest with dd\n";
> +    $result = system(
> +        "dd if=/dev/zero of=$basedir/fstest bs=1024 count=10240 2>/dev/null");
> +    if ( $result != 0 ) {
> +        print "dd failed to create fstest\n";
> +        exit -1;
> +    }
> +
> +    attach_dev();
> +
> +    print "Make $mk_type filesystem on $dev\n";
> +    $result = system("mkfs.$mk_type $dev >& /dev/null");
> +    if ( $result != 0 ) {
> +        system("losetup -d $dev 2>/dev/null");
> +        cleanup();
> +        print "mkfs.$mk_type failed to create filesystem on $dev\n";
> +        exit -1;
> +    }
> +}
> +
> +sub mk_mntpoint_1 {
> +    system("rm -rf $private_path/mp1 2>/dev/null");
> +    system("mkdir -p $private_path/mp1 2>/dev/null");
> +}
> +
> +sub mk_mntpoint_2 {
> +    system("rm -rf $private_path/mp2 2>/dev/null");
> +    system("mkdir -p $private_path/mp2 2>/dev/null");
> +}
> +
> +sub cleanup {
> +    system("rm -rf $basedir/fstest 2>/dev/null");
> +    system("rm -rf $basedir/mntpoint 2>/dev/null");
> +}
> +
> +sub cleanup1 {
> +    system("losetup -d $dev 2>/dev/null");
> +    system("rm -rf $basedir/fstest 2>/dev/null");
> +    system("rm -rf $basedir/mntpoint 2>/dev/null");
> +}
> +
> +############### Test setfscreatecon(3) ##########################
> +print "Test setfscreatecon(3)\n";
> +$result = system
> +"runcon -t test_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0";
> +ok( $result eq 0 );
> +
> +$result = system
> +"runcon -t test_no_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0 2>&1";
> +ok( $result >> 8 eq 13 );
> +
> +############### Test Basic Mount/Unmount ##########################
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +$mount_opts1 =
> +  "quota,usrquota,grpquota,defcontext=system_u:object_r:test_filesystem_t:s0";
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$mount_opts1\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Then remount\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/mount -r -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Running quotacheck(8) to init user/group quota files\n";
> +$result = system("quotacheck -ugF vfsv0 $private_path/mp1");

On RHEL-6, there is a type transition to quota_t when running
quotacheck as unconfined_t and it hits some denials... Would it be OK
to run it as "runcon `id -Z` quotacheck ..." here to keep the test
runnable on older systems?

> +ok( $result eq 0 );
> +
> +print "Toggle User & Group quotas on/off\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v"
> +);
> +ok( $result eq 0 );
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.group $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Get statfs(2)\n";
> +$result =
> +  system(
> +    "runcon -t test_filesystem_t $basedir/statfs_test -t $basedir/mntpoint $v");
> +ok( $result eq 0 );
> +
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v"
> +  );
> +ok( $result eq 0 );
> +
> +if ($test_watch) {
> +    print "fanotify(7) test\n";
> +    $result = system(
> +"runcon -t test_filesystem_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1"
> +    );
> +    ok( $result eq 0 );
> +}
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp1 $v");
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Test Move Mount ##########################
> +make_fs($fs_type);
> +$mount_opts2 =
> +  "quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_t:s0";
> +system("mkdir -p $private_path 2>/dev/null");
> +
> +print "Set mount MS_BIND on filesystem\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/mount -s $private_path -t $private_path -b $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Set mount MS_PRIVATE on filesystem\n";
> +$result =
> +  system("runcon -t test_filesystem_t $basedir/mount -t $private_path -p $v");
> +ok( $result eq 0 );
> +
> +mk_mntpoint_1();
> +mk_mntpoint_2();
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$mount_opts2\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts2 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Set mount MS_MOVE on filesystem\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/mount -s $private_path/mp1 -t $private_path/mp2 -m  $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp2\n";
> +$result =
> +  system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp2 $v");
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint\n";
> +$result =
> +  system("runcon -t test_filesystem_t $basedir/umount -t $private_path $v");
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { relabelfrom } ##########################
> +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM
> +
> +$opts_no_relabelfrom =
> +"defcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0,fscontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_relabelfrom\n";
> +$result = system(
> +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { relabelto } ##########################
> +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO
> +
> +$opts_no_relabelto =
> +  "fscontext=system_u:object_r:test_filesystem_no_relabelto_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_relabelto\n";
> +$result = system(
> +"runcon -t test_filesystem_no_relabelto_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelto $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { relabelfrom } ##########################
> +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM
> +
> +$opts_no_relabelfrom =
> +  "rootcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_relabelfrom\n";
> +$result = system(
> +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { associate } ##########################
> +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE
> +
> +$opts_no_associate =
> +"defcontext=system_u:object_r:test_filesystem_no_associate_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_associate\n";
> +$result = system(
> +"runcon -t test_filesystem_no_associate_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { associate } ##########################
> +# hooks.c may_create() FILESYSTEM__ASSOCIATE
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +$opts_no_associate_file =
> +  "fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0";
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_associate_file\n";
> +$result = system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1"
> +  );
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { quotamod } ##########################
> +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD
> +
> +$opts_no_quotamod =
> +"quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesystem_no_quotamod_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +system("mkdir -p $private_path 2>/dev/null");
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_quotamod\n";
> +$result = system(
> +"runcon -t test_filesystem_no_quotamod_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotamod $v 2>&1"
> +);
> +ok( $result eq 0 );
> +
> +# No need to run quotacheck(8) as never gets far enough to read quota file
> +print "Toggle User & Group quotas on/off\n";    # Must have full path
> +$result = system(
> +"runcon -t test_filesystem_no_quotamod_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_no_quotamod_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { quotaget } ##########################
> +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET
> +
> +$opts_no_quotaget =
> +"quota,usrquota,grpquota,context=system_u:object_r:test_filesystem_no_quotaget_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_quotaget\n";
> +$result = system(
> +"runcon -t test_filesystem_no_quotaget_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotaget $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Running quotacheck(8) to init user/group quota files\n";
> +$result = system("quotacheck -ugF vfsv0 $private_path/mp1");

Same issue as above.

> +ok( $result eq 0 );
> +
> +print "Toggle User & Group quotas on/off\n";    # Must have full path
> +$result = system(
> +"runcon -t test_filesystem_no_quotaget_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_no_quotaget_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { mount } ##########################
> +# hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT
> +
> +$opts_no_mount = "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_mount\n";
> +$result = system(
> +"runcon -t test_filesystem_no_mount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_mount $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { getattr } ##########################
> +# hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR
> +
> +$opts_no_getattr =
> +  "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_getattr\n";
> +$result = system(
> +"runcon -t test_filesystem_no_getattr_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_getattr $v"
> +);
> +ok( $result eq 0 );
> +
> +$result = system(
> +"runcon -t test_filesystem_no_getattr_t $basedir/statfs_test -t $basedir/mntpoint $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_no_getattr_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { remount } ##########################
> +# hooks.c selinux_mount() FILESYSTEM__REMOUNT
> +
> +$opts_no_remount =
> +  "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_remount\n";
> +$result = system(
> +"runcon -t test_filesystem_no_remount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Then remount\n";
> +$result = system(
> +"runcon -t test_filesystem_no_remount_t $basedir/mount -r -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_no_remount_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { unmount } ##########################
> +# hooks.c selinux_umount() FILESYSTEM__UNMOUNT
> +
> +$opts_no_unmount =
> +  "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_unmount\n";
> +$result = system(
> +"runcon -t test_filesystem_no_unmount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_unmount $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_no_unmount_t $basedir/umount -t $basedir/mntpoint/mp1 $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +# Make sure it does get unmounted
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +    "runcon -t test_filesystem_t $basedir/umount -t $basedir/mntpoint/mp1 $v");
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { associate }  ##########################
> +# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +$opts_no_associate_file =
> +"defcontext=system_u:object_r:test_filesystem_no_associate_file_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0";
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_associate_file\n";
> +$result = system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1"
> +  );
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { watch }  ##########################
> +# hooks.c selinux_path_notify() FILESYSTEM__WATCH
> +if ($test_watch) {
> +    cleanup();
> +    mk_mntpoint_1();
> +    make_fs($fs_type);
> +    $opts_no_watch = "context=system_u:object_r:test_filesystem_no_watch_t:s0";
> +
> +    print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +    print "Using mount options:\n\t$opts_no_watch\n";
> +    $result = system(
> +"runcon -t test_filesystem_no_watch_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_watch $v"
> +    );
> +    ok( $result eq 0 );
> +
> +    print "test_fanotify\n";
> +    $result = system(
> +"runcon -t test_filesystem_no_watch_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1 2>&1"
> +    );
> +    ok( $result >> 8 eq 13 );
> +
> +    print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +    $result = system(
> +"runcon -t test_filesystem_no_watch_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +    );
> +    ok( $result eq 0 );
> +
> +    print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +    cleanup1();
> +}
> +
> +##########################################################################
> +# context     - Useful when mounting filesystems that do not support extended
> +#               attributes.
> +#   Tested by - Creating a filesystem that has xattrs set to a different value,
> +#               then mount with context= and confirm that the files have that
> +#               context as well as any newly created files (even if fscreate
> +#               was set to something else), and that setfilecon/setxattr() on
> +#               files within the mount fails with errno EOPNOTSUPP.
> +##########################################################################
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +# Mount with xttrs to create a file with specific context.
> +$context1_opts = "defcontext=system_u:object_r:test_filesystem_context_t:s0";
> +
> +print "Testing 'context=' mount option\n";
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$context1_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context1_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +# Create file with 'test_filesystem_filecon_t' context
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +# Need to free the loop device, then get new dev one and attach
> +system("losetup -d $dev 2>/dev/null");
> +get_loop_dev();
> +attach_dev();
> +
> +# Mount again with no xttr support
> +$context2_opts = "context=system_u:object_r:test_filesystem_context_t:s0";
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$context2_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context2_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +# Now check the context on file is system_u:object_r:test_filesystem_context_t:s0
> +print "Check test file context $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/check_file_context -f $private_path/mp1/test_file -e system_u:object_r:test_filesystem_context_t:s0 $v"
> +  );
> +ok( $result eq 0 );
> +
> +# Then create a file with 'test_filesystem_filecon_t' context, this should fail with EOPNOTSUPP
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v 2>/dev/null"
> +  );
> +ok( $result >> 8 eq 95 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +##########################################################################
> +# rootcontext - Explicitly label the root inode of the filesystem being
> +#               mounted before that filesystem or inode becomes visible
> +#               to userspace.
> +#   Tested by - Set mountpoint to unlabeled_t and then check that the
> +#               context of the root directory matches rootcontext= after
> +#               the mount operation.
> +##########################################################################
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +$root_opts = "rootcontext=system_u:object_r:test_filesystem_context_t:s0";
> +
> +print "Testing 'rootcontext=' mount option\n";
> +
> +# Reset mountpoint to 'unlabeled_t' so it is different to any other possible test values.
> +print "Resetting MP to unlabeled_t $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/check_mount_context -r -m $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$root_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $root_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +# Now check the mountpoint is the 'rootcontext=' value
> +print "Check MP context $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/check_mount_context -m $basedir/mntpoint/mp1 -e system_u:object_r:test_filesystem_context_t:s0 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +##########################################################################
> +# defcontext  - Set default security context for unlabeled files.
> +#               This overrides the value set for unlabeled files in policy
> +#               and requires a filesystem that supports xattr labeling.
> +#   Tested by - Create filesystem that has files w/o xattrs and then confirm
> +#               that they are mapped to the specified defcontext upon mount,
> +#               where defcontext differs from the policy default.
> +##########################################################################
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +$test_opts = "context=system_u:object_r:test_filesystem_context_t:s0";
> +
> +print "Testing 'defcontext=' mount option\n";
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$test_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $test_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +# Create file, its context will be system_u:object_r:test_filesystem_context_t:s0 from $test_opts
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -u system_u -t test_filesystem_fscontext_t $basedir/create_file -f $basedir/mntpoint/mp1/test_file $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +# Need to free the loop device, then get new dev one and attach
> +system("losetup -d $dev 2>/dev/null");
> +get_loop_dev();
> +attach_dev();
> +
> +# Mount again with defcontext=
> +$defcontext_opts = "defcontext=system_u:object_r:test_filesystem_filecon_t:s0";
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$defcontext_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $defcontext_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +# Now check the file context is now system_u:object_r:test_filesystem_filecon_t:s0
> +print "Check test file context $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/check_file_context -f $basedir/mntpoint/mp1/test_file -e system_u:object_r:test_filesystem_filecon_t:s0 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +##########################################################################
> +# fscontext   - Sets the overarching filesystem label to a specific security
> +#               context. This filesystem label is separate from the individual
> +#               labels on the files.
> +#   Tested by - Mount a tmpfs (fs_use_trans) filesystem with fscontext= and
> +#               then create a file within it, checking its context.
> +##########################################################################
> +$fs_type = "tmpfs";
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +$fscontext_opts =
> +"fscontext=system_u:object_r:test_filesystem_fscontext_t:s0,size=10M,mode=0770";
> +
> +print "Testing 'fscontext=' mount option\n";
> +print "Mount tmpfs filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$fscontext_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_fscontext_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $fscontext_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_fscontext_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_fscontext_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +# Cleanup any attached /dev/loop entries
> +foreach my $n (@device_list) {
> +    system("$basedir/grim_reaper $n 2>/dev/null");
> +}
> +
> +exit;

[...]

--
Ondrej Mosnacek <omosnace at redhat dot com>
Software Engineer, Security Technologies
Red Hat, Inc.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/1] selinux-testsuite: Add filesystem tests
  2020-01-06 16:11   ` Ondrej Mosnacek
@ 2020-01-07 15:30     ` Richard Haines
  0 siblings, 0 replies; 6+ messages in thread
From: Richard Haines @ 2020-01-07 15:30 UTC (permalink / raw)
  To: Ondrej Mosnacek; +Cc: SElinux list

On Mon, 2020-01-06 at 17:11 +0100, Ondrej Mosnacek wrote:
> On Fri, Dec 20, 2019 at 11:11 AM Richard Haines
> <richard_c_haines@btinternet.com> wrote:
> > Test filesystem permissions and setfscreatecon(3).
> > 
> > From kernels 5.5 filesystem { watch } is also tested.
> > 
> > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> 
> Please see a few inline comments below.

Thanks for flagging these REL6/7 issues as I only have access to
current Fedora plus Rawhide.
I'll send update later today.

Richard



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/1] selinux-testsuite: Add filesystem tests
  2019-12-20 10:11 ` [PATCH 1/1] " Richard Haines
  2020-01-06 16:11   ` Ondrej Mosnacek
@ 2020-01-09 14:18   ` Stephen Smalley
  2020-01-09 17:33     ` Richard Haines
  1 sibling, 1 reply; 6+ messages in thread
From: Stephen Smalley @ 2020-01-09 14:18 UTC (permalink / raw)
  To: Richard Haines, selinux, Ondrej Mosnacek

On 12/20/19 5:11 AM, Richard Haines wrote:
> Test filesystem permissions and setfscreatecon(3).
> 
>  From kernels 5.5 filesystem { watch } is also tested.
> 
> Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>

During the execution of these tests, I see the following kernel log spew:

<6>[  496.535286] loop: module loaded
<6>[  498.180983] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts: quota,usrquota,grpquota
<4>[  498.181535] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  498.225114] EXT4-fs (loop0): re-mounted. Opts: quota,usrquota,grpquota
<4>[  498.225167] ext4 filesystem being remounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  498.284372] EXT4-fs (loop0): re-mounted. Opts: (null)
<6>[  498.349328] EXT4-fs (loop0): re-mounted. Opts: (null)
<4>[  498.349385] ext4 filesystem being remounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  500.582812] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts: quota,usrquota,grpquota
<4>[  500.583071] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<3>[  501.030500] blk_update_request: I/O error, dev loop0, sector 0 op 
0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
<3>[  501.030856] blk_update_request: I/O error, dev loop0, sector 0 op 
0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
<6>[  502.557867] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<6>[  504.475061] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<6>[  506.366675] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<3>[  506.479705] blk_update_request: I/O error, dev loop0, sector 0 op 
0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
<3>[  506.479925] blk_update_request: I/O error, dev loop0, sector 0 op 
0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
<6>[  508.316818] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<3>[  508.526137] blk_update_request: I/O error, dev loop0, sector 0 op 
0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
<3>[  508.526466] blk_update_request: I/O error, dev loop0, sector 0 op 
0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
<6>[  510.241013] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<4>[  510.241323] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  511.867178] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts: quota,usrquota,grpquota
<4>[  511.867442] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<3>[  512.521949] blk_update_request: I/O error, dev loop0, sector 0 op 
0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
<3>[  512.525497] blk_update_request: I/O error, dev loop0, sector 0 op 
0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
<6>[  513.996580] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts: quota,usrquota,grpquota
<4>[  513.996869] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  514.040984] EXT4-fs (loop0): re-mounted. Opts: (null)
<6>[  514.065928] EXT4-fs (loop0): re-mounted. Opts: (null)
<4>[  514.065950] ext4 filesystem being remounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  516.071775] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<6>[  518.001912] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<4>[  518.002294] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  519.450511] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<4>[  519.450737] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  521.579819] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<4>[  521.580225] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  523.874190] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<4>[  523.874526] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  525.559041] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<4>[  525.559423] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  526.541667] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<4>[  526.542194] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  528.760343] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<4>[  528.760704] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  530.463519] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<4>[  530.463823] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)
<6>[  531.469358] EXT4-fs (loop0): mounted filesystem with ordered data 
mode. Opts:
<4>[  531.469779] ext4 filesystem being mounted at 
/home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
timestamps until 2038 (0x7fffffff)

Wondering if all of that is expected and necessary for testing or if we 
can get rid of some of the noise.

> ---
>   defconfig                                     |   6 +
>   policy/Makefile                               |   4 +
>   policy/test_filesystem.te                     | 324 +++++++
>   tests/Makefile                                |   7 +
>   tests/filesystem/.gitignore                   |  11 +
>   tests/filesystem/Makefile                     |  16 +
>   tests/filesystem/check_file_context.c         |  75 ++
>   tests/filesystem/check_mount_context.c        | 109 +++
>   tests/filesystem/create_file.c                |  79 ++
>   tests/filesystem/create_file_change_context.c | 143 +++
>   tests/filesystem/fanotify_fs.c                |  79 ++
>   tests/filesystem/fs_relabel.c                 |  72 ++
>   tests/filesystem/grim_reaper.c                |  63 ++
>   tests/filesystem/mount.c                      | 130 +++
>   tests/filesystem/quotas_test.c                | 134 +++
>   tests/filesystem/statfs_test.c                |  65 ++
>   tests/filesystem/test                         | 830 ++++++++++++++++++
>   tests/filesystem/umount.c                     |  84 ++
>   18 files changed, 2231 insertions(+)
>   create mode 100644 policy/test_filesystem.te
>   create mode 100644 tests/filesystem/.gitignore
>   create mode 100644 tests/filesystem/Makefile
>   create mode 100644 tests/filesystem/check_file_context.c
>   create mode 100644 tests/filesystem/check_mount_context.c
>   create mode 100644 tests/filesystem/create_file.c
>   create mode 100644 tests/filesystem/create_file_change_context.c
>   create mode 100644 tests/filesystem/fanotify_fs.c
>   create mode 100644 tests/filesystem/fs_relabel.c
>   create mode 100644 tests/filesystem/grim_reaper.c
>   create mode 100644 tests/filesystem/mount.c
>   create mode 100644 tests/filesystem/quotas_test.c
>   create mode 100644 tests/filesystem/statfs_test.c
>   create mode 100755 tests/filesystem/test
>   create mode 100644 tests/filesystem/umount.c
> 
> diff --git a/defconfig b/defconfig
> index 3bea332..7cb6a2c 100644
> --- a/defconfig
> +++ b/defconfig
> @@ -88,3 +88,9 @@ CONFIG_TUN=m
>   CONFIG_HAVE_PERF_EVENTS=y
>   CONFIG_PERF_EVENTS=y
>   CONFIG_TRACEPOINTS=y
> +
> +# Test filesystem permissions.
> +# This is not required for SELinux operation itself.
> +CONFIG_BLK_DEV_LOOP=m
> +CONFIG_BLK_DEV_LOOP_MIN_COUNT=0
> +CONFIG_QFMT_V2=y
> diff --git a/policy/Makefile b/policy/Makefile
> index 6f1db03..30896d8 100644
> --- a/policy/Makefile
> +++ b/policy/Makefile
> @@ -114,6 +114,10 @@ TARGETS += test_lockdown.te
>   export M4PARAM += -Dlockdown_defined
>   endif
>   
> +ifeq ($(shell grep -q filesystem $(POLDEV)/include/support/all_perms.spt && echo true),true)
> +TARGETS += test_filesystem.te
> +endif
> +
>   ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
>   TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te test_ibpkey.te, $(TARGETS))
>   endif
> diff --git a/policy/test_filesystem.te b/policy/test_filesystem.te
> new file mode 100644
> index 0000000..2eee1fc
> --- /dev/null
> +++ b/policy/test_filesystem.te
> @@ -0,0 +1,324 @@
> +#
> +######### Test filesystem permissions policy module ##########
> +#
> +attribute filesystemdomain;
> +
> +#################### Create a test file context ######################
> +type test_filesystem_filecon_t;
> +unconfined_runs_test(test_filesystem_filecon_t)
> +
> +################# Test all functions ##########################
> +type test_filesystem_t;
> +domain_type(test_filesystem_t)
> +unconfined_runs_test(test_filesystem_t)
> +typeattribute test_filesystem_t testdomain;
> +typeattribute test_filesystem_t filesystemdomain;
> +
> +allow test_filesystem_t self:capability { sys_admin };
> +allow test_filesystem_t self:filesystem { mount remount quotamod relabelfrom relabelto unmount quotaget };
> +allow test_filesystem_t self:dir { mounton add_name write };
> +allow test_filesystem_t test_file_t:dir { mounton write remove_name rmdir };
> +# Create test file
> +allow test_filesystem_t self:dir { add_name write };
> +allow test_filesystem_t self:file { create relabelfrom relabelto };
> +
> +fs_mount_all_fs(test_filesystem_t)
> +fs_remount_all_fs(test_filesystem_t)
> +fs_unmount_all_fs(test_filesystem_t)
> +fs_relabelfrom_all_fs(test_filesystem_t)
> +fs_get_xattr_fs_quotas(test_filesystem_t)
> +files_search_all(test_filesystem_t)
> +# Required for mount opts "rootcontext=system_u:object_r:test_filesystem_t:s0";
> +fs_associate(test_filesystem_t)
> +fs_getattr_xattr_fs(test_filesystem_t)
> +
> +# For running quotacheck(8)
> +files_type(test_filesystem_t)
> +# Update quotas
> +fs_set_all_quotas(test_filesystem_t)
> +allow test_filesystem_t self:file { quotaon };
> +# Create test file and change context:
> +fs_associate(test_filesystem_filecon_t)
> +allow test_filesystem_t test_filesystem_filecon_t:file { open read getattr relabelto write };
> +dontaudit test_filesystem_t kernel_t:process { setsched };
> +
> +#################### Deny filesystem { getattr } ######################
> +type test_filesystem_no_getattr_t;
> +domain_type(test_filesystem_no_getattr_t)
> +unconfined_runs_test(test_filesystem_no_getattr_t)
> +typeattribute test_filesystem_no_getattr_t testdomain;
> +typeattribute test_filesystem_no_getattr_t filesystemdomain;
> +
> +allow test_filesystem_no_getattr_t self:capability { sys_admin };
> +fs_mount_all_fs(test_filesystem_no_getattr_t)
> +fs_unmount_all_fs(test_filesystem_no_getattr_t)
> +fs_relabelfrom_all_fs(test_filesystem_no_getattr_t)
> +fs_associate(test_filesystem_no_getattr_t)
> +allow test_filesystem_no_getattr_t self:dir { mounton };
> +allow test_filesystem_no_getattr_t test_file_t:dir { mounton write remove_name rmdir };
> +dontaudit test_filesystem_no_getattr_t kernel_t:process { setsched };
> +
> +#################### Deny filesystem { remount } ######################
> +type test_filesystem_no_remount_t;
> +domain_type(test_filesystem_no_remount_t)
> +unconfined_runs_test(test_filesystem_no_remount_t)
> +typeattribute test_filesystem_no_remount_t testdomain;
> +typeattribute test_filesystem_no_remount_t filesystemdomain;
> +
> +allow test_filesystem_no_remount_t self:capability { sys_admin };
> +fs_mount_all_fs(test_filesystem_no_remount_t)
> +fs_unmount_all_fs(test_filesystem_no_remount_t)
> +fs_relabelfrom_all_fs(test_filesystem_no_remount_t)
> +fs_associate(test_filesystem_no_remount_t)
> +allow test_filesystem_no_remount_t self:dir { mounton };
> +allow test_filesystem_no_remount_t test_file_t:dir { mounton write remove_name rmdir };
> +dontaudit test_filesystem_no_remount_t kernel_t:process { setsched };
> +
> +#################### Deny filesystem { mount } ######################
> +type test_filesystem_no_mount_t;
> +domain_type(test_filesystem_no_mount_t)
> +unconfined_runs_test(test_filesystem_no_mount_t)
> +typeattribute test_filesystem_no_mount_t testdomain;
> +typeattribute test_filesystem_no_mount_t filesystemdomain;
> +
> +allow test_filesystem_no_mount_t self:capability { sys_admin };
> +fs_relabelfrom_all_fs(test_filesystem_no_mount_t)
> +fs_associate(test_filesystem_no_mount_t)
> +allow test_filesystem_no_mount_t self:dir { mounton };
> +allow test_filesystem_no_mount_t test_file_t:dir { mounton write remove_name rmdir };
> +dontaudit test_filesystem_no_mount_t kernel_t:process { setsched };
> +
> +#################### Deny filesystem { unmount } ######################
> +type test_filesystem_no_unmount_t;
> +domain_type(test_filesystem_no_unmount_t)
> +unconfined_runs_test(test_filesystem_no_unmount_t)
> +typeattribute test_filesystem_no_unmount_t testdomain;
> +typeattribute test_filesystem_no_unmount_t filesystemdomain;
> +
> +allow test_filesystem_no_unmount_t self:capability { sys_admin };
> +fs_mount_all_fs(test_filesystem_no_unmount_t)
> +fs_relabelfrom_all_fs(test_filesystem_no_unmount_t)
> +fs_associate(test_filesystem_no_unmount_t)
> +allow test_filesystem_no_unmount_t self:dir { mounton };
> +allow test_filesystem_no_unmount_t test_file_t:dir { mounton write remove_name rmdir };
> +dontaudit test_filesystem_no_unmount_t kernel_t:process { setsched };
> +
> +#################### Deny filesystem { relabelfrom } ######################
> +type test_filesystem_no_relabelfrom_t;
> +domain_type(test_filesystem_no_relabelfrom_t)
> +unconfined_runs_test(test_filesystem_no_relabelfrom_t)
> +typeattribute test_filesystem_no_relabelfrom_t testdomain;
> +typeattribute test_filesystem_no_relabelfrom_t filesystemdomain;
> +
> +allow test_filesystem_no_relabelfrom_t self:capability { sys_admin };
> +fs_associate(test_filesystem_no_relabelfrom_t)
> +allow test_filesystem_no_relabelfrom_t self:dir { mounton };
> +allow test_filesystem_no_relabelfrom_t test_file_t:dir { mounton write remove_name rmdir };
> +dontaudit test_filesystem_no_relabelfrom_t kernel_t:process { setsched };
> +
> +#################### Deny filesystem { relabelto } ######################
> +type test_filesystem_no_relabelto_t;
> +domain_type(test_filesystem_no_relabelto_t)
> +unconfined_runs_test(test_filesystem_no_relabelto_t)
> +typeattribute test_filesystem_no_relabelto_t testdomain;
> +typeattribute test_filesystem_no_relabelto_t filesystemdomain;
> +
> +allow test_filesystem_no_relabelto_t self:capability { sys_admin };
> +fs_mount_all_fs(test_filesystem_no_relabelto_t)
> +fs_relabelfrom_all_fs(test_filesystem_no_relabelto_t)
> +fs_associate(test_filesystem_no_relabelto_t)
> +allow test_filesystem_no_relabelto_t self:dir { mounton };
> +allow test_filesystem_no_relabelto_t test_file_t:dir { mounton write remove_name rmdir };
> +dontaudit test_filesystem_no_relabelto_t kernel_t:process { setsched };
> +
> +#################### Deny filesystem { associate } ######################
> +type test_filesystem_no_associate_t;
> +type test_filesystem_no_associate1_t;
> +domain_type(test_filesystem_no_associate_t)
> +unconfined_runs_test(test_filesystem_no_associate_t)
> +typeattribute test_filesystem_no_associate_t testdomain;
> +typeattribute test_filesystem_no_associate_t filesystemdomain;
> +
> +allow test_filesystem_no_associate_t self:capability { sys_admin };
> +allow test_filesystem_no_associate_t self:filesystem { relabelto mount relabelfrom };
> +fs_mount_all_fs(test_filesystem_no_associate_t)
> +fs_relabelfrom_all_fs(test_filesystem_no_associate_t)
> +allow test_filesystem_no_associate_t self:dir { mounton };
> +allow test_filesystem_no_associate_t test_file_t:dir { mounton write remove_name rmdir };
> +dontaudit test_filesystem_no_associate_t kernel_t:process { setsched };
> +
> +########## Deny filesystem { associate } for create file ################
> +type test_filesystem_no_associate_file_t;
> +domain_type(test_filesystem_no_associate_file_t)
> +unconfined_runs_test(test_filesystem_no_associate_file_t)
> +typeattribute test_filesystem_no_associate_file_t testdomain;
> +typeattribute test_filesystem_no_associate_file_t filesystemdomain;
> +
> +allow test_filesystem_no_associate_file_t self:capability { sys_admin };
> +allow test_filesystem_no_associate_file_t self:filesystem { mount relabelfrom relabelto unmount associate };
> +allow test_filesystem_no_associate_file_t self:dir { mounton add_name write };
> +allow test_filesystem_no_associate_file_t test_file_t:dir { mounton write remove_name rmdir };
> +
> +fs_mount_all_fs(test_filesystem_no_associate_file_t)
> +fs_unmount_all_fs(test_filesystem_no_associate_file_t)
> +fs_relabelfrom_all_fs(test_filesystem_no_associate_file_t)
> +fs_associate(test_filesystem_no_associate_file_t)
> +fs_getattr_xattr_fs(test_filesystem_no_associate_file_t)
> +dontaudit test_filesystem_no_associate_file_t kernel_t:process { setsched };
> +
> +# Create test file
> +allow test_filesystem_no_associate_file_t self:file { create relabelfrom relabelto };
> +############ hooks.c may_create() FILESYSTEM__ASSOCIATE #############
> +# FOR: neverallow unlabeled_t test_filesystem_no_associate_file_t:filesystem { associate };
> +allow test_filesystem_no_associate_file_t unconfined_t:file { open read write };
> +allow test_filesystem_no_associate_file_t unlabeled_t:dir { add_name search write };
> +allow test_filesystem_no_associate_file_t unlabeled_t:file { create open relabelfrom write };
> +############ hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE ##########
> +# FOR: neverallow unconfined_t test_filesystem_no_associate_file_t:filesystem { associate };
> +dontaudit unconfined_t test_filesystem_filecon_t:file { getattr read };
> +allow test_filesystem_no_associate_file_t unconfined_t:dir { add_name write };
> +allow test_filesystem_no_associate_file_t unconfined_t:file { create relabelfrom relabelto };
> +
> +#################### Deny filesystem { quotamod } ######################
> +type test_filesystem_no_quotamod_t;
> +domain_type(test_filesystem_no_quotamod_t)
> +unconfined_runs_test(test_filesystem_no_quotamod_t)
> +typeattribute test_filesystem_no_quotamod_t testdomain;
> +typeattribute test_filesystem_no_quotamod_t filesystemdomain;
> +
> +allow test_filesystem_no_quotamod_t self:capability { sys_admin };
> +allow test_filesystem_no_quotamod_t self:filesystem { quotaget relabelto mount unmount};
> +fs_mount_all_fs(test_filesystem_no_quotamod_t)
> +fs_relabelfrom_all_fs(test_filesystem_no_quotamod_t)
> +fs_associate(test_filesystem_no_quotamod_t)
> +# Required as $private_path to quota files
> +files_search_all(test_filesystem_no_quotamod_t)
> +allow test_filesystem_no_quotamod_t self:dir { mounton };
> +allow test_filesystem_no_quotamod_t test_file_t:dir { mounton write remove_name rmdir };
> +dontaudit test_filesystem_no_quotamod_t kernel_t:process { setsched };
> +
> +#################### Deny filesystem { quotaget } ######################
> +type test_filesystem_no_quotaget_t;
> +domain_type(test_filesystem_no_quotaget_t)
> +unconfined_runs_test(test_filesystem_no_quotaget_t)
> +typeattribute test_filesystem_no_quotaget_t testdomain;
> +typeattribute test_filesystem_no_quotaget_t filesystemdomain;
> +
> +allow test_filesystem_no_quotaget_t self:capability { sys_admin };
> +allow test_filesystem_no_quotaget_t self:filesystem { quotamod relabelto mount unmount relabelfrom };
> +allow test_filesystem_no_quotaget_t self:dir { mounton };
> +allow test_filesystem_no_quotaget_t test_file_t:dir { mounton write remove_name rmdir };
> +allow test_filesystem_no_quotaget_t self:file { quotaon };
> +fs_mount_all_fs(test_filesystem_no_quotaget_t)
> +fs_relabelfrom_all_fs(test_filesystem_no_quotaget_t)
> +fs_associate(test_filesystem_no_quotaget_t)
> +# Required as $private_path to quota files
> +files_search_all(test_filesystem_no_quotaget_t)
> +# For running quotacheck(8)
> +files_type(test_filesystem_no_quotaget_t)
> +dontaudit test_filesystem_no_quotaget_t kernel_t:process { setsched };
> +
> +#################### Deny filesystem { watch } ######################
> +type test_filesystem_no_watch_t;
> +domain_type(test_filesystem_no_watch_t)
> +unconfined_runs_test(test_filesystem_no_watch_t)
> +typeattribute test_filesystem_no_watch_t testdomain;
> +typeattribute test_filesystem_no_watch_t filesystemdomain;
> +
> +allow test_filesystem_no_watch_t self:capability { sys_admin };
> +allow test_filesystem_no_watch_t self:filesystem { associate relabelto mount unmount relabelfrom };
> +allow test_filesystem_no_watch_t self:dir { mounton };
> +allow test_filesystem_no_watch_t test_file_t:dir { mounton write remove_name rmdir };
> +fs_mount_all_fs(test_filesystem_no_watch_t)
> +fs_relabelfrom_all_fs(test_filesystem_no_watch_t)
> +fs_associate(test_filesystem_no_watch_t)
> +dontaudit test_filesystem_no_watch_t kernel_t:process { setsched };
> +
> +################# Test process { setfscreate } #############
> +type test_setfscreatecon_t;
> +domain_type(test_setfscreatecon_t)
> +unconfined_runs_test(test_setfscreatecon_t)
> +typeattribute test_setfscreatecon_t testdomain;
> +typeattribute test_setfscreatecon_t filesystemdomain;
> +
> +allow test_setfscreatecon_t self:capability { sys_admin };
> +allow test_setfscreatecon_t self:process { setfscreate };
> +
> +# Set new context on fs:
> +type test_setfscreatecon_newcon_t;
> +domain_type(test_setfscreatecon_newcon_t)
> +typeattribute test_setfscreatecon_newcon_t testdomain;
> +
> +################# deny process { setfscreate } #############
> +type test_no_setfscreatecon_t;
> +domain_type(test_no_setfscreatecon_t)
> +unconfined_runs_test(test_no_setfscreatecon_t)
> +typeattribute test_no_setfscreatecon_t testdomain;
> +typeattribute test_no_setfscreatecon_t filesystemdomain;
> +
> +allow test_no_setfscreatecon_t self:capability { sys_admin };
> +# neverallow test_no_setfscreatecon_t self:process { setfscreate };
> +
> +################# Test fscontext= ##########################
> +type test_filesystem_fscontext_t;
> +domain_type(test_filesystem_fscontext_t)
> +unconfined_runs_test(test_filesystem_fscontext_t)
> +typeattribute test_filesystem_fscontext_t testdomain;
> +typeattribute test_filesystem_fscontext_t filesystemdomain;
> +
> +allow test_filesystem_fscontext_t self:capability { sys_admin };
> +allow test_filesystem_fscontext_t self:filesystem { associate mount relabelfrom relabelto unmount };
> +allow test_filesystem_fscontext_t self:dir { mounton add_name write };
> +allow test_filesystem_fscontext_t test_file_t:dir { mounton write remove_name rmdir };
> +# Create test file
> +allow test_filesystem_fscontext_t self:dir { add_name write };
> +allow test_filesystem_fscontext_t self:file { create relabelfrom relabelto };
> +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { relabelto };
> +allow test_filesystem_filecon_t test_filesystem_fscontext_t:filesystem { associate };
> +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { open getattr read write };
> +
> +fs_mount_all_fs(test_filesystem_fscontext_t)
> +fs_unmount_all_fs(test_filesystem_fscontext_t)
> +fs_relabelfrom_all_fs(test_filesystem_fscontext_t)
> +files_search_all(test_filesystem_fscontext_t)
> +
> +########### Test context=, rootcontext= and defcontext #################
> +type test_filesystem_context_t;
> +domain_type(test_filesystem_context_t)
> +unconfined_runs_test(test_filesystem_context_t)
> +typeattribute test_filesystem_context_t testdomain;
> +typeattribute test_filesystem_context_t filesystemdomain;
> +
> +allow test_filesystem_context_t self:capability { sys_admin };
> +allow test_filesystem_context_t self:filesystem { associate mount relabelfrom relabelto unmount };
> +allow test_filesystem_context_t self:dir { mounton add_name write };
> +allow test_filesystem_context_t test_file_t:dir { mounton write remove_name rmdir };
> +# Create test file
> +allow test_filesystem_context_t self:dir { add_name write };
> +allow test_filesystem_context_t self:file { create relabelfrom relabelto };
> +allow test_filesystem_context_t test_filesystem_filecon_t:file { open getattr read write relabelto };
> +allow test_filesystem_filecon_t test_filesystem_context_t:filesystem { associate };
> +
> +fs_mount_all_fs(test_filesystem_context_t)
> +fs_unmount_all_fs(test_filesystem_context_t)
> +fs_relabelfrom_all_fs(test_filesystem_context_t)
> +files_search_all(test_filesystem_context_t)
> +fs_associate(test_filesystem_context_t)
> +allow test_filesystem_context_t test_file_t:dir { add_name };
> +dontaudit test_filesystem_context_t kernel_t:process { setsched };
> +
> +# For testing rootcontext= Set mountpoint to unlabeled first
> +allow test_filesystem_context_t test_file_t:dir { relabelfrom };
> +allow test_filesystem_context_t unlabeled_t:dir { mounton relabelto };
> +
> +# For testing defcontext=
> +allow test_filesystem_context_t test_filesystem_filecon_t:dir { search };
> +allow test_filesystem_fscontext_t test_filesystem_context_t:dir { add_name search write };
> +allow test_filesystem_fscontext_t test_filesystem_context_t:file { create getattr open write };
> +dontaudit unconfined_t test_filesystem_filecon_t:dir { read search };
> +
> +#
> +########### Allow these domains to be entered from sysadm domain ############
> +#
> +miscfiles_domain_entry_test_files(filesystemdomain)
> +userdom_sysadm_entry_spec_domtrans_to(filesystemdomain)
> diff --git a/tests/Makefile b/tests/Makefile
> index e19ea2f..a1478f1 100644
> --- a/tests/Makefile
> +++ b/tests/Makefile
> @@ -91,6 +91,13 @@ ifeq ($(shell grep -q lockdown $(POLDEV)/include/support/all_perms.spt && echo t
>   SUBDIRS += lockdown
>   endif
>   
> +ifeq ($(shell grep -q filesystem $(POLDEV)/include/support/all_perms.spt && echo true),true)
> +SUBDIRS += filesystem
> +ifeq ($(shell grep -q all_filesystem_perms.*watch $(POLDEV)/include/support/all_perms.spt && echo true),true)
> +export CFLAGS += -DHAVE_FS_WATCH_PERM
> +endif
> +endif
> +
>   ifeq ($(DISTRO),RHEL4)
>       SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp_nosuid overlay unix_socket, $(SUBDIRS))
>   endif
> diff --git a/tests/filesystem/.gitignore b/tests/filesystem/.gitignore
> new file mode 100644
> index 0000000..5ac18d0
> --- /dev/null
> +++ b/tests/filesystem/.gitignore
> @@ -0,0 +1,11 @@
> +mount
> +umount
> +quotas_test
> +statfs_test
> +fanotify_fs
> +create_file_change_context
> +fs_relabel
> +check_file_context
> +check_mount_context
> +create_file
> +grim_reaper
> diff --git a/tests/filesystem/Makefile b/tests/filesystem/Makefile
> new file mode 100644
> index 0000000..d2fad63
> --- /dev/null
> +++ b/tests/filesystem/Makefile
> @@ -0,0 +1,16 @@
> +# Required for local building
> +#export CFLAGS += -DHAVE_FS_WATCH_PERM
> +
> +TARGETS = mount umount quotas_test statfs_test create_file_change_context \
> +fs_relabel check_file_context grim_reaper check_mount_context create_file
> +
> +LDLIBS += -lselinux
> +
> +ifneq (,$(findstring -DHAVE_FS_WATCH_PERM,$(CFLAGS)))
> +	TARGETS += fanotify_fs
> +endif
> +
> +all: $(TARGETS)
> +
> +clean:
> +	rm -f $(TARGETS)
> diff --git a/tests/filesystem/check_file_context.c b/tests/filesystem/check_file_context.c
> new file mode 100644
> index 0000000..1380f16
> --- /dev/null
> +++ b/tests/filesystem/check_file_context.c
> @@ -0,0 +1,75 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <linux/unistd.h>
> +#include <selinux/selinux.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-v] -f -e -n\n"
> +		"Where:\n\t"
> +		"-f  File to check its context\n\t"
> +		"-e  Expected context\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int opt, result, fd;
> +	char *context = NULL, *expected = NULL, *file = NULL;
> +	bool verbose = false;
> +
> +	while ((opt = getopt(argc, argv, "f:e:v")) != -1) {
> +		switch (opt) {
> +		case 'f':
> +			file = optarg;
> +			break;
> +		case 'e':
> +			expected = optarg;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!file || !expected)
> +		print_usage(argv[0]);
> +
> +	fd = open(file, O_RDWR);
> +	if (fd < 0) {
> +		fprintf(stderr, "open(2) Failed: %s\n", strerror(errno));
> +		return -1;
> +	}
> +
> +	result = fgetfilecon(fd, &context);
> +	if (result < 0) {
> +		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> +			strerror(errno));
> +		result = -1;
> +		goto err;
> +	}
> +	result = 0;
> +
> +	if (strcmp(expected, context)) {
> +		fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n",
> +			expected, context);
> +		result = -1;
> +	} else {
> +		if (verbose)
> +			printf("Pass - File contexts match: %s\n", context);
> +	}
> +err:
> +	free(context);
> +	close(fd);
> +
> +	return result;
> +}
> diff --git a/tests/filesystem/check_mount_context.c b/tests/filesystem/check_mount_context.c
> new file mode 100644
> index 0000000..dbe0fb8
> --- /dev/null
> +++ b/tests/filesystem/check_mount_context.c
> @@ -0,0 +1,109 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <linux/unistd.h>
> +#include <selinux/selinux.h>
> +#include <selinux/context.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-v] -m [-e] -r\n"
> +		"Where:\n\t"
> +		"-m  Mountpoint\n\t"
> +		"-e  Expected MP context\n\t"
> +		"-r  Reset MP context to 'unlabeled_t'\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int opt, result, save_err;
> +	char *context = NULL, *expected = NULL, *mount = NULL, *newcon = NULL;
> +	bool verbose = false, reset = false;
> +	const char *type = "unlabeled_t";
> +	context_t con_t;
> +
> +	while ((opt = getopt(argc, argv, "m:e:rv")) != -1) {
> +		switch (opt) {
> +		case 'm':
> +			mount = optarg;
> +			break;
> +		case 'e':
> +			expected = optarg;
> +			break;
> +		case 'r':
> +			reset = true;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!mount)
> +		print_usage(argv[0]);
> +
> +	result = getfilecon(mount, &context);
> +	if (result < 0) {
> +		fprintf(stderr, "getfilecon(3) Failed: %s\n", strerror(errno));
> +		result = -1;
> +		goto err;
> +	}
> +	if (verbose)
> +		printf("Current MP context: %s\n", context);
> +
> +	result = 0;
> +
> +	if (reset) {
> +		/* Set context to unlabeled_t */
> +		con_t = context_new(context);
> +		if (!con_t) {
> +			fprintf(stderr, "Unable to create context structure\n");
> +			exit(-1);
> +		}
> +
> +		if (context_type_set(con_t, type)) {
> +			fprintf(stderr, "Unable to set new type\n");
> +			exit(-1);
> +		}
> +
> +		newcon = context_str(con_t);
> +		if (!newcon) {
> +			fprintf(stderr, "Unable to obtain new context string\n");
> +			exit(-1);
> +		}
> +
> +		result = setfilecon(mount, newcon);
> +		save_err = errno;
> +		if (result < 0) {
> +			fprintf(stderr, "setfilecon(3) Failed: %s\n",
> +				strerror(errno));
> +			result = save_err;
> +			goto err;
> +		}
> +		if (verbose)
> +			printf("Set new MP context: %s\n", newcon);
> +	} else {
> +		if (strcmp(expected, context)) {
> +			fprintf(stderr, "Mount context error, expected:\n\t%s\ngot:\n\t%s\n",
> +				expected, context);
> +			result = -1;
> +		} else {
> +			if (verbose)
> +				printf("Pass - Mountpoint contexts match: %s\n",
> +				       context);
> +		}
> +	}
> +
> +err:
> +	free(context);
> +	return result;
> +}
> diff --git a/tests/filesystem/create_file.c b/tests/filesystem/create_file.c
> new file mode 100644
> index 0000000..3d73067
> --- /dev/null
> +++ b/tests/filesystem/create_file.c
> @@ -0,0 +1,79 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <sys/types.h>
> +#include <linux/unistd.h>
> +#include <selinux/selinux.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-v] -f\n"
> +		"Where:\n\t"
> +		"-f  File to create\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int opt, result, fd, save_err;
> +	char *context, *file = NULL;
> +	bool verbose = false;
> +
> +	while ((opt = getopt(argc, argv, "f:v")) != -1) {
> +		switch (opt) {
> +		case 'f':
> +			file = optarg;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!file)
> +		print_usage(argv[0]);
> +
> +	if (verbose) {
> +		result = getcon(&context);
> +		if (result < 0) {
> +			fprintf(stderr, "Failed to obtain process context\n");
> +			exit(-1);
> +		}
> +		printf("Process context:\n\t%s\n", context);
> +		free(context);
> +	}
> +
> +	fd = creat(file, O_RDWR);
> +	save_err = errno;
> +	if (fd < 0) {
> +		fprintf(stderr, "creat(2) Failed: %s\n", strerror(errno));
> +		return save_err;
> +	}
> +
> +	context = NULL;
> +	result = fgetfilecon(fd, &context);
> +	if (result < 0) {
> +		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> +			strerror(errno));
> +		result = -1;
> +		goto err;
> +	}
> +	result = 0;
> +
> +	if (verbose)
> +		printf("File context is: %s\n", context);
> +
> +err:
> +	free(context);
> +	close(fd);
> +
> +	return result;
> +}
> diff --git a/tests/filesystem/create_file_change_context.c b/tests/filesystem/create_file_change_context.c
> new file mode 100644
> index 0000000..2a3b995
> --- /dev/null
> +++ b/tests/filesystem/create_file_change_context.c
> @@ -0,0 +1,143 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <linux/unistd.h>
> +#include <selinux/selinux.h>
> +#include <selinux/context.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-v] -t -f\n"
> +		"Where:\n\t"
> +		"-t  Type for context of created file\n\t"
> +		"-f  File to create\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int opt, result, fd, save_err;
> +	char *context, *newfcon, *orgfcon, *type = NULL, *file = NULL;
> +	bool verbose = false;
> +	context_t con_t;
> +
> +	while ((opt = getopt(argc, argv, "t:f:v")) != -1) {
> +		switch (opt) {
> +		case 't':
> +			type = optarg;
> +			break;
> +		case 'f':
> +			file = optarg;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!type || !file)
> +		print_usage(argv[0]);
> +
> +	result = getcon(&context);
> +	if (result < 0) {
> +		fprintf(stderr, "Failed to obtain process context\n");
> +		exit(-1);
> +	}
> +
> +	/* Build new file context */
> +	con_t = context_new(context);
> +	if (!con_t) {
> +		fprintf(stderr, "Unable to create context structure\n");
> +		exit(-1);
> +	}
> +
> +	if (context_type_set(con_t, type)) {
> +		fprintf(stderr, "Unable to set new type\n");
> +		exit(-1);
> +	}
> +
> +	newfcon = context_str(con_t);
> +	if (!newfcon) {
> +		fprintf(stderr, "Unable to obtain new context string\n");
> +		exit(-1);
> +	}
> +
> +	if (verbose) {
> +		printf("Process context:\n\t%s\n", context);
> +		printf("is creating test file:\n\t%s\n", file);
> +		printf("and changing its context to:\n\t%s\n", newfcon);
> +	}
> +
> +	free(context);
> +	context = NULL;
> +
> +	/* hooks.c may_create() FILESYSTEM__ASSOCIATE */
> +	fd = creat(file, O_RDWR);
> +	save_err = errno;
> +	if (fd < 0) {
> +		fprintf(stderr, "creat(2) Failed: %s\n", strerror(errno));
> +		result = save_err;
> +		goto err;
> +	}
> +
> +	result = fgetfilecon(fd, &orgfcon);
> +	if (result < 0) {
> +		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> +			strerror(errno));
> +		result = -1;
> +		goto err;
> +	}
> +
> +	if (verbose)
> +		printf("Current test file context is: %s\n", orgfcon);
> +
> +	free(orgfcon);
> +
> +	/* hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE */
> +	result = fsetfilecon(fd, newfcon);
> +	save_err = errno;
> +	if (result < 0) {
> +		fprintf(stderr, "fsetfilecon(3) Failed: %s\n",
> +			strerror(errno));
> +		result = save_err;
> +		goto err;
> +	}
> +
> +	fd = open(file, O_RDWR);
> +	if (fd < 0) {
> +		fprintf(stderr, "open(2) Failed: %s\n", strerror(errno));
> +		result = -1;
> +	}
> +
> +	result = fgetfilecon(fd, &context);
> +	if (result < 0) {
> +		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> +			strerror(errno));
> +		result = -1;
> +		goto err;
> +	}
> +
> +	if (verbose)
> +		printf("New test file context is: %s\n", context);
> +
> +	result = 0;
> +	if (strcmp(newfcon, context)) {
> +		fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n",
> +			newfcon, context);
> +		result = -1;
> +	}
> +err:
> +	free(context);
> +	free(newfcon);
> +	close(fd);
> +
> +	return result;
> +}
> diff --git a/tests/filesystem/fanotify_fs.c b/tests/filesystem/fanotify_fs.c
> new file mode 100644
> index 0000000..1f8f165
> --- /dev/null
> +++ b/tests/filesystem/fanotify_fs.c
> @@ -0,0 +1,79 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <sys/fanotify.h>
> +#include <selinux/selinux.h>
> +
> +#ifndef FAN_MARK_FILESYSTEM
> +#define FAN_MARK_FILESYSTEM	0x00000100
> +#endif
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-v] -t\n"
> +		"Where:\n\t"
> +		"-t  Target path\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int mask = FAN_OPEN, flags = FAN_MARK_ADD | FAN_MARK_FILESYSTEM;
> +	int fd, result, opt, save_err;
> +	char *context, *tgt = NULL;
> +	bool verbose = false;
> +
> +	while ((opt = getopt(argc, argv, "t:v")) != -1) {
> +		switch (opt) {
> +		case 't':
> +			tgt = optarg;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!tgt)
> +		print_usage(argv[0]);
> +
> +	if (verbose) {
> +		result = getcon(&context);
> +		if (result < 0) {
> +			fprintf(stderr, "Failed to obtain process context\n");
> +			exit(-1);
> +		}
> +		printf("Process context:\n\t%s\n", context);
> +		free(context);
> +	}
> +
> +	fd = fanotify_init(FAN_CLASS_CONTENT, O_RDWR);
> +	if (fd < 0) {
> +		fprintf(stderr, "fanotify_init(2) Failed: %s\n",
> +			strerror(errno));
> +		exit(-1);
> +	}
> +
> +	result = fanotify_mark(fd, flags, mask, AT_FDCWD, tgt);
> +	save_err = errno;
> +	if (result < 0) {
> +		fprintf(stderr, "fanotify_mark(2) Failed: %s\n",
> +			strerror(errno));
> +		close(fd);
> +		return save_err;
> +	}
> +
> +	if (verbose)
> +		printf("Set fanotify_mark(2) on filesystem: %s\n", tgt);
> +
> +	close(fd);
> +	return 0;
> +}
> diff --git a/tests/filesystem/fs_relabel.c b/tests/filesystem/fs_relabel.c
> new file mode 100644
> index 0000000..25b1781
> --- /dev/null
> +++ b/tests/filesystem/fs_relabel.c
> @@ -0,0 +1,72 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <linux/unistd.h>
> +#include <selinux/selinux.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-v] -n\n"
> +		"Where:\n\t"
> +		"-n  New fs context\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int opt, result, save_err;
> +	char *context, *fscreate_con, *newcon = NULL;
> +	bool verbose = false;
> +
> +	while ((opt = getopt(argc, argv, "n:v")) != -1) {
> +		switch (opt) {
> +		case 'n':
> +			newcon = optarg;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!newcon)
> +		print_usage(argv[0]);
> +
> +	if (verbose) {
> +		result = getcon(&context);
> +		if (result < 0) {
> +			fprintf(stderr, "Failed to obtain process context\n");
> +			exit(-1);
> +		}
> +		printf("Process context:\n\t%s\n", context);
> +		free(context);
> +	}
> +
> +	result = setfscreatecon(newcon);
> +	save_err = errno;
> +	if (result < 0) {
> +		fprintf(stderr, "Failed setfscreatecon(3): %s\n",
> +			strerror(errno));
> +		return save_err;
> +	}
> +
> +	result = getfscreatecon(&fscreate_con);
> +	if (result < 0) {
> +		fprintf(stderr, "Failed getfscreatecon(3): %s\n",
> +			strerror(errno));
> +		exit(-1);
> +	}
> +	if (verbose)
> +		printf("New fscreate context: %s\n", fscreate_con);
> +
> +	free(fscreate_con);
> +	return 0;
> +}
> diff --git a/tests/filesystem/grim_reaper.c b/tests/filesystem/grim_reaper.c
> new file mode 100644
> index 0000000..0105ab6
> --- /dev/null
> +++ b/tests/filesystem/grim_reaper.c
> @@ -0,0 +1,63 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <sys/mount.h>
> +#include <selinux/selinux.h>
> +
> +#define WAIT_COUNT 60
> +#define USLEEP_TIME 10000
> +
> +/* Remove any mounts associated with the loop device in argv[1] */
> +int main(int argc, char *argv[])
> +{
> +	FILE *fp;
> +	size_t len;
> +	ssize_t num;
> +	int index = 0, i, result = 0;
> +	char *mount_info[2];
> +	char *buf = NULL, *item;
> +
> +	if (!argv[1])
> +		return -1;
> +
> +	fp = fopen("/proc/mounts", "re");
> +	if (!fp) {
> +		fprintf(stderr, "Failed to open /proc/mounts: %s\n",
> +			strerror(errno));
> +		return -1;
> +	}
> +
> +	while ((num = getline(&buf, &len, fp)) != -1) {
> +		index = 0;
> +		item = strtok(buf, " ");
> +		while (item != NULL) {
> +			mount_info[index] = item;
> +			index++;
> +			if (index == 2)
> +				break;
> +			item = strtok(NULL, " ");
> +		}
> +
> +		if (strcmp(mount_info[0], argv[1]) == 0) {
> +			for (i = 0; i < WAIT_COUNT; i++) {
> +				result = umount(mount_info[1]);
> +				if (!result)
> +					break;
> +
> +				if (errno != EBUSY) {
> +					fprintf(stderr, "Failed umount(2): %s\n",
> +						strerror(errno));
> +					break;
> +				}
> +				usleep(USLEEP_TIME);
> +			}
> +		}
> +	}
> +
> +	free(buf);
> +	fclose(fp);
> +	return result;
> +}
> diff --git a/tests/filesystem/mount.c b/tests/filesystem/mount.c
> new file mode 100644
> index 0000000..034f0ec
> --- /dev/null
> +++ b/tests/filesystem/mount.c
> @@ -0,0 +1,130 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <sys/mount.h>
> +#include <selinux/selinux.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-s src] -t tgt [-f fs_type] [-o options] [-bmprv]\n"
> +		"Where:\n\t"
> +		"-s  Source path\n\t"
> +		"-t  Target path\n\t"
> +		"-f  Filesystem type\n\t"
> +		"-o  Options list (comma separated list)\n\t"
> +		"Zero or one of the following flags:\n\t"
> +		"\t-b  MS_BIND\n\t"
> +		"\t-m  MS_MOVE\n\t"
> +		"\t-p  MS_PRIVATE\n\t"
> +		"\t-r  MS_REMOUNT\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +static int ck_mount(char *mntpoint)
> +{
> +	int result = 0;
> +	FILE *fp;
> +	size_t len;
> +	ssize_t num;
> +	char *buf = NULL;
> +
> +	fp = fopen("/proc/mounts", "re");
> +	if (fp == NULL) {
> +		fprintf(stderr, "Failed to open /proc/mounts: %s\n",
> +			strerror(errno));
> +		return -1;
> +	}
> +
> +	while ((num = getline(&buf, &len, fp)) != -1) {
> +		if (strstr(buf, mntpoint) != NULL) {
> +			result = 1;
> +			break;
> +		}
> +	}
> +
> +	free(buf);
> +	fclose(fp);
> +	return result;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int opt, result, save_err, flags = 0;
> +	char *context, *src = NULL, *tgt = NULL, *fs_type = NULL, *opts = NULL;
> +	bool verbose = false;
> +
> +	while ((opt = getopt(argc, argv, "s:t:f:o:pbmrv")) != -1) {
> +		switch (opt) {
> +		case 's':
> +			src = optarg;
> +			break;
> +		case 't':
> +			tgt = optarg;
> +			break;
> +		case 'f':
> +			fs_type = optarg;
> +			break;
> +		case 'o':
> +			opts = optarg;
> +			break;
> +		case 'b':
> +			flags = MS_BIND;
> +			break;
> +		case 'p':
> +			flags = MS_PRIVATE;
> +			break;
> +		case 'm':
> +			flags = MS_MOVE;
> +			break;
> +		case 'r':
> +			flags = MS_REMOUNT;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!tgt)
> +		print_usage(argv[0]);
> +
> +	if (verbose) {
> +		result = getcon(&context);
> +		if (result < 0) {
> +			fprintf(stderr, "Failed to obtain process context\n");
> +			return -1;
> +		}
> +		printf("Process context:\n\t%s\n", context);
> +		free(context);
> +	}
> +
> +	if (verbose)
> +		printf("Mounting\n\tsrc: %s\n\ttgt: %s\n\tfs_type: %s flags: 0x%x\n\topts: %s\n",
> +		       src, tgt, fs_type, flags, opts);
> +
> +	result = mount(src, tgt, fs_type, flags, opts);
> +	save_err = errno;
> +	if (result < 0) {
> +		fprintf(stderr, "Failed mount(2): %s\n", strerror(errno));
> +		return save_err;
> +	}
> +
> +	if (flags == MS_MOVE) {
> +		if (!ck_mount(src) && ck_mount(tgt)) {
> +			if (verbose)
> +				printf("MS_MOVE: Moved mountpoint\n");
> +		} else {
> +			fprintf(stderr, "MS_MOVE: Move mountpoint failed\n");
> +			return -1;
> +		}
> +	}
> +
> +	return 0;
> +}
> diff --git a/tests/filesystem/quotas_test.c b/tests/filesystem/quotas_test.c
> new file mode 100644
> index 0000000..34aaca9
> --- /dev/null
> +++ b/tests/filesystem/quotas_test.c
> @@ -0,0 +1,134 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <sys/quota.h>
> +#include <selinux/selinux.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s -s src -t tgt\n"
> +		"Where:\n\t"
> +		"-s  Source path (e.g. /dev/loop0)\n\t"
> +		"-t  Target quota file (Full path with either 'aquota.user'\n\t"
> +		"    or 'aquota.group' appended)\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int opt, result, qcmd, save_err, test_id = geteuid();
> +	char *context, *src = NULL, *tgt = NULL;
> +	bool verbose = false;
> +	char fmt_buf[2];
> +
> +	while ((opt = getopt(argc, argv, "s:t:v")) != -1) {
> +		switch (opt) {
> +		case 's':
> +			src = optarg;
> +			break;
> +		case 't':
> +			tgt = optarg;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!src || !tgt)
> +		print_usage(argv[0]);
> +
> +	if (verbose) {
> +		result = getcon(&context);
> +		if (result < 0) {
> +			fprintf(stderr, "Failed to obtain process context\n");
> +			return -1;
> +		}
> +		printf("Process context:\n\t%s\n", context);
> +		free(context);
> +	}
> +
> +	if (strstr(tgt, "aquota.user") != NULL) {
> +		qcmd = QCMD(Q_QUOTAON, USRQUOTA);
> +		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> +		save_err = errno;
> +		if (result < 0) {
> +			fprintf(stderr, "quotactl(Q_QUOTAON, USRQUOTA) Failed: %s\n",
> +				strerror(errno));
> +			return save_err;
> +		}
> +		if (verbose)
> +			printf("User Quota - ON\n");
> +
> +		qcmd = QCMD(Q_GETFMT, USRQUOTA);
> +		result = quotactl(qcmd, src, test_id, fmt_buf);
> +		save_err = errno;
> +		if (result < 0) {
> +			fprintf(stderr, "quotactl(Q_GETFMT, USRQUOTA) Failed: %s\n",
> +				strerror(errno));
> +			return save_err;
> +		}
> +		if (verbose)
> +			printf("User Format: 0x%x\n", fmt_buf[0]);
> +
> +		qcmd = QCMD(Q_QUOTAOFF, USRQUOTA);
> +		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> +		save_err = errno;
> +		if (result < 0) {
> +			fprintf(stderr, "quotactl(Q_QUOTAOFF, USRQUOTA) Failed: %s\n",
> +				strerror(errno));
> +			return save_err;
> +		}
> +		if (verbose)
> +			printf("User Quota - OFF\n");
> +
> +		return 0;
> +
> +	} else if (strstr(tgt, "aquota.group") != NULL) {
> +		qcmd = QCMD(Q_QUOTAON, GRPQUOTA);
> +		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> +		save_err = errno;
> +		if (result < 0) {
> +			fprintf(stderr, "quotactl(Q_QUOTAON, GRPQUOTA) Failed: %s\n",
> +				strerror(errno));
> +			return save_err;
> +		}
> +		if (verbose)
> +			printf("Group Quota - ON\n");
> +
> +		qcmd = QCMD(Q_GETFMT, GRPQUOTA);
> +		result = quotactl(qcmd, src, test_id, fmt_buf);
> +		save_err = errno;
> +		if (result < 0) {
> +			fprintf(stderr, "quotactl(Q_GETFMT, GRPQUOTA) Failed: %s\n",
> +				strerror(errno));
> +			return save_err;
> +		}
> +		if (verbose)
> +			printf("Group Format: 0x%x\n", fmt_buf[0]);
> +
> +		qcmd = QCMD(Q_QUOTAOFF, GRPQUOTA);
> +		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> +		save_err = errno;
> +		if (result < 0) {
> +			fprintf(stderr, "quotactl(Q_QUOTAOFF, GRPQUOTA) Failed: %s\n",
> +				strerror(errno));
> +			return save_err;
> +		}
> +		if (verbose)
> +			printf("Group Quota - OFF\n");
> +
> +		return 0;
> +	}
> +
> +	fprintf(stderr, "Required %s to specify 'aquota.user' or 'aquota.group' file\n",
> +		tgt);
> +	return -1;
> +}
> diff --git a/tests/filesystem/statfs_test.c b/tests/filesystem/statfs_test.c
> new file mode 100644
> index 0000000..5de49b1
> --- /dev/null
> +++ b/tests/filesystem/statfs_test.c
> @@ -0,0 +1,65 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <sys/statfs.h>
> +#include <selinux/selinux.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-v] -t\n"
> +		"Where:\n\t"
> +		"-t  Target path\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int opt, result, save_err;
> +	char *context, *tgt = NULL;
> +	bool verbose = false;
> +	struct statfs statfs_t;
> +
> +	while ((opt = getopt(argc, argv, "t:v")) != -1) {
> +		switch (opt) {
> +		case 't':
> +			tgt = optarg;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!tgt)
> +		print_usage(argv[0]);
> +
> +	if (verbose) {
> +		result = getcon(&context);
> +		if (result < 0) {
> +			fprintf(stderr, "Failed to obtain process context\n");
> +			return -1;
> +		}
> +		printf("Process context:\n\t%s\n", context);
> +		free(context);
> +	}
> +
> +	result = statfs(tgt, &statfs_t);
> +	save_err = errno;
> +	if (result < 0) {
> +		fprintf(stderr, "statfs(2) Failed: %s\n", strerror(errno));
> +		return save_err;
> +	}
> +
> +	if (verbose)
> +		printf("statfs(2) returned magic filesystem: 0x%lx\n",
> +		       statfs_t.f_type);
> +
> +	return 0;
> +}
> diff --git a/tests/filesystem/test b/tests/filesystem/test
> new file mode 100755
> index 0000000..00c69e1
> --- /dev/null
> +++ b/tests/filesystem/test
> @@ -0,0 +1,830 @@
> +#!/usr/bin/perl
> +use Test::More;
> +
> +BEGIN {
> +    $basedir = $0;
> +    $basedir =~ s|(.*)/[^/]*|$1|;
> +
> +    $test_count = 63;
> +
> +    # Allow info to be shown.
> +    $v = $ARGV[0];
> +    if ($v) {
> +        if ( $v ne "-v" ) {
> +            plan skip_all => "Invalid option (use -v)";
> +        }
> +    }
> +    else {
> +        $v = " ";
> +    }
> +
> +    # From kernel 5.5 support for fanotify(7) with filesystem { watch }
> +    $kvercur = `uname -r`;
> +    chomp($kvercur);
> +    $kverminstream = "5.5";
> +
> +    $result = `$basedir/../kvercmp $kvercur $kverminstream`;
> +    if ( $result > 0 && -e "$basedir/fanotify_fs" ) {
> +        $test_watch = 1;
> +        $test_count += 4;
> +    }
> +
> +    plan tests => $test_count;
> +}
> +
> +# mount(2) MS_BIND | MS_PRIVATE requires an absolute path to a private mount
> +# point before MS_MOVE
> +$cwd = `pwd 2>/dev/null`;
> +chomp($cwd);
> +$private_path = "$cwd";
> +if ( $basedir eq "." ) {
> +    $private_path = "$cwd/mntpoint";
> +}
> +else {
> +    $private_path = "$cwd/$basedir/mntpoint";
> +}
> +
> +# Set initial filesystem type
> +$fs_type = "ext4";
> +
> +# For list of devices used
> +$device_count = 0;
> +
> +sub get_loop_dev {
> +    print "Finding free /dev/loop entry\n";
> +    $dev = `losetup -f 2>/dev/null`;
> +    chomp($dev);
> +    if ( $dev eq "" ) {
> +        print "losetup failed to obtain /dev/loop entry\n";
> +        cleanup();
> +        exit -1;
> +    }
> +
> +    # Keep list of devices for cleanup later
> +    if ( $device_count eq 0 ) {
> +        $device_list[$device_count] = $dev;
> +        $device_count += 1;
> +    }
> +    elsif ( $dev ne $device_list[ $device_count - 1 ] ) {
> +        $device_list[$device_count] = $dev;
> +        $device_count += 1;
> +    }
> +}
> +
> +sub attach_dev {
> +    print "Attaching $basedir/fstest to $dev\n";
> +    $result = system("losetup $dev $basedir/fstest 2>/dev/null");
> +    if ( $result != 0 ) {
> +        print "Failed to attach $basedir/fstest to $dev\n";
> +        cleanup();
> +        exit -1;
> +    }
> +}
> +
> +sub make_fs {
> +    my ($mk_type) = @_;
> +
> +    get_loop_dev();
> +
> +    if ( $mk_type eq "tmpfs" ) {
> +        return;
> +    }
> +
> +    print "Create $basedir/fstest with dd\n";
> +    $result = system(
> +        "dd if=/dev/zero of=$basedir/fstest bs=1024 count=10240 2>/dev/null");
> +    if ( $result != 0 ) {
> +        print "dd failed to create fstest\n";
> +        exit -1;
> +    }
> +
> +    attach_dev();
> +
> +    print "Make $mk_type filesystem on $dev\n";
> +    $result = system("mkfs.$mk_type $dev >& /dev/null");
> +    if ( $result != 0 ) {
> +        system("losetup -d $dev 2>/dev/null");
> +        cleanup();
> +        print "mkfs.$mk_type failed to create filesystem on $dev\n";
> +        exit -1;
> +    }
> +}
> +
> +sub mk_mntpoint_1 {
> +    system("rm -rf $private_path/mp1 2>/dev/null");
> +    system("mkdir -p $private_path/mp1 2>/dev/null");
> +}
> +
> +sub mk_mntpoint_2 {
> +    system("rm -rf $private_path/mp2 2>/dev/null");
> +    system("mkdir -p $private_path/mp2 2>/dev/null");
> +}
> +
> +sub cleanup {
> +    system("rm -rf $basedir/fstest 2>/dev/null");
> +    system("rm -rf $basedir/mntpoint 2>/dev/null");
> +}
> +
> +sub cleanup1 {
> +    system("losetup -d $dev 2>/dev/null");
> +    system("rm -rf $basedir/fstest 2>/dev/null");
> +    system("rm -rf $basedir/mntpoint 2>/dev/null");
> +}
> +
> +############### Test setfscreatecon(3) ##########################
> +print "Test setfscreatecon(3)\n";
> +$result = system
> +"runcon -t test_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0";
> +ok( $result eq 0 );
> +
> +$result = system
> +"runcon -t test_no_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0 2>&1";
> +ok( $result >> 8 eq 13 );
> +
> +############### Test Basic Mount/Unmount ##########################
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +$mount_opts1 =
> +  "quota,usrquota,grpquota,defcontext=system_u:object_r:test_filesystem_t:s0";
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$mount_opts1\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Then remount\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/mount -r -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Running quotacheck(8) to init user/group quota files\n";
> +$result = system("quotacheck -ugF vfsv0 $private_path/mp1");
> +ok( $result eq 0 );
> +
> +print "Toggle User & Group quotas on/off\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v"
> +);
> +ok( $result eq 0 );
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.group $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Get statfs(2)\n";
> +$result =
> +  system(
> +    "runcon -t test_filesystem_t $basedir/statfs_test -t $basedir/mntpoint $v");
> +ok( $result eq 0 );
> +
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v"
> +  );
> +ok( $result eq 0 );
> +
> +if ($test_watch) {
> +    print "fanotify(7) test\n";
> +    $result = system(
> +"runcon -t test_filesystem_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1"
> +    );
> +    ok( $result eq 0 );
> +}
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp1 $v");
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Test Move Mount ##########################
> +make_fs($fs_type);
> +$mount_opts2 =
> +  "quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_t:s0";
> +system("mkdir -p $private_path 2>/dev/null");
> +
> +print "Set mount MS_BIND on filesystem\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/mount -s $private_path -t $private_path -b $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Set mount MS_PRIVATE on filesystem\n";
> +$result =
> +  system("runcon -t test_filesystem_t $basedir/mount -t $private_path -p $v");
> +ok( $result eq 0 );
> +
> +mk_mntpoint_1();
> +mk_mntpoint_2();
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$mount_opts2\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts2 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Set mount MS_MOVE on filesystem\n";
> +$result = system(
> +"runcon -t test_filesystem_t $basedir/mount -s $private_path/mp1 -t $private_path/mp2 -m  $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp2\n";
> +$result =
> +  system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp2 $v");
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint\n";
> +$result =
> +  system("runcon -t test_filesystem_t $basedir/umount -t $private_path $v");
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { relabelfrom } ##########################
> +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM
> +
> +$opts_no_relabelfrom =
> +"defcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0,fscontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_relabelfrom\n";
> +$result = system(
> +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { relabelto } ##########################
> +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO
> +
> +$opts_no_relabelto =
> +  "fscontext=system_u:object_r:test_filesystem_no_relabelto_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_relabelto\n";
> +$result = system(
> +"runcon -t test_filesystem_no_relabelto_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelto $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { relabelfrom } ##########################
> +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM
> +
> +$opts_no_relabelfrom =
> +  "rootcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_relabelfrom\n";
> +$result = system(
> +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { associate } ##########################
> +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE
> +
> +$opts_no_associate =
> +"defcontext=system_u:object_r:test_filesystem_no_associate_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_associate\n";
> +$result = system(
> +"runcon -t test_filesystem_no_associate_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { associate } ##########################
> +# hooks.c may_create() FILESYSTEM__ASSOCIATE
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +$opts_no_associate_file =
> +  "fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0";
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_associate_file\n";
> +$result = system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1"
> +  );
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { quotamod } ##########################
> +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD
> +
> +$opts_no_quotamod =
> +"quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesystem_no_quotamod_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +system("mkdir -p $private_path 2>/dev/null");
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_quotamod\n";
> +$result = system(
> +"runcon -t test_filesystem_no_quotamod_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotamod $v 2>&1"
> +);
> +ok( $result eq 0 );
> +
> +# No need to run quotacheck(8) as never gets far enough to read quota file
> +print "Toggle User & Group quotas on/off\n";    # Must have full path
> +$result = system(
> +"runcon -t test_filesystem_no_quotamod_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_no_quotamod_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { quotaget } ##########################
> +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET
> +
> +$opts_no_quotaget =
> +"quota,usrquota,grpquota,context=system_u:object_r:test_filesystem_no_quotaget_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_quotaget\n";
> +$result = system(
> +"runcon -t test_filesystem_no_quotaget_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotaget $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Running quotacheck(8) to init user/group quota files\n";
> +$result = system("quotacheck -ugF vfsv0 $private_path/mp1");
> +ok( $result eq 0 );
> +
> +print "Toggle User & Group quotas on/off\n";    # Must have full path
> +$result = system(
> +"runcon -t test_filesystem_no_quotaget_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_no_quotaget_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { mount } ##########################
> +# hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT
> +
> +$opts_no_mount = "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_mount\n";
> +$result = system(
> +"runcon -t test_filesystem_no_mount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_mount $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { getattr } ##########################
> +# hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR
> +
> +$opts_no_getattr =
> +  "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_getattr\n";
> +$result = system(
> +"runcon -t test_filesystem_no_getattr_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_getattr $v"
> +);
> +ok( $result eq 0 );
> +
> +$result = system(
> +"runcon -t test_filesystem_no_getattr_t $basedir/statfs_test -t $basedir/mntpoint $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_no_getattr_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { remount } ##########################
> +# hooks.c selinux_mount() FILESYSTEM__REMOUNT
> +
> +$opts_no_remount =
> +  "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_remount\n";
> +$result = system(
> +"runcon -t test_filesystem_no_remount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Then remount\n";
> +$result = system(
> +"runcon -t test_filesystem_no_remount_t $basedir/mount -r -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_no_remount_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { unmount } ##########################
> +# hooks.c selinux_umount() FILESYSTEM__UNMOUNT
> +
> +$opts_no_unmount =
> +  "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0";
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_unmount\n";
> +$result = system(
> +"runcon -t test_filesystem_no_unmount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_unmount $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_no_unmount_t $basedir/umount -t $basedir/mntpoint/mp1 $v 2>&1"
> +);
> +ok( $result >> 8 eq 13 );
> +
> +# Make sure it does get unmounted
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +    "runcon -t test_filesystem_t $basedir/umount -t $basedir/mntpoint/mp1 $v");
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { associate }  ##########################
> +# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +$opts_no_associate_file =
> +"defcontext=system_u:object_r:test_filesystem_no_associate_file_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0";
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_associate_file\n";
> +$result = system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1"
> +  );
> +ok( $result >> 8 eq 13 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +############### Deny filesystem { watch }  ##########################
> +# hooks.c selinux_path_notify() FILESYSTEM__WATCH
> +if ($test_watch) {
> +    cleanup();
> +    mk_mntpoint_1();
> +    make_fs($fs_type);
> +    $opts_no_watch = "context=system_u:object_r:test_filesystem_no_watch_t:s0";
> +
> +    print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +    print "Using mount options:\n\t$opts_no_watch\n";
> +    $result = system(
> +"runcon -t test_filesystem_no_watch_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_watch $v"
> +    );
> +    ok( $result eq 0 );
> +
> +    print "test_fanotify\n";
> +    $result = system(
> +"runcon -t test_filesystem_no_watch_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1 2>&1"
> +    );
> +    ok( $result >> 8 eq 13 );
> +
> +    print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +    $result = system(
> +"runcon -t test_filesystem_no_watch_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +    );
> +    ok( $result eq 0 );
> +
> +    print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +    cleanup1();
> +}
> +
> +##########################################################################
> +# context     - Useful when mounting filesystems that do not support extended
> +#               attributes.
> +#   Tested by - Creating a filesystem that has xattrs set to a different value,
> +#               then mount with context= and confirm that the files have that
> +#               context as well as any newly created files (even if fscreate
> +#               was set to something else), and that setfilecon/setxattr() on
> +#               files within the mount fails with errno EOPNOTSUPP.
> +##########################################################################
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +# Mount with xttrs to create a file with specific context.
> +$context1_opts = "defcontext=system_u:object_r:test_filesystem_context_t:s0";
> +
> +print "Testing 'context=' mount option\n";
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$context1_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context1_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +# Create file with 'test_filesystem_filecon_t' context
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +# Need to free the loop device, then get new dev one and attach
> +system("losetup -d $dev 2>/dev/null");
> +get_loop_dev();
> +attach_dev();
> +
> +# Mount again with no xttr support
> +$context2_opts = "context=system_u:object_r:test_filesystem_context_t:s0";
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$context2_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context2_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +# Now check the context on file is system_u:object_r:test_filesystem_context_t:s0
> +print "Check test file context $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/check_file_context -f $private_path/mp1/test_file -e system_u:object_r:test_filesystem_context_t:s0 $v"
> +  );
> +ok( $result eq 0 );
> +
> +# Then create a file with 'test_filesystem_filecon_t' context, this should fail with EOPNOTSUPP
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v 2>/dev/null"
> +  );
> +ok( $result >> 8 eq 95 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +##########################################################################
> +# rootcontext - Explicitly label the root inode of the filesystem being
> +#               mounted before that filesystem or inode becomes visible
> +#               to userspace.
> +#   Tested by - Set mountpoint to unlabeled_t and then check that the
> +#               context of the root directory matches rootcontext= after
> +#               the mount operation.
> +##########################################################################
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +$root_opts = "rootcontext=system_u:object_r:test_filesystem_context_t:s0";
> +
> +print "Testing 'rootcontext=' mount option\n";
> +
> +# Reset mountpoint to 'unlabeled_t' so it is different to any other possible test values.
> +print "Resetting MP to unlabeled_t $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/check_mount_context -r -m $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$root_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $root_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +# Now check the mountpoint is the 'rootcontext=' value
> +print "Check MP context $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/check_mount_context -m $basedir/mntpoint/mp1 -e system_u:object_r:test_filesystem_context_t:s0 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +##########################################################################
> +# defcontext  - Set default security context for unlabeled files.
> +#               This overrides the value set for unlabeled files in policy
> +#               and requires a filesystem that supports xattr labeling.
> +#   Tested by - Create filesystem that has files w/o xattrs and then confirm
> +#               that they are mapped to the specified defcontext upon mount,
> +#               where defcontext differs from the policy default.
> +##########################################################################
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +
> +$test_opts = "context=system_u:object_r:test_filesystem_context_t:s0";
> +
> +print "Testing 'defcontext=' mount option\n";
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$test_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $test_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +# Create file, its context will be system_u:object_r:test_filesystem_context_t:s0 from $test_opts
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -u system_u -t test_filesystem_fscontext_t $basedir/create_file -f $basedir/mntpoint/mp1/test_file $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +# Need to free the loop device, then get new dev one and attach
> +system("losetup -d $dev 2>/dev/null");
> +get_loop_dev();
> +attach_dev();
> +
> +# Mount again with defcontext=
> +$defcontext_opts = "defcontext=system_u:object_r:test_filesystem_filecon_t:s0";
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$defcontext_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $defcontext_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +# Now check the file context is now system_u:object_r:test_filesystem_filecon_t:s0
> +print "Check test file context $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/check_file_context -f $basedir/mntpoint/mp1/test_file -e system_u:object_r:test_filesystem_filecon_t:s0 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +##########################################################################
> +# fscontext   - Sets the overarching filesystem label to a specific security
> +#               context. This filesystem label is separate from the individual
> +#               labels on the files.
> +#   Tested by - Mount a tmpfs (fs_use_trans) filesystem with fscontext= and
> +#               then create a file within it, checking its context.
> +##########################################################################
> +$fs_type = "tmpfs";
> +cleanup();
> +mk_mntpoint_1();
> +make_fs($fs_type);
> +$fscontext_opts =
> +"fscontext=system_u:object_r:test_filesystem_fscontext_t:s0,size=10M,mode=0770";
> +
> +print "Testing 'fscontext=' mount option\n";
> +print "Mount tmpfs filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$fscontext_opts\n";
> +$result = system(
> +"runcon -t test_filesystem_fscontext_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $fscontext_opts $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_fscontext_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_fscontext_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1();
> +
> +# Cleanup any attached /dev/loop entries
> +foreach my $n (@device_list) {
> +    system("$basedir/grim_reaper $n 2>/dev/null");
> +}
> +
> +exit;
> diff --git a/tests/filesystem/umount.c b/tests/filesystem/umount.c
> new file mode 100644
> index 0000000..4a20448
> --- /dev/null
> +++ b/tests/filesystem/umount.c
> @@ -0,0 +1,84 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <stdbool.h>
> +#include <sys/mount.h>
> +#include <selinux/selinux.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s [-v] [-t]\n"
> +		"Where:\n\t"
> +		"-t  Target path\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +#define WAIT_COUNT 60
> +#define USLEEP_TIME 100000
> +
> +int main(int argc, char *argv[])
> +{
> +	char *context, *tgt = NULL;
> +	int opt, result, i, save_err;
> +	bool verbose = false;
> +
> +	while ((opt = getopt(argc, argv, "t:v")) != -1) {
> +		switch (opt) {
> +		case 't':
> +			tgt = optarg;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!tgt)
> +		print_usage(argv[0]);
> +
> +	if (verbose) {
> +		result = getcon(&context);
> +		if (result < 0) {
> +			fprintf(stderr, "Failed to obtain process context\n");
> +			exit(-1);
> +		}
> +		printf("Process context:\n\t%s\n", context);
> +		free(context);
> +	}
> +
> +	/*
> +	 * umount(2) will sometimes return EBUSY when other tasks are
> +	 * checking mounts so wait around before bailing out.
> +	 */
> +	for (i = 0; i < WAIT_COUNT; i++) {
> +		result = umount(tgt);
> +		save_err = errno;
> +		if (!result) {
> +			if (verbose)
> +				printf("Unmounted: %s\n", tgt);
> +
> +			return 0;
> +		}
> +
> +		if (verbose && save_err == EBUSY)
> +			printf("umount(2) returned EBUSY %d times\n", i + 1);
> +
> +		if (save_err != EBUSY) {
> +			fprintf(stderr, "Failed umount(2): %s\n",
> +				strerror(save_err));
> +			return save_err;
> +		}
> +		usleep(USLEEP_TIME);
> +	}
> +
> +	fprintf(stderr, "Failed to umount(2) after %d retries with: %s\n",
> +		WAIT_COUNT, strerror(save_err));
> +
> +	return save_err;
> +}
> 


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH 1/1] selinux-testsuite: Add filesystem tests
  2020-01-09 14:18   ` Stephen Smalley
@ 2020-01-09 17:33     ` Richard Haines
  0 siblings, 0 replies; 6+ messages in thread
From: Richard Haines @ 2020-01-09 17:33 UTC (permalink / raw)
  To: Stephen Smalley, selinux, Ondrej Mosnacek

On Thu, 2020-01-09 at 09:18 -0500, Stephen Smalley wrote:
> On 12/20/19 5:11 AM, Richard Haines wrote:
> > Test filesystem permissions and setfscreatecon(3).
> > 
> >  From kernels 5.5 filesystem { watch } is also tested.
> > 
> > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> 
> During the execution of these tests, I see the following kernel log
> spew:
> 
> <6>[  496.535286] loop: module loaded
> <6>[  498.180983] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts: quota,usrquota,grpquota
> <4>[  498.181535] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  498.225114] EXT4-fs (loop0): re-mounted. Opts:
> quota,usrquota,grpquota
> <4>[  498.225167] ext4 filesystem being remounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  498.284372] EXT4-fs (loop0): re-mounted. Opts: (null)
> <6>[  498.349328] EXT4-fs (loop0): re-mounted. Opts: (null)
> <4>[  498.349385] ext4 filesystem being remounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  500.582812] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts: quota,usrquota,grpquota
> <4>[  500.583071] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <3>[  501.030500] blk_update_request: I/O error, dev loop0, sector 0
> op 
> 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
> <3>[  501.030856] blk_update_request: I/O error, dev loop0, sector 0
> op 
> 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
> <6>[  502.557867] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <6>[  504.475061] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <6>[  506.366675] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <3>[  506.479705] blk_update_request: I/O error, dev loop0, sector 0
> op 
> 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
> <3>[  506.479925] blk_update_request: I/O error, dev loop0, sector 0
> op 
> 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
> <6>[  508.316818] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <3>[  508.526137] blk_update_request: I/O error, dev loop0, sector 0
> op 
> 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
> <3>[  508.526466] blk_update_request: I/O error, dev loop0, sector 0
> op 
> 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
> <6>[  510.241013] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <4>[  510.241323] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  511.867178] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts: quota,usrquota,grpquota
> <4>[  511.867442] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <3>[  512.521949] blk_update_request: I/O error, dev loop0, sector 0
> op 
> 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
> <3>[  512.525497] blk_update_request: I/O error, dev loop0, sector 0
> op 
> 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0
> <6>[  513.996580] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts: quota,usrquota,grpquota
> <4>[  513.996869] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  514.040984] EXT4-fs (loop0): re-mounted. Opts: (null)
> <6>[  514.065928] EXT4-fs (loop0): re-mounted. Opts: (null)
> <4>[  514.065950] ext4 filesystem being remounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  516.071775] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <6>[  518.001912] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <4>[  518.002294] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  519.450511] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <4>[  519.450737] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  521.579819] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <4>[  521.580225] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  523.874190] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <4>[  523.874526] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  525.559041] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <4>[  525.559423] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  526.541667] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <4>[  526.542194] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  528.760343] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <4>[  528.760704] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  530.463519] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <4>[  530.463823] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> <6>[  531.469358] EXT4-fs (loop0): mounted filesystem with ordered
> data 
> mode. Opts:
> <4>[  531.469779] ext4 filesystem being mounted at 
> /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports 
> timestamps until 2038 (0x7fffffff)
> 
> Wondering if all of that is expected and necessary for testing or if
> we 
> can get rid of some of the noise.

I'll see about stopping some of these in the next version.

> 
> > ---
> >   defconfig                                     |   6 +
> >   policy/Makefile                               |   4 +
> >   policy/test_filesystem.te                     | 324 +++++++
> >   tests/Makefile                                |   7 +
> >   tests/filesystem/.gitignore                   |  11 +
> >   tests/filesystem/Makefile                     |  16 +
> >   tests/filesystem/check_file_context.c         |  75 ++
> >   tests/filesystem/check_mount_context.c        | 109 +++
> >   tests/filesystem/create_file.c                |  79 ++
> >   tests/filesystem/create_file_change_context.c | 143 +++
> >   tests/filesystem/fanotify_fs.c                |  79 ++
> >   tests/filesystem/fs_relabel.c                 |  72 ++
> >   tests/filesystem/grim_reaper.c                |  63 ++
> >   tests/filesystem/mount.c                      | 130 +++
> >   tests/filesystem/quotas_test.c                | 134 +++
> >   tests/filesystem/statfs_test.c                |  65 ++
> >   tests/filesystem/test                         | 830
> > ++++++++++++++++++
> >   tests/filesystem/umount.c                     |  84 ++
> >   18 files changed, 2231 insertions(+)
> >   create mode 100644 policy/test_filesystem.te
> >   create mode 100644 tests/filesystem/.gitignore
> >   create mode 100644 tests/filesystem/Makefile
> >   create mode 100644 tests/filesystem/check_file_context.c
> >   create mode 100644 tests/filesystem/check_mount_context.c
> >   create mode 100644 tests/filesystem/create_file.c
> >   create mode 100644 tests/filesystem/create_file_change_context.c
> >   create mode 100644 tests/filesystem/fanotify_fs.c
> >   create mode 100644 tests/filesystem/fs_relabel.c
> >   create mode 100644 tests/filesystem/grim_reaper.c
> >   create mode 100644 tests/filesystem/mount.c
> >   create mode 100644 tests/filesystem/quotas_test.c
> >   create mode 100644 tests/filesystem/statfs_test.c
> >   create mode 100755 tests/filesystem/test
> >   create mode 100644 tests/filesystem/umount.c
> > 
> > diff --git a/defconfig b/defconfig
> > index 3bea332..7cb6a2c 100644
> > --- a/defconfig
> > +++ b/defconfig
> > @@ -88,3 +88,9 @@ CONFIG_TUN=m
> >   CONFIG_HAVE_PERF_EVENTS=y
> >   CONFIG_PERF_EVENTS=y
> >   CONFIG_TRACEPOINTS=y
> > +
> > +# Test filesystem permissions.
> > +# This is not required for SELinux operation itself.
> > +CONFIG_BLK_DEV_LOOP=m
> > +CONFIG_BLK_DEV_LOOP_MIN_COUNT=0
> > +CONFIG_QFMT_V2=y
> > diff --git a/policy/Makefile b/policy/Makefile
> > index 6f1db03..30896d8 100644
> > --- a/policy/Makefile
> > +++ b/policy/Makefile
> > @@ -114,6 +114,10 @@ TARGETS += test_lockdown.te
> >   export M4PARAM += -Dlockdown_defined
> >   endif
> >   
> > +ifeq ($(shell grep -q filesystem
> > $(POLDEV)/include/support/all_perms.spt && echo true),true)
> > +TARGETS += test_filesystem.te
> > +endif
> > +
> >   ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
> >   TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te
> > test_ibpkey.te, $(TARGETS))
> >   endif
> > diff --git a/policy/test_filesystem.te b/policy/test_filesystem.te
> > new file mode 100644
> > index 0000000..2eee1fc
> > --- /dev/null
> > +++ b/policy/test_filesystem.te
> > @@ -0,0 +1,324 @@
> > +#
> > +######### Test filesystem permissions policy module ##########
> > +#
> > +attribute filesystemdomain;
> > +
> > +#################### Create a test file context
> > ######################
> > +type test_filesystem_filecon_t;
> > +unconfined_runs_test(test_filesystem_filecon_t)
> > +
> > +################# Test all functions ##########################
> > +type test_filesystem_t;
> > +domain_type(test_filesystem_t)
> > +unconfined_runs_test(test_filesystem_t)
> > +typeattribute test_filesystem_t testdomain;
> > +typeattribute test_filesystem_t filesystemdomain;
> > +
> > +allow test_filesystem_t self:capability { sys_admin };
> > +allow test_filesystem_t self:filesystem { mount remount quotamod
> > relabelfrom relabelto unmount quotaget };
> > +allow test_filesystem_t self:dir { mounton add_name write };
> > +allow test_filesystem_t test_file_t:dir { mounton write
> > remove_name rmdir };
> > +# Create test file
> > +allow test_filesystem_t self:dir { add_name write };
> > +allow test_filesystem_t self:file { create relabelfrom relabelto
> > };
> > +
> > +fs_mount_all_fs(test_filesystem_t)
> > +fs_remount_all_fs(test_filesystem_t)
> > +fs_unmount_all_fs(test_filesystem_t)
> > +fs_relabelfrom_all_fs(test_filesystem_t)
> > +fs_get_xattr_fs_quotas(test_filesystem_t)
> > +files_search_all(test_filesystem_t)
> > +# Required for mount opts
> > "rootcontext=system_u:object_r:test_filesystem_t:s0";
> > +fs_associate(test_filesystem_t)
> > +fs_getattr_xattr_fs(test_filesystem_t)
> > +
> > +# For running quotacheck(8)
> > +files_type(test_filesystem_t)
> > +# Update quotas
> > +fs_set_all_quotas(test_filesystem_t)
> > +allow test_filesystem_t self:file { quotaon };
> > +# Create test file and change context:
> > +fs_associate(test_filesystem_filecon_t)
> > +allow test_filesystem_t test_filesystem_filecon_t:file { open read
> > getattr relabelto write };
> > +dontaudit test_filesystem_t kernel_t:process { setsched };
> > +
> > +#################### Deny filesystem { getattr }
> > ######################
> > +type test_filesystem_no_getattr_t;
> > +domain_type(test_filesystem_no_getattr_t)
> > +unconfined_runs_test(test_filesystem_no_getattr_t)
> > +typeattribute test_filesystem_no_getattr_t testdomain;
> > +typeattribute test_filesystem_no_getattr_t filesystemdomain;
> > +
> > +allow test_filesystem_no_getattr_t self:capability { sys_admin };
> > +fs_mount_all_fs(test_filesystem_no_getattr_t)
> > +fs_unmount_all_fs(test_filesystem_no_getattr_t)
> > +fs_relabelfrom_all_fs(test_filesystem_no_getattr_t)
> > +fs_associate(test_filesystem_no_getattr_t)
> > +allow test_filesystem_no_getattr_t self:dir { mounton };
> > +allow test_filesystem_no_getattr_t test_file_t:dir { mounton write
> > remove_name rmdir };
> > +dontaudit test_filesystem_no_getattr_t kernel_t:process { setsched
> > };
> > +
> > +#################### Deny filesystem { remount }
> > ######################
> > +type test_filesystem_no_remount_t;
> > +domain_type(test_filesystem_no_remount_t)
> > +unconfined_runs_test(test_filesystem_no_remount_t)
> > +typeattribute test_filesystem_no_remount_t testdomain;
> > +typeattribute test_filesystem_no_remount_t filesystemdomain;
> > +
> > +allow test_filesystem_no_remount_t self:capability { sys_admin };
> > +fs_mount_all_fs(test_filesystem_no_remount_t)
> > +fs_unmount_all_fs(test_filesystem_no_remount_t)
> > +fs_relabelfrom_all_fs(test_filesystem_no_remount_t)
> > +fs_associate(test_filesystem_no_remount_t)
> > +allow test_filesystem_no_remount_t self:dir { mounton };
> > +allow test_filesystem_no_remount_t test_file_t:dir { mounton write
> > remove_name rmdir };
> > +dontaudit test_filesystem_no_remount_t kernel_t:process { setsched
> > };
> > +
> > +#################### Deny filesystem { mount }
> > ######################
> > +type test_filesystem_no_mount_t;
> > +domain_type(test_filesystem_no_mount_t)
> > +unconfined_runs_test(test_filesystem_no_mount_t)
> > +typeattribute test_filesystem_no_mount_t testdomain;
> > +typeattribute test_filesystem_no_mount_t filesystemdomain;
> > +
> > +allow test_filesystem_no_mount_t self:capability { sys_admin };
> > +fs_relabelfrom_all_fs(test_filesystem_no_mount_t)
> > +fs_associate(test_filesystem_no_mount_t)
> > +allow test_filesystem_no_mount_t self:dir { mounton };
> > +allow test_filesystem_no_mount_t test_file_t:dir { mounton write
> > remove_name rmdir };
> > +dontaudit test_filesystem_no_mount_t kernel_t:process { setsched
> > };
> > +
> > +#################### Deny filesystem { unmount }
> > ######################
> > +type test_filesystem_no_unmount_t;
> > +domain_type(test_filesystem_no_unmount_t)
> > +unconfined_runs_test(test_filesystem_no_unmount_t)
> > +typeattribute test_filesystem_no_unmount_t testdomain;
> > +typeattribute test_filesystem_no_unmount_t filesystemdomain;
> > +
> > +allow test_filesystem_no_unmount_t self:capability { sys_admin };
> > +fs_mount_all_fs(test_filesystem_no_unmount_t)
> > +fs_relabelfrom_all_fs(test_filesystem_no_unmount_t)
> > +fs_associate(test_filesystem_no_unmount_t)
> > +allow test_filesystem_no_unmount_t self:dir { mounton };
> > +allow test_filesystem_no_unmount_t test_file_t:dir { mounton write
> > remove_name rmdir };
> > +dontaudit test_filesystem_no_unmount_t kernel_t:process { setsched
> > };
> > +
> > +#################### Deny filesystem { relabelfrom }
> > ######################
> > +type test_filesystem_no_relabelfrom_t;
> > +domain_type(test_filesystem_no_relabelfrom_t)
> > +unconfined_runs_test(test_filesystem_no_relabelfrom_t)
> > +typeattribute test_filesystem_no_relabelfrom_t testdomain;
> > +typeattribute test_filesystem_no_relabelfrom_t filesystemdomain;
> > +
> > +allow test_filesystem_no_relabelfrom_t self:capability { sys_admin
> > };
> > +fs_associate(test_filesystem_no_relabelfrom_t)
> > +allow test_filesystem_no_relabelfrom_t self:dir { mounton };
> > +allow test_filesystem_no_relabelfrom_t test_file_t:dir { mounton
> > write remove_name rmdir };
> > +dontaudit test_filesystem_no_relabelfrom_t kernel_t:process {
> > setsched };
> > +
> > +#################### Deny filesystem { relabelto }
> > ######################
> > +type test_filesystem_no_relabelto_t;
> > +domain_type(test_filesystem_no_relabelto_t)
> > +unconfined_runs_test(test_filesystem_no_relabelto_t)
> > +typeattribute test_filesystem_no_relabelto_t testdomain;
> > +typeattribute test_filesystem_no_relabelto_t filesystemdomain;
> > +
> > +allow test_filesystem_no_relabelto_t self:capability { sys_admin
> > };
> > +fs_mount_all_fs(test_filesystem_no_relabelto_t)
> > +fs_relabelfrom_all_fs(test_filesystem_no_relabelto_t)
> > +fs_associate(test_filesystem_no_relabelto_t)
> > +allow test_filesystem_no_relabelto_t self:dir { mounton };
> > +allow test_filesystem_no_relabelto_t test_file_t:dir { mounton
> > write remove_name rmdir };
> > +dontaudit test_filesystem_no_relabelto_t kernel_t:process {
> > setsched };
> > +
> > +#################### Deny filesystem { associate }
> > ######################
> > +type test_filesystem_no_associate_t;
> > +type test_filesystem_no_associate1_t;
> > +domain_type(test_filesystem_no_associate_t)
> > +unconfined_runs_test(test_filesystem_no_associate_t)
> > +typeattribute test_filesystem_no_associate_t testdomain;
> > +typeattribute test_filesystem_no_associate_t filesystemdomain;
> > +
> > +allow test_filesystem_no_associate_t self:capability { sys_admin
> > };
> > +allow test_filesystem_no_associate_t self:filesystem { relabelto
> > mount relabelfrom };
> > +fs_mount_all_fs(test_filesystem_no_associate_t)
> > +fs_relabelfrom_all_fs(test_filesystem_no_associate_t)
> > +allow test_filesystem_no_associate_t self:dir { mounton };
> > +allow test_filesystem_no_associate_t test_file_t:dir { mounton
> > write remove_name rmdir };
> > +dontaudit test_filesystem_no_associate_t kernel_t:process {
> > setsched };
> > +
> > +########## Deny filesystem { associate } for create file
> > ################
> > +type test_filesystem_no_associate_file_t;
> > +domain_type(test_filesystem_no_associate_file_t)
> > +unconfined_runs_test(test_filesystem_no_associate_file_t)
> > +typeattribute test_filesystem_no_associate_file_t testdomain;
> > +typeattribute test_filesystem_no_associate_file_t
> > filesystemdomain;
> > +
> > +allow test_filesystem_no_associate_file_t self:capability {
> > sys_admin };
> > +allow test_filesystem_no_associate_file_t self:filesystem { mount
> > relabelfrom relabelto unmount associate };
> > +allow test_filesystem_no_associate_file_t self:dir { mounton
> > add_name write };
> > +allow test_filesystem_no_associate_file_t test_file_t:dir {
> > mounton write remove_name rmdir };
> > +
> > +fs_mount_all_fs(test_filesystem_no_associate_file_t)
> > +fs_unmount_all_fs(test_filesystem_no_associate_file_t)
> > +fs_relabelfrom_all_fs(test_filesystem_no_associate_file_t)
> > +fs_associate(test_filesystem_no_associate_file_t)
> > +fs_getattr_xattr_fs(test_filesystem_no_associate_file_t)
> > +dontaudit test_filesystem_no_associate_file_t kernel_t:process {
> > setsched };
> > +
> > +# Create test file
> > +allow test_filesystem_no_associate_file_t self:file { create
> > relabelfrom relabelto };
> > +############ hooks.c may_create() FILESYSTEM__ASSOCIATE
> > #############
> > +# FOR: neverallow unlabeled_t
> > test_filesystem_no_associate_file_t:filesystem { associate };
> > +allow test_filesystem_no_associate_file_t unconfined_t:file { open
> > read write };
> > +allow test_filesystem_no_associate_file_t unlabeled_t:dir {
> > add_name search write };
> > +allow test_filesystem_no_associate_file_t unlabeled_t:file {
> > create open relabelfrom write };
> > +############ hooks.c selinux_inode_setxattr()
> > FILESYSTEM__ASSOCIATE ##########
> > +# FOR: neverallow unconfined_t
> > test_filesystem_no_associate_file_t:filesystem { associate };
> > +dontaudit unconfined_t test_filesystem_filecon_t:file { getattr
> > read };
> > +allow test_filesystem_no_associate_file_t unconfined_t:dir {
> > add_name write };
> > +allow test_filesystem_no_associate_file_t unconfined_t:file {
> > create relabelfrom relabelto };
> > +
> > +#################### Deny filesystem { quotamod }
> > ######################
> > +type test_filesystem_no_quotamod_t;
> > +domain_type(test_filesystem_no_quotamod_t)
> > +unconfined_runs_test(test_filesystem_no_quotamod_t)
> > +typeattribute test_filesystem_no_quotamod_t testdomain;
> > +typeattribute test_filesystem_no_quotamod_t filesystemdomain;
> > +
> > +allow test_filesystem_no_quotamod_t self:capability { sys_admin };
> > +allow test_filesystem_no_quotamod_t self:filesystem { quotaget
> > relabelto mount unmount};
> > +fs_mount_all_fs(test_filesystem_no_quotamod_t)
> > +fs_relabelfrom_all_fs(test_filesystem_no_quotamod_t)
> > +fs_associate(test_filesystem_no_quotamod_t)
> > +# Required as $private_path to quota files
> > +files_search_all(test_filesystem_no_quotamod_t)
> > +allow test_filesystem_no_quotamod_t self:dir { mounton };
> > +allow test_filesystem_no_quotamod_t test_file_t:dir { mounton
> > write remove_name rmdir };
> > +dontaudit test_filesystem_no_quotamod_t kernel_t:process {
> > setsched };
> > +
> > +#################### Deny filesystem { quotaget }
> > ######################
> > +type test_filesystem_no_quotaget_t;
> > +domain_type(test_filesystem_no_quotaget_t)
> > +unconfined_runs_test(test_filesystem_no_quotaget_t)
> > +typeattribute test_filesystem_no_quotaget_t testdomain;
> > +typeattribute test_filesystem_no_quotaget_t filesystemdomain;
> > +
> > +allow test_filesystem_no_quotaget_t self:capability { sys_admin };
> > +allow test_filesystem_no_quotaget_t self:filesystem { quotamod
> > relabelto mount unmount relabelfrom };
> > +allow test_filesystem_no_quotaget_t self:dir { mounton };
> > +allow test_filesystem_no_quotaget_t test_file_t:dir { mounton
> > write remove_name rmdir };
> > +allow test_filesystem_no_quotaget_t self:file { quotaon };
> > +fs_mount_all_fs(test_filesystem_no_quotaget_t)
> > +fs_relabelfrom_all_fs(test_filesystem_no_quotaget_t)
> > +fs_associate(test_filesystem_no_quotaget_t)
> > +# Required as $private_path to quota files
> > +files_search_all(test_filesystem_no_quotaget_t)
> > +# For running quotacheck(8)
> > +files_type(test_filesystem_no_quotaget_t)
> > +dontaudit test_filesystem_no_quotaget_t kernel_t:process {
> > setsched };
> > +
> > +#################### Deny filesystem { watch }
> > ######################
> > +type test_filesystem_no_watch_t;
> > +domain_type(test_filesystem_no_watch_t)
> > +unconfined_runs_test(test_filesystem_no_watch_t)
> > +typeattribute test_filesystem_no_watch_t testdomain;
> > +typeattribute test_filesystem_no_watch_t filesystemdomain;
> > +
> > +allow test_filesystem_no_watch_t self:capability { sys_admin };
> > +allow test_filesystem_no_watch_t self:filesystem { associate
> > relabelto mount unmount relabelfrom };
> > +allow test_filesystem_no_watch_t self:dir { mounton };
> > +allow test_filesystem_no_watch_t test_file_t:dir { mounton write
> > remove_name rmdir };
> > +fs_mount_all_fs(test_filesystem_no_watch_t)
> > +fs_relabelfrom_all_fs(test_filesystem_no_watch_t)
> > +fs_associate(test_filesystem_no_watch_t)
> > +dontaudit test_filesystem_no_watch_t kernel_t:process { setsched
> > };
> > +
> > +################# Test process { setfscreate } #############
> > +type test_setfscreatecon_t;
> > +domain_type(test_setfscreatecon_t)
> > +unconfined_runs_test(test_setfscreatecon_t)
> > +typeattribute test_setfscreatecon_t testdomain;
> > +typeattribute test_setfscreatecon_t filesystemdomain;
> > +
> > +allow test_setfscreatecon_t self:capability { sys_admin };
> > +allow test_setfscreatecon_t self:process { setfscreate };
> > +
> > +# Set new context on fs:
> > +type test_setfscreatecon_newcon_t;
> > +domain_type(test_setfscreatecon_newcon_t)
> > +typeattribute test_setfscreatecon_newcon_t testdomain;
> > +
> > +################# deny process { setfscreate } #############
> > +type test_no_setfscreatecon_t;
> > +domain_type(test_no_setfscreatecon_t)
> > +unconfined_runs_test(test_no_setfscreatecon_t)
> > +typeattribute test_no_setfscreatecon_t testdomain;
> > +typeattribute test_no_setfscreatecon_t filesystemdomain;
> > +
> > +allow test_no_setfscreatecon_t self:capability { sys_admin };
> > +# neverallow test_no_setfscreatecon_t self:process { setfscreate
> > };
> > +
> > +################# Test fscontext= ##########################
> > +type test_filesystem_fscontext_t;
> > +domain_type(test_filesystem_fscontext_t)
> > +unconfined_runs_test(test_filesystem_fscontext_t)
> > +typeattribute test_filesystem_fscontext_t testdomain;
> > +typeattribute test_filesystem_fscontext_t filesystemdomain;
> > +
> > +allow test_filesystem_fscontext_t self:capability { sys_admin };
> > +allow test_filesystem_fscontext_t self:filesystem { associate
> > mount relabelfrom relabelto unmount };
> > +allow test_filesystem_fscontext_t self:dir { mounton add_name
> > write };
> > +allow test_filesystem_fscontext_t test_file_t:dir { mounton write
> > remove_name rmdir };
> > +# Create test file
> > +allow test_filesystem_fscontext_t self:dir { add_name write };
> > +allow test_filesystem_fscontext_t self:file { create relabelfrom
> > relabelto };
> > +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file {
> > relabelto };
> > +allow test_filesystem_filecon_t
> > test_filesystem_fscontext_t:filesystem { associate };
> > +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file {
> > open getattr read write };
> > +
> > +fs_mount_all_fs(test_filesystem_fscontext_t)
> > +fs_unmount_all_fs(test_filesystem_fscontext_t)
> > +fs_relabelfrom_all_fs(test_filesystem_fscontext_t)
> > +files_search_all(test_filesystem_fscontext_t)
> > +
> > +########### Test context=, rootcontext= and defcontext
> > #################
> > +type test_filesystem_context_t;
> > +domain_type(test_filesystem_context_t)
> > +unconfined_runs_test(test_filesystem_context_t)
> > +typeattribute test_filesystem_context_t testdomain;
> > +typeattribute test_filesystem_context_t filesystemdomain;
> > +
> > +allow test_filesystem_context_t self:capability { sys_admin };
> > +allow test_filesystem_context_t self:filesystem { associate mount
> > relabelfrom relabelto unmount };
> > +allow test_filesystem_context_t self:dir { mounton add_name write
> > };
> > +allow test_filesystem_context_t test_file_t:dir { mounton write
> > remove_name rmdir };
> > +# Create test file
> > +allow test_filesystem_context_t self:dir { add_name write };
> > +allow test_filesystem_context_t self:file { create relabelfrom
> > relabelto };
> > +allow test_filesystem_context_t test_filesystem_filecon_t:file {
> > open getattr read write relabelto };
> > +allow test_filesystem_filecon_t
> > test_filesystem_context_t:filesystem { associate };
> > +
> > +fs_mount_all_fs(test_filesystem_context_t)
> > +fs_unmount_all_fs(test_filesystem_context_t)
> > +fs_relabelfrom_all_fs(test_filesystem_context_t)
> > +files_search_all(test_filesystem_context_t)
> > +fs_associate(test_filesystem_context_t)
> > +allow test_filesystem_context_t test_file_t:dir { add_name };
> > +dontaudit test_filesystem_context_t kernel_t:process { setsched };
> > +
> > +# For testing rootcontext= Set mountpoint to unlabeled first
> > +allow test_filesystem_context_t test_file_t:dir { relabelfrom };
> > +allow test_filesystem_context_t unlabeled_t:dir { mounton
> > relabelto };
> > +
> > +# For testing defcontext=
> > +allow test_filesystem_context_t test_filesystem_filecon_t:dir {
> > search };
> > +allow test_filesystem_fscontext_t test_filesystem_context_t:dir {
> > add_name search write };
> > +allow test_filesystem_fscontext_t test_filesystem_context_t:file {
> > create getattr open write };
> > +dontaudit unconfined_t test_filesystem_filecon_t:dir { read search
> > };
> > +
> > +#
> > +########### Allow these domains to be entered from sysadm domain
> > ############
> > +#
> > +miscfiles_domain_entry_test_files(filesystemdomain)
> > +userdom_sysadm_entry_spec_domtrans_to(filesystemdomain)
> > diff --git a/tests/Makefile b/tests/Makefile
> > index e19ea2f..a1478f1 100644
> > --- a/tests/Makefile
> > +++ b/tests/Makefile
> > @@ -91,6 +91,13 @@ ifeq ($(shell grep -q lockdown
> > $(POLDEV)/include/support/all_perms.spt && echo t
> >   SUBDIRS += lockdown
> >   endif
> >   
> > +ifeq ($(shell grep -q filesystem
> > $(POLDEV)/include/support/all_perms.spt && echo true),true)
> > +SUBDIRS += filesystem
> > +ifeq ($(shell grep -q all_filesystem_perms.*watch
> > $(POLDEV)/include/support/all_perms.spt && echo true),true)
> > +export CFLAGS += -DHAVE_FS_WATCH_PERM
> > +endif
> > +endif
> > +
> >   ifeq ($(DISTRO),RHEL4)
> >       SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket
> > mmap nnp_nosuid overlay unix_socket, $(SUBDIRS))
> >   endif
> > diff --git a/tests/filesystem/.gitignore
> > b/tests/filesystem/.gitignore
> > new file mode 100644
> > index 0000000..5ac18d0
> > --- /dev/null
> > +++ b/tests/filesystem/.gitignore
> > @@ -0,0 +1,11 @@
> > +mount
> > +umount
> > +quotas_test
> > +statfs_test
> > +fanotify_fs
> > +create_file_change_context
> > +fs_relabel
> > +check_file_context
> > +check_mount_context
> > +create_file
> > +grim_reaper
> > diff --git a/tests/filesystem/Makefile b/tests/filesystem/Makefile
> > new file mode 100644
> > index 0000000..d2fad63
> > --- /dev/null
> > +++ b/tests/filesystem/Makefile
> > @@ -0,0 +1,16 @@
> > +# Required for local building
> > +#export CFLAGS += -DHAVE_FS_WATCH_PERM
> > +
> > +TARGETS = mount umount quotas_test statfs_test
> > create_file_change_context \
> > +fs_relabel check_file_context grim_reaper check_mount_context
> > create_file
> > +
> > +LDLIBS += -lselinux
> > +
> > +ifneq (,$(findstring -DHAVE_FS_WATCH_PERM,$(CFLAGS)))
> > +	TARGETS += fanotify_fs
> > +endif
> > +
> > +all: $(TARGETS)
> > +
> > +clean:
> > +	rm -f $(TARGETS)
> > diff --git a/tests/filesystem/check_file_context.c
> > b/tests/filesystem/check_file_context.c
> > new file mode 100644
> > index 0000000..1380f16
> > --- /dev/null
> > +++ b/tests/filesystem/check_file_context.c
> > @@ -0,0 +1,75 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <stdbool.h>
> > +#include <linux/unistd.h>
> > +#include <selinux/selinux.h>
> > +
> > +static void print_usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v] -f -e -n\n"
> > +		"Where:\n\t"
> > +		"-f  File to check its context\n\t"
> > +		"-e  Expected context\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +	int opt, result, fd;
> > +	char *context = NULL, *expected = NULL, *file = NULL;
> > +	bool verbose = false;
> > +
> > +	while ((opt = getopt(argc, argv, "f:e:v")) != -1) {
> > +		switch (opt) {
> > +		case 'f':
> > +			file = optarg;
> > +			break;
> > +		case 'e':
> > +			expected = optarg;
> > +			break;
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			print_usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (!file || !expected)
> > +		print_usage(argv[0]);
> > +
> > +	fd = open(file, O_RDWR);
> > +	if (fd < 0) {
> > +		fprintf(stderr, "open(2) Failed: %s\n",
> > strerror(errno));
> > +		return -1;
> > +	}
> > +
> > +	result = fgetfilecon(fd, &context);
> > +	if (result < 0) {
> > +		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> > +			strerror(errno));
> > +		result = -1;
> > +		goto err;
> > +	}
> > +	result = 0;
> > +
> > +	if (strcmp(expected, context)) {
> > +		fprintf(stderr, "File context error,
> > expected:\n\t%s\ngot:\n\t%s\n",
> > +			expected, context);
> > +		result = -1;
> > +	} else {
> > +		if (verbose)
> > +			printf("Pass - File contexts match: %s\n",
> > context);
> > +	}
> > +err:
> > +	free(context);
> > +	close(fd);
> > +
> > +	return result;
> > +}
> > diff --git a/tests/filesystem/check_mount_context.c
> > b/tests/filesystem/check_mount_context.c
> > new file mode 100644
> > index 0000000..dbe0fb8
> > --- /dev/null
> > +++ b/tests/filesystem/check_mount_context.c
> > @@ -0,0 +1,109 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <stdbool.h>
> > +#include <linux/unistd.h>
> > +#include <selinux/selinux.h>
> > +#include <selinux/context.h>
> > +
> > +static void print_usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v] -m [-e] -r\n"
> > +		"Where:\n\t"
> > +		"-m  Mountpoint\n\t"
> > +		"-e  Expected MP context\n\t"
> > +		"-r  Reset MP context to 'unlabeled_t'\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +	int opt, result, save_err;
> > +	char *context = NULL, *expected = NULL, *mount = NULL, *newcon
> > = NULL;
> > +	bool verbose = false, reset = false;
> > +	const char *type = "unlabeled_t";
> > +	context_t con_t;
> > +
> > +	while ((opt = getopt(argc, argv, "m:e:rv")) != -1) {
> > +		switch (opt) {
> > +		case 'm':
> > +			mount = optarg;
> > +			break;
> > +		case 'e':
> > +			expected = optarg;
> > +			break;
> > +		case 'r':
> > +			reset = true;
> > +			break;
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			print_usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (!mount)
> > +		print_usage(argv[0]);
> > +
> > +	result = getfilecon(mount, &context);
> > +	if (result < 0) {
> > +		fprintf(stderr, "getfilecon(3) Failed: %s\n",
> > strerror(errno));
> > +		result = -1;
> > +		goto err;
> > +	}
> > +	if (verbose)
> > +		printf("Current MP context: %s\n", context);
> > +
> > +	result = 0;
> > +
> > +	if (reset) {
> > +		/* Set context to unlabeled_t */
> > +		con_t = context_new(context);
> > +		if (!con_t) {
> > +			fprintf(stderr, "Unable to create context
> > structure\n");
> > +			exit(-1);
> > +		}
> > +
> > +		if (context_type_set(con_t, type)) {
> > +			fprintf(stderr, "Unable to set new type\n");
> > +			exit(-1);
> > +		}
> > +
> > +		newcon = context_str(con_t);
> > +		if (!newcon) {
> > +			fprintf(stderr, "Unable to obtain new context
> > string\n");
> > +			exit(-1);
> > +		}
> > +
> > +		result = setfilecon(mount, newcon);
> > +		save_err = errno;
> > +		if (result < 0) {
> > +			fprintf(stderr, "setfilecon(3) Failed: %s\n",
> > +				strerror(errno));
> > +			result = save_err;
> > +			goto err;
> > +		}
> > +		if (verbose)
> > +			printf("Set new MP context: %s\n", newcon);
> > +	} else {
> > +		if (strcmp(expected, context)) {
> > +			fprintf(stderr, "Mount context error,
> > expected:\n\t%s\ngot:\n\t%s\n",
> > +				expected, context);
> > +			result = -1;
> > +		} else {
> > +			if (verbose)
> > +				printf("Pass - Mountpoint contexts
> > match: %s\n",
> > +				       context);
> > +		}
> > +	}
> > +
> > +err:
> > +	free(context);
> > +	return result;
> > +}
> > diff --git a/tests/filesystem/create_file.c
> > b/tests/filesystem/create_file.c
> > new file mode 100644
> > index 0000000..3d73067
> > --- /dev/null
> > +++ b/tests/filesystem/create_file.c
> > @@ -0,0 +1,79 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <stdbool.h>
> > +#include <sys/types.h>
> > +#include <linux/unistd.h>
> > +#include <selinux/selinux.h>
> > +
> > +static void print_usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v] -f\n"
> > +		"Where:\n\t"
> > +		"-f  File to create\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +	int opt, result, fd, save_err;
> > +	char *context, *file = NULL;
> > +	bool verbose = false;
> > +
> > +	while ((opt = getopt(argc, argv, "f:v")) != -1) {
> > +		switch (opt) {
> > +		case 'f':
> > +			file = optarg;
> > +			break;
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			print_usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (!file)
> > +		print_usage(argv[0]);
> > +
> > +	if (verbose) {
> > +		result = getcon(&context);
> > +		if (result < 0) {
> > +			fprintf(stderr, "Failed to obtain process
> > context\n");
> > +			exit(-1);
> > +		}
> > +		printf("Process context:\n\t%s\n", context);
> > +		free(context);
> > +	}
> > +
> > +	fd = creat(file, O_RDWR);
> > +	save_err = errno;
> > +	if (fd < 0) {
> > +		fprintf(stderr, "creat(2) Failed: %s\n",
> > strerror(errno));
> > +		return save_err;
> > +	}
> > +
> > +	context = NULL;
> > +	result = fgetfilecon(fd, &context);
> > +	if (result < 0) {
> > +		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> > +			strerror(errno));
> > +		result = -1;
> > +		goto err;
> > +	}
> > +	result = 0;
> > +
> > +	if (verbose)
> > +		printf("File context is: %s\n", context);
> > +
> > +err:
> > +	free(context);
> > +	close(fd);
> > +
> > +	return result;
> > +}
> > diff --git a/tests/filesystem/create_file_change_context.c
> > b/tests/filesystem/create_file_change_context.c
> > new file mode 100644
> > index 0000000..2a3b995
> > --- /dev/null
> > +++ b/tests/filesystem/create_file_change_context.c
> > @@ -0,0 +1,143 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <stdbool.h>
> > +#include <linux/unistd.h>
> > +#include <selinux/selinux.h>
> > +#include <selinux/context.h>
> > +
> > +static void print_usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v] -t -f\n"
> > +		"Where:\n\t"
> > +		"-t  Type for context of created file\n\t"
> > +		"-f  File to create\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +	int opt, result, fd, save_err;
> > +	char *context, *newfcon, *orgfcon, *type = NULL, *file = NULL;
> > +	bool verbose = false;
> > +	context_t con_t;
> > +
> > +	while ((opt = getopt(argc, argv, "t:f:v")) != -1) {
> > +		switch (opt) {
> > +		case 't':
> > +			type = optarg;
> > +			break;
> > +		case 'f':
> > +			file = optarg;
> > +			break;
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			print_usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (!type || !file)
> > +		print_usage(argv[0]);
> > +
> > +	result = getcon(&context);
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed to obtain process context\n");
> > +		exit(-1);
> > +	}
> > +
> > +	/* Build new file context */
> > +	con_t = context_new(context);
> > +	if (!con_t) {
> > +		fprintf(stderr, "Unable to create context
> > structure\n");
> > +		exit(-1);
> > +	}
> > +
> > +	if (context_type_set(con_t, type)) {
> > +		fprintf(stderr, "Unable to set new type\n");
> > +		exit(-1);
> > +	}
> > +
> > +	newfcon = context_str(con_t);
> > +	if (!newfcon) {
> > +		fprintf(stderr, "Unable to obtain new context
> > string\n");
> > +		exit(-1);
> > +	}
> > +
> > +	if (verbose) {
> > +		printf("Process context:\n\t%s\n", context);
> > +		printf("is creating test file:\n\t%s\n", file);
> > +		printf("and changing its context to:\n\t%s\n",
> > newfcon);
> > +	}
> > +
> > +	free(context);
> > +	context = NULL;
> > +
> > +	/* hooks.c may_create() FILESYSTEM__ASSOCIATE */
> > +	fd = creat(file, O_RDWR);
> > +	save_err = errno;
> > +	if (fd < 0) {
> > +		fprintf(stderr, "creat(2) Failed: %s\n",
> > strerror(errno));
> > +		result = save_err;
> > +		goto err;
> > +	}
> > +
> > +	result = fgetfilecon(fd, &orgfcon);
> > +	if (result < 0) {
> > +		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> > +			strerror(errno));
> > +		result = -1;
> > +		goto err;
> > +	}
> > +
> > +	if (verbose)
> > +		printf("Current test file context is: %s\n", orgfcon);
> > +
> > +	free(orgfcon);
> > +
> > +	/* hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE */
> > +	result = fsetfilecon(fd, newfcon);
> > +	save_err = errno;
> > +	if (result < 0) {
> > +		fprintf(stderr, "fsetfilecon(3) Failed: %s\n",
> > +			strerror(errno));
> > +		result = save_err;
> > +		goto err;
> > +	}
> > +
> > +	fd = open(file, O_RDWR);
> > +	if (fd < 0) {
> > +		fprintf(stderr, "open(2) Failed: %s\n",
> > strerror(errno));
> > +		result = -1;
> > +	}
> > +
> > +	result = fgetfilecon(fd, &context);
> > +	if (result < 0) {
> > +		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> > +			strerror(errno));
> > +		result = -1;
> > +		goto err;
> > +	}
> > +
> > +	if (verbose)
> > +		printf("New test file context is: %s\n", context);
> > +
> > +	result = 0;
> > +	if (strcmp(newfcon, context)) {
> > +		fprintf(stderr, "File context error,
> > expected:\n\t%s\ngot:\n\t%s\n",
> > +			newfcon, context);
> > +		result = -1;
> > +	}
> > +err:
> > +	free(context);
> > +	free(newfcon);
> > +	close(fd);
> > +
> > +	return result;
> > +}
> > diff --git a/tests/filesystem/fanotify_fs.c
> > b/tests/filesystem/fanotify_fs.c
> > new file mode 100644
> > index 0000000..1f8f165
> > --- /dev/null
> > +++ b/tests/filesystem/fanotify_fs.c
> > @@ -0,0 +1,79 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <fcntl.h>
> > +#include <errno.h>
> > +#include <stdbool.h>
> > +#include <sys/fanotify.h>
> > +#include <selinux/selinux.h>
> > +
> > +#ifndef FAN_MARK_FILESYSTEM
> > +#define FAN_MARK_FILESYSTEM	0x00000100
> > +#endif
> > +
> > +static void print_usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v] -t\n"
> > +		"Where:\n\t"
> > +		"-t  Target path\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +	int mask = FAN_OPEN, flags = FAN_MARK_ADD |
> > FAN_MARK_FILESYSTEM;
> > +	int fd, result, opt, save_err;
> > +	char *context, *tgt = NULL;
> > +	bool verbose = false;
> > +
> > +	while ((opt = getopt(argc, argv, "t:v")) != -1) {
> > +		switch (opt) {
> > +		case 't':
> > +			tgt = optarg;
> > +			break;
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			print_usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (!tgt)
> > +		print_usage(argv[0]);
> > +
> > +	if (verbose) {
> > +		result = getcon(&context);
> > +		if (result < 0) {
> > +			fprintf(stderr, "Failed to obtain process
> > context\n");
> > +			exit(-1);
> > +		}
> > +		printf("Process context:\n\t%s\n", context);
> > +		free(context);
> > +	}
> > +
> > +	fd = fanotify_init(FAN_CLASS_CONTENT, O_RDWR);
> > +	if (fd < 0) {
> > +		fprintf(stderr, "fanotify_init(2) Failed: %s\n",
> > +			strerror(errno));
> > +		exit(-1);
> > +	}
> > +
> > +	result = fanotify_mark(fd, flags, mask, AT_FDCWD, tgt);
> > +	save_err = errno;
> > +	if (result < 0) {
> > +		fprintf(stderr, "fanotify_mark(2) Failed: %s\n",
> > +			strerror(errno));
> > +		close(fd);
> > +		return save_err;
> > +	}
> > +
> > +	if (verbose)
> > +		printf("Set fanotify_mark(2) on filesystem: %s\n",
> > tgt);
> > +
> > +	close(fd);
> > +	return 0;
> > +}
> > diff --git a/tests/filesystem/fs_relabel.c
> > b/tests/filesystem/fs_relabel.c
> > new file mode 100644
> > index 0000000..25b1781
> > --- /dev/null
> > +++ b/tests/filesystem/fs_relabel.c
> > @@ -0,0 +1,72 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <fcntl.h>
> > +#include <stdbool.h>
> > +#include <linux/unistd.h>
> > +#include <selinux/selinux.h>
> > +
> > +static void print_usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v] -n\n"
> > +		"Where:\n\t"
> > +		"-n  New fs context\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char **argv)
> > +{
> > +	int opt, result, save_err;
> > +	char *context, *fscreate_con, *newcon = NULL;
> > +	bool verbose = false;
> > +
> > +	while ((opt = getopt(argc, argv, "n:v")) != -1) {
> > +		switch (opt) {
> > +		case 'n':
> > +			newcon = optarg;
> > +			break;
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			print_usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (!newcon)
> > +		print_usage(argv[0]);
> > +
> > +	if (verbose) {
> > +		result = getcon(&context);
> > +		if (result < 0) {
> > +			fprintf(stderr, "Failed to obtain process
> > context\n");
> > +			exit(-1);
> > +		}
> > +		printf("Process context:\n\t%s\n", context);
> > +		free(context);
> > +	}
> > +
> > +	result = setfscreatecon(newcon);
> > +	save_err = errno;
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed setfscreatecon(3): %s\n",
> > +			strerror(errno));
> > +		return save_err;
> > +	}
> > +
> > +	result = getfscreatecon(&fscreate_con);
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed getfscreatecon(3): %s\n",
> > +			strerror(errno));
> > +		exit(-1);
> > +	}
> > +	if (verbose)
> > +		printf("New fscreate context: %s\n", fscreate_con);
> > +
> > +	free(fscreate_con);
> > +	return 0;
> > +}
> > diff --git a/tests/filesystem/grim_reaper.c
> > b/tests/filesystem/grim_reaper.c
> > new file mode 100644
> > index 0000000..0105ab6
> > --- /dev/null
> > +++ b/tests/filesystem/grim_reaper.c
> > @@ -0,0 +1,63 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <stdbool.h>
> > +#include <sys/mount.h>
> > +#include <selinux/selinux.h>
> > +
> > +#define WAIT_COUNT 60
> > +#define USLEEP_TIME 10000
> > +
> > +/* Remove any mounts associated with the loop device in argv[1] */
> > +int main(int argc, char *argv[])
> > +{
> > +	FILE *fp;
> > +	size_t len;
> > +	ssize_t num;
> > +	int index = 0, i, result = 0;
> > +	char *mount_info[2];
> > +	char *buf = NULL, *item;
> > +
> > +	if (!argv[1])
> > +		return -1;
> > +
> > +	fp = fopen("/proc/mounts", "re");
> > +	if (!fp) {
> > +		fprintf(stderr, "Failed to open /proc/mounts: %s\n",
> > +			strerror(errno));
> > +		return -1;
> > +	}
> > +
> > +	while ((num = getline(&buf, &len, fp)) != -1) {
> > +		index = 0;
> > +		item = strtok(buf, " ");
> > +		while (item != NULL) {
> > +			mount_info[index] = item;
> > +			index++;
> > +			if (index == 2)
> > +				break;
> > +			item = strtok(NULL, " ");
> > +		}
> > +
> > +		if (strcmp(mount_info[0], argv[1]) == 0) {
> > +			for (i = 0; i < WAIT_COUNT; i++) {
> > +				result = umount(mount_info[1]);
> > +				if (!result)
> > +					break;
> > +
> > +				if (errno != EBUSY) {
> > +					fprintf(stderr, "Failed
> > umount(2): %s\n",
> > +						strerror(errno));
> > +					break;
> > +				}
> > +				usleep(USLEEP_TIME);
> > +			}
> > +		}
> > +	}
> > +
> > +	free(buf);
> > +	fclose(fp);
> > +	return result;
> > +}
> > diff --git a/tests/filesystem/mount.c b/tests/filesystem/mount.c
> > new file mode 100644
> > index 0000000..034f0ec
> > --- /dev/null
> > +++ b/tests/filesystem/mount.c
> > @@ -0,0 +1,130 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <stdbool.h>
> > +#include <sys/mount.h>
> > +#include <selinux/selinux.h>
> > +
> > +static void print_usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-s src] -t tgt [-f fs_type] [-o options]
> > [-bmprv]\n"
> > +		"Where:\n\t"
> > +		"-s  Source path\n\t"
> > +		"-t  Target path\n\t"
> > +		"-f  Filesystem type\n\t"
> > +		"-o  Options list (comma separated list)\n\t"
> > +		"Zero or one of the following flags:\n\t"
> > +		"\t-b  MS_BIND\n\t"
> > +		"\t-m  MS_MOVE\n\t"
> > +		"\t-p  MS_PRIVATE\n\t"
> > +		"\t-r  MS_REMOUNT\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +static int ck_mount(char *mntpoint)
> > +{
> > +	int result = 0;
> > +	FILE *fp;
> > +	size_t len;
> > +	ssize_t num;
> > +	char *buf = NULL;
> > +
> > +	fp = fopen("/proc/mounts", "re");
> > +	if (fp == NULL) {
> > +		fprintf(stderr, "Failed to open /proc/mounts: %s\n",
> > +			strerror(errno));
> > +		return -1;
> > +	}
> > +
> > +	while ((num = getline(&buf, &len, fp)) != -1) {
> > +		if (strstr(buf, mntpoint) != NULL) {
> > +			result = 1;
> > +			break;
> > +		}
> > +	}
> > +
> > +	free(buf);
> > +	fclose(fp);
> > +	return result;
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +	int opt, result, save_err, flags = 0;
> > +	char *context, *src = NULL, *tgt = NULL, *fs_type = NULL, *opts
> > = NULL;
> > +	bool verbose = false;
> > +
> > +	while ((opt = getopt(argc, argv, "s:t:f:o:pbmrv")) != -1) {
> > +		switch (opt) {
> > +		case 's':
> > +			src = optarg;
> > +			break;
> > +		case 't':
> > +			tgt = optarg;
> > +			break;
> > +		case 'f':
> > +			fs_type = optarg;
> > +			break;
> > +		case 'o':
> > +			opts = optarg;
> > +			break;
> > +		case 'b':
> > +			flags = MS_BIND;
> > +			break;
> > +		case 'p':
> > +			flags = MS_PRIVATE;
> > +			break;
> > +		case 'm':
> > +			flags = MS_MOVE;
> > +			break;
> > +		case 'r':
> > +			flags = MS_REMOUNT;
> > +			break;
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			print_usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (!tgt)
> > +		print_usage(argv[0]);
> > +
> > +	if (verbose) {
> > +		result = getcon(&context);
> > +		if (result < 0) {
> > +			fprintf(stderr, "Failed to obtain process
> > context\n");
> > +			return -1;
> > +		}
> > +		printf("Process context:\n\t%s\n", context);
> > +		free(context);
> > +	}
> > +
> > +	if (verbose)
> > +		printf("Mounting\n\tsrc: %s\n\ttgt: %s\n\tfs_type: %s
> > flags: 0x%x\n\topts: %s\n",
> > +		       src, tgt, fs_type, flags, opts);
> > +
> > +	result = mount(src, tgt, fs_type, flags, opts);
> > +	save_err = errno;
> > +	if (result < 0) {
> > +		fprintf(stderr, "Failed mount(2): %s\n",
> > strerror(errno));
> > +		return save_err;
> > +	}
> > +
> > +	if (flags == MS_MOVE) {
> > +		if (!ck_mount(src) && ck_mount(tgt)) {
> > +			if (verbose)
> > +				printf("MS_MOVE: Moved mountpoint\n");
> > +		} else {
> > +			fprintf(stderr, "MS_MOVE: Move mountpoint
> > failed\n");
> > +			return -1;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > diff --git a/tests/filesystem/quotas_test.c
> > b/tests/filesystem/quotas_test.c
> > new file mode 100644
> > index 0000000..34aaca9
> > --- /dev/null
> > +++ b/tests/filesystem/quotas_test.c
> > @@ -0,0 +1,134 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <stdbool.h>
> > +#include <sys/quota.h>
> > +#include <selinux/selinux.h>
> > +
> > +static void print_usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s -s src -t tgt\n"
> > +		"Where:\n\t"
> > +		"-s  Source path (e.g. /dev/loop0)\n\t"
> > +		"-t  Target quota file (Full path with either
> > 'aquota.user'\n\t"
> > +		"    or 'aquota.group' appended)\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +	int opt, result, qcmd, save_err, test_id = geteuid();
> > +	char *context, *src = NULL, *tgt = NULL;
> > +	bool verbose = false;
> > +	char fmt_buf[2];
> > +
> > +	while ((opt = getopt(argc, argv, "s:t:v")) != -1) {
> > +		switch (opt) {
> > +		case 's':
> > +			src = optarg;
> > +			break;
> > +		case 't':
> > +			tgt = optarg;
> > +			break;
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			print_usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (!src || !tgt)
> > +		print_usage(argv[0]);
> > +
> > +	if (verbose) {
> > +		result = getcon(&context);
> > +		if (result < 0) {
> > +			fprintf(stderr, "Failed to obtain process
> > context\n");
> > +			return -1;
> > +		}
> > +		printf("Process context:\n\t%s\n", context);
> > +		free(context);
> > +	}
> > +
> > +	if (strstr(tgt, "aquota.user") != NULL) {
> > +		qcmd = QCMD(Q_QUOTAON, USRQUOTA);
> > +		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> > +		save_err = errno;
> > +		if (result < 0) {
> > +			fprintf(stderr, "quotactl(Q_QUOTAON, USRQUOTA)
> > Failed: %s\n",
> > +				strerror(errno));
> > +			return save_err;
> > +		}
> > +		if (verbose)
> > +			printf("User Quota - ON\n");
> > +
> > +		qcmd = QCMD(Q_GETFMT, USRQUOTA);
> > +		result = quotactl(qcmd, src, test_id, fmt_buf);
> > +		save_err = errno;
> > +		if (result < 0) {
> > +			fprintf(stderr, "quotactl(Q_GETFMT, USRQUOTA)
> > Failed: %s\n",
> > +				strerror(errno));
> > +			return save_err;
> > +		}
> > +		if (verbose)
> > +			printf("User Format: 0x%x\n", fmt_buf[0]);
> > +
> > +		qcmd = QCMD(Q_QUOTAOFF, USRQUOTA);
> > +		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> > +		save_err = errno;
> > +		if (result < 0) {
> > +			fprintf(stderr, "quotactl(Q_QUOTAOFF, USRQUOTA)
> > Failed: %s\n",
> > +				strerror(errno));
> > +			return save_err;
> > +		}
> > +		if (verbose)
> > +			printf("User Quota - OFF\n");
> > +
> > +		return 0;
> > +
> > +	} else if (strstr(tgt, "aquota.group") != NULL) {
> > +		qcmd = QCMD(Q_QUOTAON, GRPQUOTA);
> > +		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> > +		save_err = errno;
> > +		if (result < 0) {
> > +			fprintf(stderr, "quotactl(Q_QUOTAON, GRPQUOTA)
> > Failed: %s\n",
> > +				strerror(errno));
> > +			return save_err;
> > +		}
> > +		if (verbose)
> > +			printf("Group Quota - ON\n");
> > +
> > +		qcmd = QCMD(Q_GETFMT, GRPQUOTA);
> > +		result = quotactl(qcmd, src, test_id, fmt_buf);
> > +		save_err = errno;
> > +		if (result < 0) {
> > +			fprintf(stderr, "quotactl(Q_GETFMT, GRPQUOTA)
> > Failed: %s\n",
> > +				strerror(errno));
> > +			return save_err;
> > +		}
> > +		if (verbose)
> > +			printf("Group Format: 0x%x\n", fmt_buf[0]);
> > +
> > +		qcmd = QCMD(Q_QUOTAOFF, GRPQUOTA);
> > +		result = quotactl(qcmd, src, QFMT_VFS_V0, tgt);
> > +		save_err = errno;
> > +		if (result < 0) {
> > +			fprintf(stderr, "quotactl(Q_QUOTAOFF, GRPQUOTA)
> > Failed: %s\n",
> > +				strerror(errno));
> > +			return save_err;
> > +		}
> > +		if (verbose)
> > +			printf("Group Quota - OFF\n");
> > +
> > +		return 0;
> > +	}
> > +
> > +	fprintf(stderr, "Required %s to specify 'aquota.user' or
> > 'aquota.group' file\n",
> > +		tgt);
> > +	return -1;
> > +}
> > diff --git a/tests/filesystem/statfs_test.c
> > b/tests/filesystem/statfs_test.c
> > new file mode 100644
> > index 0000000..5de49b1
> > --- /dev/null
> > +++ b/tests/filesystem/statfs_test.c
> > @@ -0,0 +1,65 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <stdbool.h>
> > +#include <sys/statfs.h>
> > +#include <selinux/selinux.h>
> > +
> > +static void print_usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v] -t\n"
> > +		"Where:\n\t"
> > +		"-t  Target path\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +	int opt, result, save_err;
> > +	char *context, *tgt = NULL;
> > +	bool verbose = false;
> > +	struct statfs statfs_t;
> > +
> > +	while ((opt = getopt(argc, argv, "t:v")) != -1) {
> > +		switch (opt) {
> > +		case 't':
> > +			tgt = optarg;
> > +			break;
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			print_usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (!tgt)
> > +		print_usage(argv[0]);
> > +
> > +	if (verbose) {
> > +		result = getcon(&context);
> > +		if (result < 0) {
> > +			fprintf(stderr, "Failed to obtain process
> > context\n");
> > +			return -1;
> > +		}
> > +		printf("Process context:\n\t%s\n", context);
> > +		free(context);
> > +	}
> > +
> > +	result = statfs(tgt, &statfs_t);
> > +	save_err = errno;
> > +	if (result < 0) {
> > +		fprintf(stderr, "statfs(2) Failed: %s\n",
> > strerror(errno));
> > +		return save_err;
> > +	}
> > +
> > +	if (verbose)
> > +		printf("statfs(2) returned magic filesystem: 0x%lx\n",
> > +		       statfs_t.f_type);
> > +
> > +	return 0;
> > +}
> > diff --git a/tests/filesystem/test b/tests/filesystem/test
> > new file mode 100755
> > index 0000000..00c69e1
> > --- /dev/null
> > +++ b/tests/filesystem/test
> > @@ -0,0 +1,830 @@
> > +#!/usr/bin/perl
> > +use Test::More;
> > +
> > +BEGIN {
> > +    $basedir = $0;
> > +    $basedir =~ s|(.*)/[^/]*|$1|;
> > +
> > +    $test_count = 63;
> > +
> > +    # Allow info to be shown.
> > +    $v = $ARGV[0];
> > +    if ($v) {
> > +        if ( $v ne "-v" ) {
> > +            plan skip_all => "Invalid option (use -v)";
> > +        }
> > +    }
> > +    else {
> > +        $v = " ";
> > +    }
> > +
> > +    # From kernel 5.5 support for fanotify(7) with filesystem {
> > watch }
> > +    $kvercur = `uname -r`;
> > +    chomp($kvercur);
> > +    $kverminstream = "5.5";
> > +
> > +    $result = `$basedir/../kvercmp $kvercur $kverminstream`;
> > +    if ( $result > 0 && -e "$basedir/fanotify_fs" ) {
> > +        $test_watch = 1;
> > +        $test_count += 4;
> > +    }
> > +
> > +    plan tests => $test_count;
> > +}
> > +
> > +# mount(2) MS_BIND | MS_PRIVATE requires an absolute path to a
> > private mount
> > +# point before MS_MOVE
> > +$cwd = `pwd 2>/dev/null`;
> > +chomp($cwd);
> > +$private_path = "$cwd";
> > +if ( $basedir eq "." ) {
> > +    $private_path = "$cwd/mntpoint";
> > +}
> > +else {
> > +    $private_path = "$cwd/$basedir/mntpoint";
> > +}
> > +
> > +# Set initial filesystem type
> > +$fs_type = "ext4";
> > +
> > +# For list of devices used
> > +$device_count = 0;
> > +
> > +sub get_loop_dev {
> > +    print "Finding free /dev/loop entry\n";
> > +    $dev = `losetup -f 2>/dev/null`;
> > +    chomp($dev);
> > +    if ( $dev eq "" ) {
> > +        print "losetup failed to obtain /dev/loop entry\n";
> > +        cleanup();
> > +        exit -1;
> > +    }
> > +
> > +    # Keep list of devices for cleanup later
> > +    if ( $device_count eq 0 ) {
> > +        $device_list[$device_count] = $dev;
> > +        $device_count += 1;
> > +    }
> > +    elsif ( $dev ne $device_list[ $device_count - 1 ] ) {
> > +        $device_list[$device_count] = $dev;
> > +        $device_count += 1;
> > +    }
> > +}
> > +
> > +sub attach_dev {
> > +    print "Attaching $basedir/fstest to $dev\n";
> > +    $result = system("losetup $dev $basedir/fstest 2>/dev/null");
> > +    if ( $result != 0 ) {
> > +        print "Failed to attach $basedir/fstest to $dev\n";
> > +        cleanup();
> > +        exit -1;
> > +    }
> > +}
> > +
> > +sub make_fs {
> > +    my ($mk_type) = @_;
> > +
> > +    get_loop_dev();
> > +
> > +    if ( $mk_type eq "tmpfs" ) {
> > +        return;
> > +    }
> > +
> > +    print "Create $basedir/fstest with dd\n";
> > +    $result = system(
> > +        "dd if=/dev/zero of=$basedir/fstest bs=1024 count=10240
> > 2>/dev/null");
> > +    if ( $result != 0 ) {
> > +        print "dd failed to create fstest\n";
> > +        exit -1;
> > +    }
> > +
> > +    attach_dev();
> > +
> > +    print "Make $mk_type filesystem on $dev\n";
> > +    $result = system("mkfs.$mk_type $dev >& /dev/null");
> > +    if ( $result != 0 ) {
> > +        system("losetup -d $dev 2>/dev/null");
> > +        cleanup();
> > +        print "mkfs.$mk_type failed to create filesystem on
> > $dev\n";
> > +        exit -1;
> > +    }
> > +}
> > +
> > +sub mk_mntpoint_1 {
> > +    system("rm -rf $private_path/mp1 2>/dev/null");
> > +    system("mkdir -p $private_path/mp1 2>/dev/null");
> > +}
> > +
> > +sub mk_mntpoint_2 {
> > +    system("rm -rf $private_path/mp2 2>/dev/null");
> > +    system("mkdir -p $private_path/mp2 2>/dev/null");
> > +}
> > +
> > +sub cleanup {
> > +    system("rm -rf $basedir/fstest 2>/dev/null");
> > +    system("rm -rf $basedir/mntpoint 2>/dev/null");
> > +}
> > +
> > +sub cleanup1 {
> > +    system("losetup -d $dev 2>/dev/null");
> > +    system("rm -rf $basedir/fstest 2>/dev/null");
> > +    system("rm -rf $basedir/mntpoint 2>/dev/null");
> > +}
> > +
> > +############### Test setfscreatecon(3) ##########################
> > +print "Test setfscreatecon(3)\n";
> > +$result = system
> > +"runcon -t test_setfscreatecon_t $basedir/fs_relabel $v -n
> > system_u:system_r:test_setfscreatecon_newcon_t:s0";
> > +ok( $result eq 0 );
> > +
> > +$result = system
> > +"runcon -t test_no_setfscreatecon_t $basedir/fs_relabel $v -n
> > system_u:system_r:test_setfscreatecon_newcon_t:s0 2>&1";
> > +ok( $result >> 8 eq 13 );
> > +
> > +############### Test Basic Mount/Unmount
> > ##########################
> > +cleanup();
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +$mount_opts1 =
> > +  "quota,usrquota,grpquota,defcontext=system_u:object_r:test_files
> > ystem_t:s0";
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$mount_opts1\n";
> > +$result = system(
> > +"runcon -t test_filesystem_t $basedir/mount -s $dev -t
> > $private_path/mp1 -f $fs_type -o $mount_opts1 $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Then remount\n";
> > +$result = system(
> > +"runcon -t test_filesystem_t $basedir/mount -r -s $dev -t
> > $private_path/mp1 -f $fs_type -o $mount_opts1 $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Running quotacheck(8) to init user/group quota files\n";
> > +$result = system("quotacheck -ugF vfsv0 $private_path/mp1");
> > +ok( $result eq 0 );
> > +
> > +print "Toggle User & Group quotas on/off\n";
> > +$result = system(
> > +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t
> > $private_path/mp1/aquota.user $v"
> > +);
> > +ok( $result eq 0 );
> > +$result = system(
> > +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t
> > $private_path/mp1/aquota.group $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Get statfs(2)\n";
> > +$result =
> > +  system(
> > +    "runcon -t test_filesystem_t $basedir/statfs_test -t
> > $basedir/mntpoint $v");
> > +ok( $result eq 0 );
> > +
> > +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_t $basedir/create_file_change_context
> > -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +if ($test_watch) {
> > +    print "fanotify(7) test\n";
> > +    $result = system(
> > +"runcon -t test_filesystem_t $basedir/fanotify_fs $v -t
> > $basedir/mntpoint/mp1"
> > +    );
> > +    ok( $result eq 0 );
> > +}
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result =
> > +  system("runcon -t test_filesystem_t $basedir/umount -t
> > $private_path/mp1 $v");
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Test Move Mount ##########################
> > +make_fs($fs_type);
> > +$mount_opts2 =
> > +  "quota,usrquota,grpquota,rootcontext=system_u:object_r:test_file
> > system_t:s0";
> > +system("mkdir -p $private_path 2>/dev/null");
> > +
> > +print "Set mount MS_BIND on filesystem\n";
> > +$result = system(
> > +"runcon -t test_filesystem_t $basedir/mount -s $private_path -t
> > $private_path -b $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Set mount MS_PRIVATE on filesystem\n";
> > +$result =
> > +  system("runcon -t test_filesystem_t $basedir/mount -t
> > $private_path -p $v");
> > +ok( $result eq 0 );
> > +
> > +mk_mntpoint_1();
> > +mk_mntpoint_2();
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$mount_opts2\n";
> > +$result = system(
> > +"runcon -t test_filesystem_t $basedir/mount -s $dev -t
> > $private_path/mp1 -f $fs_type -o $mount_opts2 $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Set mount MS_MOVE on filesystem\n";
> > +$result = system(
> > +"runcon -t test_filesystem_t $basedir/mount -s $private_path/mp1
> > -t $private_path/mp2 -m  $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp2\n";
> > +$result =
> > +  system("runcon -t test_filesystem_t $basedir/umount -t
> > $private_path/mp2 $v");
> > +ok( $result eq 0 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint\n";
> > +$result =
> > +  system("runcon -t test_filesystem_t $basedir/umount -t
> > $private_path $v");
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { relabelfrom }
> > ##########################
> > +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM
> > +
> > +$opts_no_relabelfrom =
> > +"defcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0,
> > fscontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0";
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_relabelfrom\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev
> > -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v
> > 2>&1"
> > +);
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { relabelto }
> > ##########################
> > +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO
> > +
> > +$opts_no_relabelto =
> > +  "fscontext=system_u:object_r:test_filesystem_no_relabelto_t:s0";
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_relabelto\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_relabelto_t $basedir/mount -s $dev
> > -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelto $v 2>&1"
> > +);
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { relabelfrom }
> > ##########################
> > +# hooks.c may_context_mount_inode_relabel()
> > FILESYSTEM__RELABELFROM
> > +
> > +$opts_no_relabelfrom =
> > +  "rootcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:
> > s0";
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_relabelfrom\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev
> > -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v
> > 2>&1"
> > +);
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { associate }
> > ##########################
> > +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE
> > +
> > +$opts_no_associate =
> > +"defcontext=system_u:object_r:test_filesystem_no_associate_t:s0,fs
> > context=system_u:object_r:test_filesystem_no_associate_t:s0";
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_associate\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_associate_t $basedir/mount -s $dev
> > -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate $v 2>&1"
> > +);
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { associate }
> > ##########################
> > +# hooks.c may_create() FILESYSTEM__ASSOCIATE
> > +cleanup();
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +$opts_no_associate_file =
> > +  "fscontext=system_u:object_r:test_filesystem_no_associate_file_t
> > :s0";
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_associate_file\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s
> > $dev -t $basedir/mntpoint/mp1 -f $fs_type -o
> > $opts_no_associate_file $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_no_associate_file_t
> > $basedir/create_file_change_context -t unconfined_t -f
> > $basedir/mntpoint/mp1/test_file $v 2>&1"
> > +  );
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { quotamod }
> > ##########################
> > +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD
> > +
> > +$opts_no_quotamod =
> > +"quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesyst
> > em_no_quotamod_t:s0";
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +system("mkdir -p $private_path 2>/dev/null");
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_quotamod\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_quotamod_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotamod $v 2>&1"
> > +);
> > +ok( $result eq 0 );
> > +
> > +# No need to run quotacheck(8) as never gets far enough to read
> > quota file
> > +print "Toggle User & Group quotas on/off\n";    # Must have full
> > path
> > +$result = system(
> > +"runcon -t test_filesystem_no_quotamod_t $basedir/quotas_test -s
> > $dev -t $private_path/mp1/aquota.user $v 2>&1"
> > +);
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_quotamod_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { quotaget }
> > ##########################
> > +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET
> > +
> > +$opts_no_quotaget =
> > +"quota,usrquota,grpquota,context=system_u:object_r:test_filesystem
> > _no_quotaget_t:s0";
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_quotaget\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_quotaget_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotaget $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Running quotacheck(8) to init user/group quota files\n";
> > +$result = system("quotacheck -ugF vfsv0 $private_path/mp1");
> > +ok( $result eq 0 );
> > +
> > +print "Toggle User & Group quotas on/off\n";    # Must have full
> > path
> > +$result = system(
> > +"runcon -t test_filesystem_no_quotaget_t $basedir/quotas_test -s
> > $dev -t $private_path/mp1/aquota.user $v 2>&1"
> > +);
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_quotaget_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { mount }
> > ##########################
> > +# hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT
> > +
> > +$opts_no_mount =
> > "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0";
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_mount\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_mount_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_mount $v 2>&1"
> > +);
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { getattr }
> > ##########################
> > +# hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR
> > +
> > +$opts_no_getattr =
> > +  "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0";
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_getattr\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_getattr_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_getattr $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +$result = system(
> > +"runcon -t test_filesystem_no_getattr_t $basedir/statfs_test -t
> > $basedir/mntpoint $v 2>&1"
> > +);
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_getattr_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { remount }
> > ##########################
> > +# hooks.c selinux_mount() FILESYSTEM__REMOUNT
> > +
> > +$opts_no_remount =
> > +  "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0";
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_remount\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_remount_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Then remount\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_remount_t $basedir/mount -r -s $dev
> > -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v 2>&1"
> > +);
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_remount_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { unmount }
> > ##########################
> > +# hooks.c selinux_umount() FILESYSTEM__UNMOUNT
> > +
> > +$opts_no_unmount =
> > +  "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0";
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_unmount\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_unmount_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_unmount $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_unmount_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v 2>&1"
> > +);
> > +ok( $result >> 8 eq 13 );
> > +
> > +# Make sure it does get unmounted
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result =
> > +  system(
> > +    "runcon -t test_filesystem_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v");
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { associate
> > }  ##########################
> > +# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE
> > +cleanup();
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +$opts_no_associate_file =
> > +"defcontext=system_u:object_r:test_filesystem_no_associate_file_t:
> > s0,fscontext=system_u:object_r:test_filesystem_no_associate_file_t:
> > s0";
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$opts_no_associate_file\n";
> > +$result = system(
> > +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s
> > $dev -t $basedir/mntpoint/mp1 -f $fs_type -o
> > $opts_no_associate_file $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_no_associate_file_t
> > $basedir/create_file_change_context -t unconfined_t -f
> > $basedir/mntpoint/mp1/test_file $v 2>&1"
> > +  );
> > +ok( $result >> 8 eq 13 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +############### Deny filesystem { watch
> > }  ##########################
> > +# hooks.c selinux_path_notify() FILESYSTEM__WATCH
> > +if ($test_watch) {
> > +    cleanup();
> > +    mk_mntpoint_1();
> > +    make_fs($fs_type);
> > +    $opts_no_watch =
> > "context=system_u:object_r:test_filesystem_no_watch_t:s0";
> > +
> > +    print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +    print "Using mount options:\n\t$opts_no_watch\n";
> > +    $result = system(
> > +"runcon -t test_filesystem_no_watch_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_watch $v"
> > +    );
> > +    ok( $result eq 0 );
> > +
> > +    print "test_fanotify\n";
> > +    $result = system(
> > +"runcon -t test_filesystem_no_watch_t $basedir/fanotify_fs $v -t
> > $basedir/mntpoint/mp1 2>&1"
> > +    );
> > +    ok( $result >> 8 eq 13 );
> > +
> > +    print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +    $result = system(
> > +"runcon -t test_filesystem_no_watch_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +    );
> > +    ok( $result eq 0 );
> > +
> > +    print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +    cleanup1();
> > +}
> > +
> > +##################################################################
> > ########
> > +# context     - Useful when mounting filesystems that do not
> > support extended
> > +#               attributes.
> > +#   Tested by - Creating a filesystem that has xattrs set to a
> > different value,
> > +#               then mount with context= and confirm that the
> > files have that
> > +#               context as well as any newly created files (even
> > if fscreate
> > +#               was set to something else), and that
> > setfilecon/setxattr() on
> > +#               files within the mount fails with errno
> > EOPNOTSUPP.
> > +##################################################################
> > ########
> > +cleanup();
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +# Mount with xttrs to create a file with specific context.
> > +$context1_opts =
> > "defcontext=system_u:object_r:test_filesystem_context_t:s0";
> > +
> > +print "Testing 'context=' mount option\n";
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$context1_opts\n";
> > +$result = system(
> > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $context1_opts $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +# Create file with 'test_filesystem_filecon_t' context
> > +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_context_t
> > $basedir/create_file_change_context -t test_filesystem_filecon_t -f
> > $private_path/mp1/test_file $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result = system(
> > +"runcon -t test_filesystem_context_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +# Need to free the loop device, then get new dev one and attach
> > +system("losetup -d $dev 2>/dev/null");
> > +get_loop_dev();
> > +attach_dev();
> > +
> > +# Mount again with no xttr support
> > +$context2_opts =
> > "context=system_u:object_r:test_filesystem_context_t:s0";
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$context2_opts\n";
> > +$result = system(
> > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $context2_opts $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +# Now check the context on file is
> > system_u:object_r:test_filesystem_context_t:s0
> > +print "Check test file context $basedir/mntpoint/mp1/test_file\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_context_t $basedir/check_file_context
> > -f $private_path/mp1/test_file -e
> > system_u:object_r:test_filesystem_context_t:s0 $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +# Then create a file with 'test_filesystem_filecon_t' context,
> > this should fail with EOPNOTSUPP
> > +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_context_t
> > $basedir/create_file_change_context -t test_filesystem_filecon_t -f
> > $private_path/mp1/test_file $v 2>/dev/null"
> > +  );
> > +ok( $result >> 8 eq 95 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_context_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +##################################################################
> > ########
> > +# rootcontext - Explicitly label the root inode of the filesystem
> > being
> > +#               mounted before that filesystem or inode becomes
> > visible
> > +#               to userspace.
> > +#   Tested by - Set mountpoint to unlabeled_t and then check that
> > the
> > +#               context of the root directory matches rootcontext=
> > after
> > +#               the mount operation.
> > +##################################################################
> > ########
> > +cleanup();
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +$root_opts =
> > "rootcontext=system_u:object_r:test_filesystem_context_t:s0";
> > +
> > +print "Testing 'rootcontext=' mount option\n";
> > +
> > +# Reset mountpoint to 'unlabeled_t' so it is different to any
> > other possible test values.
> > +print "Resetting MP to unlabeled_t $basedir/mntpoint/mp1\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_context_t $basedir/check_mount_context
> > -r -m $basedir/mntpoint/mp1 $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$root_opts\n";
> > +$result = system(
> > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $root_opts $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +# Now check the mountpoint is the 'rootcontext=' value
> > +print "Check MP context $basedir/mntpoint/mp1\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_context_t $basedir/check_mount_context
> > -m $basedir/mntpoint/mp1 -e
> > system_u:object_r:test_filesystem_context_t:s0 $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result = system(
> > +"runcon -t test_filesystem_context_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +##################################################################
> > ########
> > +# defcontext  - Set default security context for unlabeled files.
> > +#               This overrides the value set for unlabeled files
> > in policy
> > +#               and requires a filesystem that supports xattr
> > labeling.
> > +#   Tested by - Create filesystem that has files w/o xattrs and
> > then confirm
> > +#               that they are mapped to the specified defcontext
> > upon mount,
> > +#               where defcontext differs from the policy default.
> > +##################################################################
> > ########
> > +cleanup();
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +
> > +$test_opts =
> > "context=system_u:object_r:test_filesystem_context_t:s0";
> > +
> > +print "Testing 'defcontext=' mount option\n";
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$test_opts\n";
> > +$result = system(
> > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $test_opts $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +# Create file, its context will be
> > system_u:object_r:test_filesystem_context_t:s0 from $test_opts
> > +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> > +$result =
> > +  system(
> > +"runcon -u system_u -t test_filesystem_fscontext_t
> > $basedir/create_file -f $basedir/mntpoint/mp1/test_file $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result = system(
> > +"runcon -t test_filesystem_context_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +# Need to free the loop device, then get new dev one and attach
> > +system("losetup -d $dev 2>/dev/null");
> > +get_loop_dev();
> > +attach_dev();
> > +
> > +# Mount again with defcontext=
> > +$defcontext_opts =
> > "defcontext=system_u:object_r:test_filesystem_filecon_t:s0";
> > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$defcontext_opts\n";
> > +$result = system(
> > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $defcontext_opts $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +# Now check the file context is now
> > system_u:object_r:test_filesystem_filecon_t:s0
> > +print "Check test file context $basedir/mntpoint/mp1/test_file\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_context_t $basedir/check_file_context
> > -f $basedir/mntpoint/mp1/test_file -e
> > system_u:object_r:test_filesystem_filecon_t:s0 $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_context_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +##################################################################
> > ########
> > +# fscontext   - Sets the overarching filesystem label to a
> > specific security
> > +#               context. This filesystem label is separate from
> > the individual
> > +#               labels on the files.
> > +#   Tested by - Mount a tmpfs (fs_use_trans) filesystem with
> > fscontext= and
> > +#               then create a file within it, checking its
> > context.
> > +##################################################################
> > ########
> > +$fs_type = "tmpfs";
> > +cleanup();
> > +mk_mntpoint_1();
> > +make_fs($fs_type);
> > +$fscontext_opts =
> > +"fscontext=system_u:object_r:test_filesystem_fscontext_t:s0,size=1
> > 0M,mode=0770";
> > +
> > +print "Testing 'fscontext=' mount option\n";
> > +print "Mount tmpfs filesystem on $basedir/mntpoint/mp1\n";
> > +print "Using mount options:\n\t$fscontext_opts\n";
> > +$result = system(
> > +"runcon -t test_filesystem_fscontext_t $basedir/mount -s $dev -t
> > $basedir/mntpoint/mp1 -f $fs_type -o $fscontext_opts $v"
> > +);
> > +ok( $result eq 0 );
> > +
> > +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_fscontext_t
> > $basedir/create_file_change_context -t test_filesystem_filecon_t -f
> > $private_path/mp1/test_file $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Unmount filesystem from $basedir/mntpoint/mp1\n";
> > +$result =
> > +  system(
> > +"runcon -t test_filesystem_fscontext_t $basedir/umount -t
> > $basedir/mntpoint/mp1 $v"
> > +  );
> > +ok( $result eq 0 );
> > +
> > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> > +cleanup1();
> > +
> > +# Cleanup any attached /dev/loop entries
> > +foreach my $n (@device_list) {
> > +    system("$basedir/grim_reaper $n 2>/dev/null");
> > +}
> > +
> > +exit;
> > diff --git a/tests/filesystem/umount.c b/tests/filesystem/umount.c
> > new file mode 100644
> > index 0000000..4a20448
> > --- /dev/null
> > +++ b/tests/filesystem/umount.c
> > @@ -0,0 +1,84 @@
> > +#include <stdio.h>
> > +#include <stdlib.h>
> > +#include <string.h>
> > +#include <unistd.h>
> > +#include <errno.h>
> > +#include <stdbool.h>
> > +#include <sys/mount.h>
> > +#include <selinux/selinux.h>
> > +
> > +static void print_usage(char *progname)
> > +{
> > +	fprintf(stderr,
> > +		"usage:  %s [-v] [-t]\n"
> > +		"Where:\n\t"
> > +		"-t  Target path\n\t"
> > +		"-v  Print information.\n", progname);
> > +	exit(-1);
> > +}
> > +
> > +#define WAIT_COUNT 60
> > +#define USLEEP_TIME 100000
> > +
> > +int main(int argc, char *argv[])
> > +{
> > +	char *context, *tgt = NULL;
> > +	int opt, result, i, save_err;
> > +	bool verbose = false;
> > +
> > +	while ((opt = getopt(argc, argv, "t:v")) != -1) {
> > +		switch (opt) {
> > +		case 't':
> > +			tgt = optarg;
> > +			break;
> > +		case 'v':
> > +			verbose = true;
> > +			break;
> > +		default:
> > +			print_usage(argv[0]);
> > +		}
> > +	}
> > +
> > +	if (!tgt)
> > +		print_usage(argv[0]);
> > +
> > +	if (verbose) {
> > +		result = getcon(&context);
> > +		if (result < 0) {
> > +			fprintf(stderr, "Failed to obtain process
> > context\n");
> > +			exit(-1);
> > +		}
> > +		printf("Process context:\n\t%s\n", context);
> > +		free(context);
> > +	}
> > +
> > +	/*
> > +	 * umount(2) will sometimes return EBUSY when other tasks are
> > +	 * checking mounts so wait around before bailing out.
> > +	 */
> > +	for (i = 0; i < WAIT_COUNT; i++) {
> > +		result = umount(tgt);
> > +		save_err = errno;
> > +		if (!result) {
> > +			if (verbose)
> > +				printf("Unmounted: %s\n", tgt);
> > +
> > +			return 0;
> > +		}
> > +
> > +		if (verbose && save_err == EBUSY)
> > +			printf("umount(2) returned EBUSY %d times\n", i
> > + 1);
> > +
> > +		if (save_err != EBUSY) {
> > +			fprintf(stderr, "Failed umount(2): %s\n",
> > +				strerror(save_err));
> > +			return save_err;
> > +		}
> > +		usleep(USLEEP_TIME);
> > +	}
> > +
> > +	fprintf(stderr, "Failed to umount(2) after %d retries with:
> > %s\n",
> > +		WAIT_COUNT, strerror(save_err));
> > +
> > +	return save_err;
> > +}
> > 


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2020-01-09 17:34 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-12-20 10:11 [PATCH 0/1] selinux-testsuite: Add filesystem tests Richard Haines
2019-12-20 10:11 ` [PATCH 1/1] " Richard Haines
2020-01-06 16:11   ` Ondrej Mosnacek
2020-01-07 15:30     ` Richard Haines
2020-01-09 14:18   ` Stephen Smalley
2020-01-09 17:33     ` Richard Haines

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.