selinux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH V6 0/1] selinux-testsuite: Add filesystem tests
@ 2020-01-16 18:51 Richard Haines
  2020-01-16 18:51 ` [PATCH V6 1/1] " Richard Haines
  0 siblings, 1 reply; 4+ messages in thread
From: Richard Haines @ 2020-01-16 18:51 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).
V6 Changes:
1) The name-based rules only apply to 'MOD_POL_VERS=>11 and POL_VERS=>25'
   This requires testing on RHEL-6
2) Tidy up the test script and policy regarding contexts. Should now be
   easier to distinguish where denials were generated in hooks.c.

V5 Change:
1) Correct name-based type transition rules.

V4 Changes:
1) Test non-name based type transition rule.
2) Test two different name-based type transition rules that only differ 
   in name.
3) Creating ext4 filesystems with inodes > 128 bytes using -I 256.
4) Use kernel_setsched() macro.

V3 Changes:
1) Lots of minor updates.
2) Add 'udevadm settle' as suggested by Ondrej to resolve udisks(8) issue.
3) Add stopping udisks(8) daemon as a '-d' option.
4) Add file quotaon test.
5) Add test for name type_transition rule.
6) Fix setfscreatecon(3) test to create a directory and check context.
7) Use kernel_dontaudit_setsched() as explained in [1].

[1] https://lore.kernel.org/selinux/f863a91987c1926a4351f3edf968c9003197fead.camel@btinternet.com/

V2 Changes:
1) If udisks(8) daemon is running, stop then restart after tests. The tests
   run faster and stops the annoying habit of adding mounts to the 'files'
   app on the desktop. Supports /usr/bin/systemctl or /usr/sbin/service
   More importantly it stops interferance with the '*context=' tests as it
   can cause intermittent failures. Tested by running 'test' in a continuous
   loop with udisks enabled, and then again disabled.
   Loop 200 times, with udisks failed between 1 to 70 iterations, without
   udisks, no failures.
2) Add "#define QFMT_VFS_V0 2" to quotas_test.c to fix a RHEL/CentOS 7 and
   below build issue.
3) Build new file context based on the original in
   create_file_change_context.c
4) Use "runcon `id -Z` quotacheck ..." to resolve RHEL-6 test run issue.
5) Fix free() contexts in create_file_change_context.c and
   check_mount_context.c

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 }')

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

 defconfig                                     |   6 +
 policy/Makefile                               |   7 +
 policy/test_filesystem.te                     | 373 +++++++
 policy/test_filesystem_name_trans.te          |  20 +
 tests/Makefile                                |   7 +
 tests/filesystem/.gitignore                   |  11 +
 tests/filesystem/Makefile                     |  16 +
 tests/filesystem/check_file_context.c         |  75 ++
 tests/filesystem/check_mount_context.c        | 127 +++
 tests/filesystem/create_file.c                | 117 +++
 tests/filesystem/create_file_change_context.c | 146 +++
 tests/filesystem/fanotify_fs.c                |  79 ++
 tests/filesystem/fs_relabel.c                 | 138 +++
 tests/filesystem/grim_reaper.c                |  89 ++
 tests/filesystem/mount.c                      | 130 +++
 tests/filesystem/quotas_test.c                | 143 +++
 tests/filesystem/statfs_test.c                |  65 ++
 tests/filesystem/test                         | 966 ++++++++++++++++++
 tests/filesystem/umount.c                     |  84 ++
 19 files changed, 2599 insertions(+)
 create mode 100644 policy/test_filesystem.te
 create mode 100644 policy/test_filesystem_name_trans.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.24.1


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

* [PATCH V6 1/1] selinux-testsuite: Add filesystem tests
  2020-01-16 18:51 [PATCH V6 0/1] selinux-testsuite: Add filesystem tests Richard Haines
@ 2020-01-16 18:51 ` Richard Haines
  2020-01-17 17:32   ` Stephen Smalley
  0 siblings, 1 reply; 4+ messages in thread
From: Richard Haines @ 2020-01-16 18:51 UTC (permalink / raw)
  To: selinux; +Cc: Richard Haines

Test filesystem permissions, setfscreatecon(3), file { quotaon } and
changing file context via non and name-based type_transition rules.
The name-based rules only apply to MOD_POL_VERS=>11 and POL_VERS=>25

From kernels 5.5 filesystem { watch } is also tested.

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
---
 defconfig                                     |   6 +
 policy/Makefile                               |   7 +
 policy/test_filesystem.te                     | 373 +++++++
 policy/test_filesystem_name_trans.te          |  20 +
 tests/Makefile                                |   7 +
 tests/filesystem/.gitignore                   |  11 +
 tests/filesystem/Makefile                     |  16 +
 tests/filesystem/check_file_context.c         |  75 ++
 tests/filesystem/check_mount_context.c        | 127 +++
 tests/filesystem/create_file.c                | 117 +++
 tests/filesystem/create_file_change_context.c | 146 +++
 tests/filesystem/fanotify_fs.c                |  79 ++
 tests/filesystem/fs_relabel.c                 | 138 +++
 tests/filesystem/grim_reaper.c                |  89 ++
 tests/filesystem/mount.c                      | 130 +++
 tests/filesystem/quotas_test.c                | 143 +++
 tests/filesystem/statfs_test.c                |  65 ++
 tests/filesystem/test                         | 966 ++++++++++++++++++
 tests/filesystem/umount.c                     |  84 ++
 19 files changed, 2599 insertions(+)
 create mode 100644 policy/test_filesystem.te
 create mode 100644 policy/test_filesystem_name_trans.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..33378b5 100644
--- a/policy/Makefile
+++ b/policy/Makefile
@@ -114,6 +114,13 @@ 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
+ifeq ($(shell [ $(MOD_POL_VERS) -ge 11 -a $(POL_VERS) -ge 25 ] && echo true),true)
+TARGETS += test_filesystem_name_trans.te
+endif
+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..a029a1b
--- /dev/null
+++ b/policy/test_filesystem.te
@@ -0,0 +1,373 @@
+#
+######### Test filesystem permissions policy module ##########
+#
+# Note: The name-based type_transition rules are in test_filesystem_name_trans.te
+#
+attribute filesystemdomain;
+kernel_setsched(filesystemdomain)
+
+#################### Create test file contexts ######################
+type test_filesystem_filecon_t;
+files_type(test_filesystem_filecon_t)
+
+# type transition context:
+type test_filesystem_filetranscon_t;
+files_type(test_filesystem_filetranscon_t)
+
+type test_filesystem_file_t;
+files_type(test_filesystem_file_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 test_file_t:dir { add_name mounton write remove_name rmdir };
+# Create test file
+allow test_filesystem_t test_filesystem_file_t:dir { read add_name write search };
+allow test_filesystem_t test_filesystem_file_t:file { open getattr create write 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_file_t:s0";
+fs_associate(test_filesystem_file_t)
+fs_getattr_xattr_fs(test_filesystem_t)
+
+# Update quotas
+fs_set_all_quotas(test_filesystem_t)
+allow test_filesystem_t test_filesystem_file_t:file { quotaon };
+
+# Create file and change context via setfilecon(3):
+fs_associate(test_filesystem_filecon_t)
+allow test_filesystem_t test_filesystem_filecon_t:file { open read getattr relabelto write };
+
+# Create file and change context via type_transition rule:
+fs_associate(test_filesystem_filetranscon_t)
+type_transition test_filesystem_t test_filesystem_file_t:file test_filesystem_filetranscon_t;
+allow test_filesystem_t test_filesystem_filetranscon_t:file { create getattr open write relabelfrom };
+dontaudit unconfined_t test_filesystem_filetranscon_t:file { getattr read };
+
+#################### Deny filesystem { relabelfrom } ######################
+# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM
+type test_filesystem_sb_relabel_no_relabelfrom_t;
+domain_type(test_filesystem_sb_relabel_no_relabelfrom_t)
+unconfined_runs_test(test_filesystem_sb_relabel_no_relabelfrom_t)
+typeattribute test_filesystem_sb_relabel_no_relabelfrom_t testdomain;
+typeattribute test_filesystem_sb_relabel_no_relabelfrom_t filesystemdomain;
+
+allow test_filesystem_sb_relabel_no_relabelfrom_t self:capability { sys_admin };
+fs_associate(test_filesystem_sb_relabel_no_relabelfrom_t)
+allow test_filesystem_sb_relabel_no_relabelfrom_t test_file_t:dir { mounton write remove_name rmdir };
+
+#################### Deny filesystem { relabelto } ######################
+# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO
+type test_filesystem_sb_relabel_no_relabelto_t;
+domain_type(test_filesystem_sb_relabel_no_relabelto_t)
+unconfined_runs_test(test_filesystem_sb_relabel_no_relabelto_t)
+typeattribute test_filesystem_sb_relabel_no_relabelto_t testdomain;
+typeattribute test_filesystem_sb_relabel_no_relabelto_t filesystemdomain;
+
+allow test_filesystem_sb_relabel_no_relabelto_t self:capability { sys_admin };
+fs_mount_all_fs(test_filesystem_sb_relabel_no_relabelto_t)
+fs_relabelfrom_all_fs(test_filesystem_sb_relabel_no_relabelto_t)
+fs_associate(test_filesystem_sb_relabel_no_relabelto_t)
+allow test_filesystem_sb_relabel_no_relabelto_t test_file_t:dir { mounton write remove_name rmdir };
+
+#################### Deny filesystem { relabelfrom } ######################
+# hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM
+type test_filesystem_no_inode_no_relabelfrom_t;
+domain_type(test_filesystem_no_inode_no_relabelfrom_t)
+unconfined_runs_test(test_filesystem_no_inode_no_relabelfrom_t)
+typeattribute test_filesystem_no_inode_no_relabelfrom_t testdomain;
+typeattribute test_filesystem_no_inode_no_relabelfrom_t filesystemdomain;
+
+allow test_filesystem_no_inode_no_relabelfrom_t self:capability { sys_admin };
+fs_associate(test_filesystem_no_inode_no_relabelfrom_t)
+allow test_filesystem_no_inode_no_relabelfrom_t test_file_t:dir { mounton write remove_name rmdir };
+
+#################### Deny filesystem { associate } ######################
+# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE
+type test_filesystem_inode_relabel_no_associate_t;
+domain_type(test_filesystem_inode_relabel_no_associate_t)
+unconfined_runs_test(test_filesystem_inode_relabel_no_associate_t)
+typeattribute test_filesystem_inode_relabel_no_associate_t testdomain;
+typeattribute test_filesystem_inode_relabel_no_associate_t filesystemdomain;
+
+allow test_filesystem_inode_relabel_no_associate_t self:capability { sys_admin };
+allow test_filesystem_inode_relabel_no_associate_t self:filesystem { relabelto mount relabelfrom };
+fs_mount_all_fs(test_filesystem_inode_relabel_no_associate_t)
+fs_relabelfrom_all_fs(test_filesystem_inode_relabel_no_associate_t)
+allow test_filesystem_inode_relabel_no_associate_t test_file_t:dir { mounton write remove_name rmdir };
+
+########## Deny filesystem { associate } for create file ################
+# hooks.c may_create() FILESYSTEM__ASSOCIATE
+type test_filesystem_may_create_no_associate_t;
+domain_type(test_filesystem_may_create_no_associate_t)
+unconfined_runs_test(test_filesystem_may_create_no_associate_t)
+typeattribute test_filesystem_may_create_no_associate_t testdomain;
+typeattribute test_filesystem_may_create_no_associate_t filesystemdomain;
+
+allow test_filesystem_may_create_no_associate_t self:capability { sys_admin };
+allow test_filesystem_may_create_no_associate_t self:filesystem { mount relabelfrom relabelto unmount associate };
+allow test_filesystem_may_create_no_associate_t test_file_t:dir { mounton write remove_name rmdir };
+allow test_filesystem_may_create_no_associate_t self:dir { mounton add_name write };
+
+fs_mount_all_fs(test_filesystem_may_create_no_associate_t)
+fs_unmount_all_fs(test_filesystem_may_create_no_associate_t)
+fs_relabelfrom_all_fs(test_filesystem_may_create_no_associate_t)
+fs_associate(test_filesystem_may_create_no_associate_t)
+fs_getattr_xattr_fs(test_filesystem_may_create_no_associate_t)
+
+# Create test file
+# neverallow unlabeled_t test_filesystem_may_create_no_associate_t:filesystem { associate };
+allow test_filesystem_may_create_no_associate_t self:file { create relabelfrom relabelto };
+allow test_filesystem_may_create_no_associate_t unconfined_t:file { open read write };
+allow test_filesystem_may_create_no_associate_t unlabeled_t:dir { add_name search write };
+allow test_filesystem_may_create_no_associate_t unlabeled_t:file { create open relabelfrom write };
+
+#################### Deny filesystem { quotamod } ######################
+# hooks.c selinux_quotactl() 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 test_file_t:dir { mounton write remove_name rmdir };
+
+#################### Deny filesystem { quotaget } ######################
+# hooks.c selinux_quotactl() 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 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)
+
+#################### Deny file { quotaon } ######################
+# hooks.c selinux_quota_on() FILE__QUOTAON
+type test_file_no_quotaon_t;
+domain_type(test_file_no_quotaon_t)
+unconfined_runs_test(test_file_no_quotaon_t)
+typeattribute test_file_no_quotaon_t testdomain;
+typeattribute test_file_no_quotaon_t filesystemdomain;
+
+allow test_file_no_quotaon_t self:capability { sys_admin };
+allow test_file_no_quotaon_t self:filesystem { quotamod relabelto mount unmount relabelfrom };
+allow test_file_no_quotaon_t test_file_t:dir { mounton write remove_name rmdir };
+# neverallow test_file_no_quotaon_t self:file { quotaon };
+fs_mount_all_fs(test_file_no_quotaon_t)
+fs_relabelfrom_all_fs(test_file_no_quotaon_t)
+fs_associate(test_file_no_quotaon_t)
+# Required as $private_path to quota files
+files_search_all(test_file_no_quotaon_t)
+# For running quotacheck(8)
+files_type(test_file_no_quotaon_t)
+
+#################### Deny filesystem { mount } ######################
+# hooks.c selinux_sb_kern_mount() 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 test_file_t:dir { mounton write remove_name rmdir };
+
+#################### Deny filesystem { getattr } ######################
+# hooks.c selinux_sb_statfs() 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 test_file_t:dir { mounton write remove_name rmdir };
+
+#################### Deny filesystem { remount } ######################
+# hooks.c selinux_mount() 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 test_file_t:dir { mounton write remove_name rmdir };
+
+#################### Deny filesystem { unmount } ######################
+# hooks.c selinux_umount() 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 test_file_t:dir { mounton write remove_name rmdir };
+
+########## Deny filesystem { associate } for setxattr ################
+# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE
+type test_filesystem_inode_setxattr_no_associate_t;
+domain_type(test_filesystem_inode_setxattr_no_associate_t)
+unconfined_runs_test(test_filesystem_inode_setxattr_no_associate_t)
+typeattribute test_filesystem_inode_setxattr_no_associate_t testdomain;
+typeattribute test_filesystem_inode_setxattr_no_associate_t filesystemdomain;
+
+allow test_filesystem_inode_setxattr_no_associate_t self:capability { sys_admin };
+allow test_filesystem_inode_setxattr_no_associate_t self:filesystem { mount relabelfrom relabelto unmount associate };
+allow test_filesystem_inode_setxattr_no_associate_t self:dir { mounton add_name write };
+allow test_filesystem_inode_setxattr_no_associate_t test_file_t:dir { mounton write remove_name rmdir };
+
+fs_mount_all_fs(test_filesystem_inode_setxattr_no_associate_t)
+fs_unmount_all_fs(test_filesystem_inode_setxattr_no_associate_t)
+fs_relabelfrom_all_fs(test_filesystem_inode_setxattr_no_associate_t)
+fs_getattr_xattr_fs(test_filesystem_inode_setxattr_no_associate_t)
+fs_associate(test_filesystem_inode_setxattr_no_associate_t)
+
+# Create test file
+allow test_filesystem_inode_setxattr_no_associate_t self:file { create relabelfrom relabelto };
+# neverallow unconfined_t test_filesystem_inode_setxattr_no_associate_t:filesystem { associate };
+dontaudit unconfined_t test_filesystem_filecon_t:file { getattr read };
+allow test_filesystem_inode_setxattr_no_associate_t unconfined_t:dir { add_name write };
+allow test_filesystem_inode_setxattr_no_associate_t unconfined_t:file { create relabelfrom relabelto };
+
+#allow test_filesystem_inode_setxattr_no_associate_t unconfined_t:file { open read getattr write };
+
+#################### Deny filesystem { watch } ######################
+# hooks.c selinux_path_notify() 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 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)
+
+################# 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 };
+allow test_setfscreatecon_t test_file_t:dir { add_name write remove_name };
+
+# Set new context on fs:
+type test_setfscreatecon_newcon_t;
+unconfined_runs_test(test_setfscreatecon_newcon_t)
+fs_associate(test_setfscreatecon_newcon_t)
+allow test_setfscreatecon_t test_setfscreatecon_newcon_t:dir { create getattr rmdir };
+
+################# 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;
+
+type test_filesystem_fscontext_fs_t;
+files_type(test_filesystem_fscontext_fs_t)
+
+allow test_filesystem_fscontext_t self:capability { sys_admin };
+allow test_filesystem_fscontext_t test_file_t:dir { mounton };
+allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { getattr open read relabelto write };
+allow test_filesystem_fscontext_t test_filesystem_fscontext_fs_t:dir { add_name search write };
+allow test_filesystem_fscontext_t test_filesystem_fscontext_fs_t:file { create getattr open relabelfrom write };
+allow test_filesystem_fscontext_t test_filesystem_fscontext_fs_t:filesystem { mount relabelto unmount };
+fs_relabelfrom_all_fs(test_filesystem_fscontext_t)
+files_search_all(test_filesystem_fscontext_t)
+allow test_filesystem_filecon_t test_filesystem_fscontext_fs_t:filesystem associate;
+
+########### Test context= #################
+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;
+
+type test_filesystem_context_file_t;
+files_type(test_filesystem_context_file_t)
+
+allow test_filesystem_context_t self:capability { sys_admin };
+allow test_filesystem_context_t test_file_t:dir { mounton };
+allow test_filesystem_context_t test_filesystem_context_file_t:dir { add_name search write };
+allow test_filesystem_context_t test_filesystem_context_file_t:file { create getattr open read relabelfrom write };
+allow test_filesystem_context_t test_filesystem_context_file_t:filesystem { mount relabelfrom relabelto unmount };
+allow test_filesystem_context_t test_filesystem_filecon_t:file { getattr open read relabelto write };
+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)
+
+# For testing defcontext=
+allow test_filesystem_fscontext_t test_filesystem_context_file_t:dir { add_name write };
+allow test_filesystem_fscontext_t test_filesystem_context_file_t:file { create getattr open write };
+
+# 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 };
+
+#
+########### 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/policy/test_filesystem_name_trans.te b/policy/test_filesystem_name_trans.te
new file mode 100644
index 0000000..ce04601
--- /dev/null
+++ b/policy/test_filesystem_name_trans.te
@@ -0,0 +1,20 @@
+#
+######### Test filesystem name-base transition policy module ##########
+#
+
+# Name-based type transition context:
+type test_filesystem_filenametranscon1_t;
+files_type(test_filesystem_filenametranscon1_t)
+type test_filesystem_filenametranscon2_t;
+files_type(test_filesystem_filenametranscon2_t)
+
+# Create file and change context via name-based type_transition rule:
+fs_associate(test_filesystem_filenametranscon1_t)
+type_transition test_filesystem_t test_filesystem_file_t:file test_filesystem_filenametranscon1_t "name_trans_test_file1";
+allow test_filesystem_t test_filesystem_filenametranscon1_t:file { create getattr open write };
+dontaudit unconfined_t test_filesystem_filenametranscon1_t:file { getattr read };
+#
+fs_associate(test_filesystem_filenametranscon2_t)
+type_transition test_filesystem_t test_filesystem_file_t:file test_filesystem_filenametranscon2_t "name_trans_test_file2";
+allow test_filesystem_t test_filesystem_filenametranscon2_t:file { create getattr open write };
+dontaudit unconfined_t test_filesystem_filenametranscon2_t:file { getattr read };
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..a522e96
--- /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 -f file -e cxt [-v]\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..2899dea
--- /dev/null
+++ b/tests/filesystem/check_mount_context.c
@@ -0,0 +1,127 @@
+#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 -m mp [-e ctx] [-r] [-v]\n"
+		"Where:\n\t"
+		"-m  Mount point\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;
+	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");
+			result = -1;
+			goto err;
+		}
+
+		if (context_type_set(con_t, type)) {
+			fprintf(stderr, "Unable to set new type\n");
+			free(con_t);
+			result = -1;
+			goto err;
+		}
+
+		newcon = context_str(con_t);
+		free(con_t);
+		if (!newcon) {
+			fprintf(stderr, "Unable to obtain new context string\n");
+			result = -1;
+			goto err;
+		}
+
+		result = setfilecon(mount, newcon);
+		free(newcon);
+		if (result < 0) {
+			fprintf(stderr, "setfilecon(3) Failed: %s\n",
+				strerror(errno));
+			result = -1;
+			goto err;
+		}
+
+		free(context);
+
+		result = getfilecon(mount, &context);
+		if (result < 0) {
+			fprintf(stderr, "getfilecon(3) Failed: %s\n",
+				strerror(errno));
+			return result;
+		}
+		result = 0;
+
+		if (verbose)
+			printf("Set new MP context: %s\n", context);
+
+	} 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..ab8f20f
--- /dev/null
+++ b/tests/filesystem/create_file.c
@@ -0,0 +1,117 @@
+#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>
+#include <selinux/context.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s -f file [-e type] [-v]\n"
+		"Where:\n\t"
+		"-f  File to create\n\t"
+		"-e  Expected file context type\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, *type = NULL;
+	const char *file_type;
+	bool verbose = false;
+	context_t con_t;
+
+	while ((opt = getopt(argc, argv, "f:e:v")) != -1) {
+		switch (opt) {
+		case 'f':
+			file = optarg;
+			break;
+		case 'e':
+			type = 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;
+	}
+
+	if (verbose)
+		printf("Created file: %s\n", file);
+
+	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: %s\n", context);
+
+	if (type) {
+		con_t = context_new(context);
+		if (!con_t) {
+			fprintf(stderr, "Unable to create context structure\n");
+			result = -1;
+			goto err;
+		}
+
+		file_type = context_type_get(con_t);
+		if (!file_type) {
+			fprintf(stderr, "Unable to get new type\n");
+			free(con_t);
+			result = -1;
+			goto err;
+		}
+
+		if (strcmp(type, file_type)) {
+			fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n",
+				type, file_type);
+			result = -1;
+		} else {
+			result = 0;
+			if (verbose)
+				printf("File context is correct\n");
+		}
+		free(con_t);
+	}
+
+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..83f780e
--- /dev/null
+++ b/tests/filesystem/create_file_change_context.c
@@ -0,0 +1,146 @@
+#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 -f file -t type [-v]\n"
+		"Where:\n\t"
+		"-f  File to create\n\t"
+		"-t  Type for context of created file\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+	int opt, result, fd, save_err;
+	char *newfcon = NULL, *orgfcon = NULL, *type = NULL, *file = NULL;
+	char *context;
+	bool verbose = false;
+	context_t con_t;
+
+	while ((opt = getopt(argc, argv, "f:t:v")) != -1) {
+		switch (opt) {
+		case 'f':
+			file = optarg;
+			break;
+		case 't':
+			type = optarg;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!type || !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);
+	}
+
+	/* 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));
+		return save_err;
+	}
+	if (verbose)
+		printf("Created file: %s\n", file);
+
+	result = fgetfilecon(fd, &orgfcon);
+	if (result < 0) {
+		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
+			strerror(errno));
+		close(fd);
+		return -1;
+	}
+	if (verbose)
+		printf("Current file context is: %s\n", orgfcon);
+
+	/* Build new file context */
+	con_t = context_new(orgfcon);
+	if (!con_t) {
+		fprintf(stderr, "Unable to create context structure\n");
+		result = -1;
+		goto err;
+	}
+
+	if (context_type_set(con_t, type)) {
+		fprintf(stderr, "Unable to set new type\n");
+		free(con_t);
+		result = -1;
+		goto err;
+	}
+
+	newfcon = context_str(con_t);
+	free(con_t);
+	if (!newfcon) {
+		fprintf(stderr, "Unable to obtain new context string\n");
+		result = -1;
+		goto err;
+	}
+
+	/* hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE */
+	result = fsetfilecon(fd, newfcon);
+	save_err = errno;
+	close(fd);
+	if (result < 0) {
+		fprintf(stderr, "fsetfilecon(3) Failed: %s\n",
+			strerror(errno));
+		result = save_err;
+		goto err1;
+	}
+
+	fd = open(file, O_RDWR);
+	if (fd < 0) {
+		fprintf(stderr, "open(2) Failed: %s\n", strerror(errno));
+		result = -1;
+		goto err1;
+	}
+
+	result = fgetfilecon(fd, &context);
+	if (result < 0) {
+		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
+			strerror(errno));
+		result = -1;
+		goto err1;
+	}
+	if (verbose)
+		printf("New 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(orgfcon);
+err1:
+	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..c525d69
--- /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 -t path [-v]\n"
+		"Where:\n\t"
+		"-t  Target mount point to mark\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..8ebc0bf
--- /dev/null
+++ b/tests/filesystem/fs_relabel.c
@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/unistd.h>
+#include <linux/limits.h>
+#include <selinux/selinux.h>
+#include <selinux/context.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s -b path -t type [-v]\n"
+		"Where:\n\t"
+		"-b  base directory\n\t"
+		"-t  Type for fs context to generate on base/mp1\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char **argv)
+{
+	int opt, result, save_err;
+	char *context, *fs_con = NULL, *newcon = NULL, *base_dir, *type;
+	char fs_mount[PATH_MAX];
+	bool verbose = false;
+	context_t con_t;
+
+	while ((opt = getopt(argc, argv, "b:t:v")) != -1) {
+		switch (opt) {
+		case 'b':
+			base_dir = optarg;
+			break;
+		case 't':
+			type = optarg;
+			break;
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	if (!type || !base_dir)
+		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 = getfilecon(base_dir, &context);
+	if (result < 0) {
+		fprintf(stderr, "getfilecon(3) Failed: %s\n",
+			strerror(errno));
+		return -1;
+	}
+	if (verbose)
+		printf("%s context is: %s\n", base_dir, context);
+
+	/* Build new context for fs */
+	con_t = context_new(context);
+	if (!con_t) {
+		fprintf(stderr, "Unable to create context structure\n");
+		result = -1;
+		goto err;
+	}
+
+	if (context_type_set(con_t, type)) {
+		fprintf(stderr, "Unable to set new type\n");
+		free(con_t);
+		result = -1;
+		goto err;
+	}
+
+	newcon = context_str(con_t);
+	free(con_t);
+	if (!newcon) {
+		fprintf(stderr, "Unable to obtain new context string\n");
+		result = -1;
+		goto err;
+	}
+
+	result = setfscreatecon(newcon);
+	save_err = errno;
+	if (result < 0) {
+		fprintf(stderr, "Failed setfscreatecon(3): %s\n",
+			strerror(errno));
+		result = save_err;
+		goto err;
+	}
+
+	sprintf(fs_mount, "%s/%s", base_dir, "mp1");
+
+	result = mkdir(fs_mount, 0777);
+	if (result < 0) {
+		fprintf(stderr, "mkdir(2) Failed: %s\n", strerror(errno));
+		goto err;
+	}
+
+	result = getfilecon(fs_mount, &fs_con);
+	if (result < 0) {
+		fprintf(stderr, "getfilecon(3) Failed: %s\n",
+			strerror(errno));
+		goto err;
+	}
+	if (verbose)
+		printf("%s context is: %s\n", fs_mount, fs_con);
+
+	result = rmdir(fs_mount);
+	if (result < 0) {
+		fprintf(stderr, "rmdir(2) Failed: %s\n", strerror(errno));
+		goto err;
+	}
+
+	if (strcmp(newcon, fs_con)) {
+		fprintf(stderr, "FS context error, expected:\n\t%s\ngot:\n\t%s\n",
+			newcon, fs_con);
+		result = -1;
+	}
+err:
+	free(context);
+	free(newcon);
+	free(fs_con);
+
+	return result;
+}
diff --git a/tests/filesystem/grim_reaper.c b/tests/filesystem/grim_reaper.c
new file mode 100644
index 0000000..340546a
--- /dev/null
+++ b/tests/filesystem/grim_reaper.c
@@ -0,0 +1,89 @@
+#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
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s -t tgt [-v]\n"
+		"Where:\n\t"
+		"-t  target to unmount if active\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	FILE *fp;
+	size_t len;
+	ssize_t num;
+	int opt, index = 0, i, result = 0;
+	char *mount_info[2], *buf = NULL, *item, *tgt;
+	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]);
+
+	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], tgt) == 0) {
+			if (verbose)
+				printf("Unmounting %s from %s\n",
+				       mount_info[1], mount_info[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..8359811
--- /dev/null
+++ b/tests/filesystem/quotas_test.c
@@ -0,0 +1,143 @@
+#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>
+
+/*
+ * This is required 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>
+ */
+#ifndef QFMT_VFS_V0
+#define QFMT_VFS_V0 2
+#endif
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s -s src -t tgt [-v]\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..310b66d
--- /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 -t path [-v]\n"
+		"Where:\n\t"
+		"-t  Target path to statfs(2)\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..f53ccfe
--- /dev/null
+++ b/tests/filesystem/test
@@ -0,0 +1,966 @@
+#!/usr/bin/perl
+use Test::More;
+
+BEGIN {
+    $basedir = $0;
+    $basedir =~ s|(.*)/[^/]*|$1|;
+
+    $test_count = 68;
+
+    # Options: -v = Verbose, -d disable udisks(8) daemon
+    $v              = " ";
+    $disable_udisks = 0;
+    $udisks2_status = 0;
+    foreach $arg (@ARGV) {
+        if ( $arg eq "-v" ) {
+            $v = $arg;
+        }
+        elsif ( $arg eq "-d" ) {
+            $disable_udisks = 1;
+        }
+    }
+
+    # 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;
+    }
+
+    $test_name_trans = 0;
+    $pol_vers        = `checkpolicy -V | cut -f 1 -d ' '`;
+    $mod_pol_vers    = `checkmodule -V | cut -f 2 -d '-'`;
+
+    if ( $mod_pol_vers >= 11 and $pol_vers >= 25 ) {
+        $test_name_trans = 1;
+        $test_count += 2;
+    }
+
+    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;
+
+# Optionally stop the udisks(8) daemon, then restart on exit.
+sub udisks2_stop {
+    $status = 0;
+
+    if ( -e "/usr/bin/systemctl" ) {
+        $u_status_cmd = "/usr/bin/systemctl status udisks2 >& /dev/null";
+        $u_stop_cmd   = "/usr/bin/systemctl stop udisks2 >& /dev/null";
+    }
+    elsif ( -e "/usr/sbin/service" ) {
+        $u_status_cmd = "/usr/sbin/service udisks2 status >& /dev/null";
+        $u_stop_cmd   = "/usr/sbin/service udisks2 stop >& /dev/null";
+    }
+
+    if ($u_status_cmd) {
+        $result = system("$u_status_cmd");
+        $status = $result >> 8;
+        if ( $status eq 0 ) {
+            print "Stopping udisks2 service for these tests.\n";
+            system("$u_stop_cmd");
+            $status = 3;
+        }
+        else {
+            $status = 4;
+        }
+    }
+    return $status;
+}
+
+sub udisks2_restart {
+    my ($status) = @_;
+
+    if ( $status eq 3 ) {
+        print "Restarting udisks2 service.\n";
+        if ( -e "/usr/bin/systemctl" ) {
+            system("/usr/bin/systemctl start udisks2 >& /dev/null");
+        }
+        elsif ( -e "/usr/sbin/service" ) {
+            system("/usr/sbin/service udisks2 start >& /dev/null");
+        }
+    }
+}
+
+sub get_loop_dev {
+    system("udevadm settle");
+    print "Finding free /dev/loop entry\n";
+    $get_dev = `losetup -f 2>/dev/null`;
+    chomp($get_dev);
+    if ( $get_dev eq "" ) {
+        print "losetup failed to obtain /dev/loop entry\n";
+    }
+
+    # Keep list of devices for cleanup later
+    if ( $device_count eq 0 ) {
+        $device_list[$device_count] = $get_dev;
+        $device_count += 1;
+    }
+    elsif ( $get_dev ne $device_list[ $device_count - 1 ] ) {
+        $device_list[$device_count] = $get_dev;
+        $device_count += 1;
+    }
+    return $get_dev;
+}
+
+sub attach_dev {
+    my ( $att_dev, $base ) = @_;
+    system("udevadm settle");
+    print "Attaching $base/fstest to $att_dev\n";
+    $result = system("losetup $att_dev $base/fstest 2>/dev/null");
+    if ( $result != 0 ) {
+        print "Failed to attach $base/fstest to $att_dev\n";
+    }
+    system("udevadm settle");
+}
+
+sub make_fs {
+    my ( $mk_type, $mk_dev, $mk_dir ) = @_;
+    print "Create $mk_dir/fstest with dd\n";
+    $result = system(
+        "dd if=/dev/zero of=$mk_dir/fstest bs=1024 count=10240 2>/dev/null");
+    if ( $result != 0 ) {
+        print "dd failed to create $mk_dir/fstest\n";
+    }
+
+    attach_dev( $mk_dev, $mk_dir );
+
+    print "Make $mk_type filesystem on $mk_dev\n";
+    $result = system("mkfs.$mk_type -I 256 $mk_dev >& /dev/null");
+    if ( $result != 0 ) {
+        system("losetup -d $mk_dev 2>/dev/null");
+        print "mkfs.$mk_type failed to create filesystem on $mk_dev\n";
+    }
+}
+
+sub mk_mntpoint_1 {
+    my ($path) = @_;
+    system("rm -rf $path/mp1 2>/dev/null");
+    system("mkdir -p $path/mp1 2>/dev/null");
+}
+
+sub mk_mntpoint_2 {
+    my ($path) = @_;
+    system("rm -rf $path/mp2 2>/dev/null");
+    system("mkdir -p $path/mp2 2>/dev/null");
+}
+
+sub cleanup {
+    my ($base) = @_;
+    system("rm -rf $base/fstest 2>/dev/null");
+    system("rm -rf $base/mntpoint 2>/dev/null");
+}
+
+sub cleanup1 {
+    my ( $base, $d ) = @_;
+    system("udevadm settle");
+    system("losetup -d $d 2>/dev/null");
+    system("udevadm settle");
+    system("rm -rf $base/fstest 2>/dev/null");
+    system("rm -rf $base/mntpoint 2>/dev/null");
+}
+
+# Cleanup any attached /dev/loop entries
+sub reaper {
+    my ( $base, $v ) = @_;
+
+    foreach my $n (@device_list) {
+        system("$base/grim_reaper -t $n $v 2>/dev/null");
+    }
+}
+
+# End subroutines
+
+if ($disable_udisks) {
+    $udisks2_status = udisks2_stop();
+}
+
+cleanup($basedir);
+
+############### Test setfscreatecon(3) ##########################
+system("mkdir -p $basedir/mntpoint 2>/dev/null");
+
+print "Test setfscreatecon(3)\n";
+$result = system
+"runcon -t test_setfscreatecon_t $basedir/fs_relabel $v -b $basedir/mntpoint -t test_setfscreatecon_newcon_t";
+ok( $result eq 0 );
+
+$result = system
+"runcon -t test_no_setfscreatecon_t $basedir/fs_relabel $v -b $basedir/mntpoint -t test_setfscreatecon_newcon_t 2>&1";
+ok( $result >> 8 eq 13 );
+
+system("rm -rf $basedir/mntpoint 2>/dev/null");
+
+############### Test Basic Mount/Unmount ##########################
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$mount_opts1 =
+"quota,usrquota,grpquota,defcontext=system_u:object_r:test_filesystem_file_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";
+
+# On RHEL-6, there is a type transition to quota_t when running quotacheck
+# as unconfined_t. Using "runcon `id -Z` quotacheck ..." resolves this.
+$result = system("runcon `id -Z` 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 'trans_test_file' and checking context changed via type_transition rule\n";
+$result =
+  system(
+"runcon -t test_filesystem_t $basedir/create_file -f $private_path/mp1/trans_test_file -e test_filesystem_filetranscon_t $v"
+  );
+ok( $result eq 0 );
+
+print "Creating 'test_file' and changing its context via setfilecon(3)\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_name_trans) {
+    print
+"Creating 'name_trans_test_file1' and checking context changed via name-based type_transition rule\n";
+    $result = system(
+"runcon -t test_filesystem_t $basedir/create_file -f $private_path/mp1/name_trans_test_file1 -e test_filesystem_filenametranscon1_t $v"
+    );
+    ok( $result eq 0 );
+
+    print
+"Creating 'name_trans_test_file2' and checking context changed via name-based type_transition rule\n";
+    $result = system(
+"runcon -t test_filesystem_t $basedir/create_file -f $basedir/mntpoint/mp1/name_trans_test_file2 -e test_filesystem_filenametranscon2_t $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( $basedir, $dev );
+
+############### Test Move Mount ##########################
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$mount_opts2 =
+"quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_file_t:s0";
+
+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_2($private_path);
+
+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( $basedir, $dev );
+
+############### Deny filesystem { relabelfrom } ##########################
+# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_relabelfrom =
+  "defcontext=system_u:object_r:test_filesystem_sb_relabel_no_relabelfrom_t:s0";
+
+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_sb_relabel_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( $basedir, $dev );
+
+############### Deny filesystem { relabelto } ##########################
+# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_relabelto =
+  "fscontext=system_u:object_r:test_filesystem_sb_relabel_no_relabelto_t:s0";
+
+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_sb_relabel_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( $basedir, $dev );
+
+############### Deny filesystem { relabelfrom } ##########################
+# hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_relabelfrom =
+  "rootcontext=system_u:object_r:test_filesystem_no_inode_no_relabelfrom_t:s0";
+
+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_inode_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( $basedir, $dev );
+
+############### Deny filesystem { associate } ##########################
+# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+
+# This defcontext will trigger denial.
+$opts_no_associate =
+"defcontext=system_u:object_r:test_filesystem_inode_relabel_no_associate_t:s0";
+
+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_inode_relabel_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( $basedir, $dev );
+
+############### Deny filesystem { associate } ##########################
+# hooks.c may_create() FILESYSTEM__ASSOCIATE
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+
+# Use this fscontext= to get sensible audit log entry of:
+#  "allow unlabeled_t test_filesystem_may_create_no_associate_t:filesystem associate;"
+$opts_no_associate_file =
+  "fscontext=system_u:object_r:test_filesystem_may_create_no_associate_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_may_create_no_associate_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_may_create_no_associate_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_may_create_no_associate_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+  );
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1( $basedir, $dev );
+
+############### Deny filesystem { quotamod } ##########################
+# hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_quotamod =
+"quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesystem_no_quotamod_t:s0";
+
+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( $basedir, $dev );
+
+############### Deny filesystem { quotaget } ##########################
+# hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_quotaget =
+"quota,usrquota,grpquota,context=system_u:object_r:test_filesystem_no_quotaget_t:s0";
+
+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("runcon `id -Z` 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( $basedir, $dev );
+
+############### Deny file { quotaon } ##########################
+# hooks.c selinux_quota_on() FILE__QUOTAON
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_quotaon =
+  "quota,usrquota,grpquota,context=system_u:object_r:test_file_no_quotaon_t:s0";
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_quotaon\n";
+$result = system(
+"runcon -t test_file_no_quotaon_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotaon $v"
+);
+ok( $result eq 0 );
+
+print "Running quotacheck(8) to init user/group quota files\n";
+$result = system("runcon `id -Z` quotacheck -ugF vfsv0 $private_path/mp1");
+ok( $result eq 0 );
+
+print "Toggle User quotas on/off\n";    # Must have full path
+$result = system(
+"runcon -t test_file_no_quotaon_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_file_no_quotaon_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+);
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1( $basedir, $dev );
+
+############### Deny filesystem { mount } ##########################
+# hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_mount = "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0";
+
+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( $basedir, $dev );
+
+############### Deny filesystem { getattr } ##########################
+# hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_getattr =
+  "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0";
+
+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( $basedir, $dev );
+
+############### Deny filesystem { remount } ##########################
+# hooks.c selinux_mount() FILESYSTEM__REMOUNT
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_remount =
+  "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0";
+
+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( $basedir, $dev );
+
+############### Deny filesystem { unmount } ##########################
+# hooks.c selinux_umount() FILESYSTEM__UNMOUNT
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_unmount =
+  "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0";
+
+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( $basedir, $dev );
+
+############### Deny filesystem { associate }  ##########################
+# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$opts_no_associate_xattr =
+"defcontext=system_u:object_r:test_filesystem_inode_setxattr_no_associate_t:s0,fscontext=system_u:object_r:test_filesystem_inode_setxattr_no_associate_t:s0";
+
+print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
+print "Using mount options:\n\t$opts_no_associate_xattr\n";
+$result = system(
+"runcon -t test_filesystem_inode_setxattr_no_associate_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_xattr $v"
+);
+ok( $result eq 0 );
+
+print "Creating test file $basedir/mntpoint/mp1/test_file\n";
+$result =
+  system(
+"runcon -t test_filesystem_inode_setxattr_no_associate_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_inode_setxattr_no_associate_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
+  );
+ok( $result eq 0 );
+
+print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
+cleanup1( $basedir, $dev );
+
+############### Deny filesystem { watch }  ##########################
+# hooks.c selinux_path_notify() FILESYSTEM__WATCH
+if ($test_watch) {
+    mk_mntpoint_1($private_path);
+    $dev = get_loop_dev();
+    make_fs( $fs_type, $dev, $basedir );
+    $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( $basedir, $dev );
+}
+
+##########################################################################
+# 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.
+##########################################################################
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+
+# Mount with xttrs to create a file with specific context.
+$context1_opts =
+  "defcontext=system_u:object_r:test_filesystem_context_file_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 one and attach
+system("losetup -d $dev 2>/dev/null");
+$dev = get_loop_dev();
+attach_dev( $dev, $basedir );
+
+# Mount again with no xttr support
+$context2_opts = "context=system_u:object_r:test_filesystem_context_file_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_file_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_file_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( $basedir, $dev );
+
+##########################################################################
+# 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.
+##########################################################################
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$root_opts = "rootcontext=system_u:object_r:test_filesystem_context_file_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_file_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( $basedir, $dev );
+
+##########################################################################
+# 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.
+##########################################################################
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+make_fs( $fs_type, $dev, $basedir );
+$test_opts = "context=system_u:object_r:test_filesystem_context_file_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_file_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 -e test_filesystem_context_file_t $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");
+$dev = get_loop_dev();
+attach_dev( $dev, $basedir );
+
+# 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( $basedir, $dev );
+
+##########################################################################
+# 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";
+mk_mntpoint_1($private_path);
+$dev = get_loop_dev();
+$fscontext_opts =
+"fscontext=system_u:object_r:test_filesystem_fscontext_fs_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( $basedir, $dev );
+
+reaper( $basedir, $v );
+
+if ($disable_udisks) {
+    udisks2_restart($udisks2_status);
+}
+
+exit;
diff --git a/tests/filesystem/umount.c b/tests/filesystem/umount.c
new file mode 100644
index 0000000..3029741
--- /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 [-t] [-v]\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.24.1


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

* Re: [PATCH V6 1/1] selinux-testsuite: Add filesystem tests
  2020-01-16 18:51 ` [PATCH V6 1/1] " Richard Haines
@ 2020-01-17 17:32   ` Stephen Smalley
       [not found]     ` <0556d72199ca519fa295449bce6aabc51061c486.camel@btinternet.com>
  0 siblings, 1 reply; 4+ messages in thread
From: Stephen Smalley @ 2020-01-17 17:32 UTC (permalink / raw)
  To: Richard Haines, selinux, Ondrej Mosnacek

On 1/16/20 1:51 PM, Richard Haines wrote:
> Test filesystem permissions, setfscreatecon(3), file { quotaon } and
> changing file context via non and name-based type_transition rules.
> The name-based rules only apply to MOD_POL_VERS=>11 and POL_VERS=>25
> 
>  From kernels 5.5 filesystem { watch } is also tested.
> 
> Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>

This passes travis-ci and testing on Fedora and generally looks good to 
me.  Only question I had was whether we should be checking the kernel's 
max supported policyvers (/sys/fs/selinux/policyvers, MAX_KERNEL_POLICY 
in the policy Makefile) as well as that of checkpolicy/checkmodule, 
because otherwise the policy might compile ok but the name-based 
transitions will be discarded upon automatic downgrade at policy load 
time and the tests will fail.

> ---
>   defconfig                                     |   6 +
>   policy/Makefile                               |   7 +
>   policy/test_filesystem.te                     | 373 +++++++
>   policy/test_filesystem_name_trans.te          |  20 +
>   tests/Makefile                                |   7 +
>   tests/filesystem/.gitignore                   |  11 +
>   tests/filesystem/Makefile                     |  16 +
>   tests/filesystem/check_file_context.c         |  75 ++
>   tests/filesystem/check_mount_context.c        | 127 +++
>   tests/filesystem/create_file.c                | 117 +++
>   tests/filesystem/create_file_change_context.c | 146 +++
>   tests/filesystem/fanotify_fs.c                |  79 ++
>   tests/filesystem/fs_relabel.c                 | 138 +++
>   tests/filesystem/grim_reaper.c                |  89 ++
>   tests/filesystem/mount.c                      | 130 +++
>   tests/filesystem/quotas_test.c                | 143 +++
>   tests/filesystem/statfs_test.c                |  65 ++
>   tests/filesystem/test                         | 966 ++++++++++++++++++
>   tests/filesystem/umount.c                     |  84 ++
>   19 files changed, 2599 insertions(+)
>   create mode 100644 policy/test_filesystem.te
>   create mode 100644 policy/test_filesystem_name_trans.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..33378b5 100644
> --- a/policy/Makefile
> +++ b/policy/Makefile
> @@ -114,6 +114,13 @@ 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
> +ifeq ($(shell [ $(MOD_POL_VERS) -ge 11 -a $(POL_VERS) -ge 25 ] && echo true),true)
> +TARGETS += test_filesystem_name_trans.te
> +endif
> +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..a029a1b
> --- /dev/null
> +++ b/policy/test_filesystem.te
> @@ -0,0 +1,373 @@
> +#
> +######### Test filesystem permissions policy module ##########
> +#
> +# Note: The name-based type_transition rules are in test_filesystem_name_trans.te
> +#
> +attribute filesystemdomain;
> +kernel_setsched(filesystemdomain)
> +
> +#################### Create test file contexts ######################
> +type test_filesystem_filecon_t;
> +files_type(test_filesystem_filecon_t)
> +
> +# type transition context:
> +type test_filesystem_filetranscon_t;
> +files_type(test_filesystem_filetranscon_t)
> +
> +type test_filesystem_file_t;
> +files_type(test_filesystem_file_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 test_file_t:dir { add_name mounton write remove_name rmdir };
> +# Create test file
> +allow test_filesystem_t test_filesystem_file_t:dir { read add_name write search };
> +allow test_filesystem_t test_filesystem_file_t:file { open getattr create write 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_file_t:s0";
> +fs_associate(test_filesystem_file_t)
> +fs_getattr_xattr_fs(test_filesystem_t)
> +
> +# Update quotas
> +fs_set_all_quotas(test_filesystem_t)
> +allow test_filesystem_t test_filesystem_file_t:file { quotaon };
> +
> +# Create file and change context via setfilecon(3):
> +fs_associate(test_filesystem_filecon_t)
> +allow test_filesystem_t test_filesystem_filecon_t:file { open read getattr relabelto write };
> +
> +# Create file and change context via type_transition rule:
> +fs_associate(test_filesystem_filetranscon_t)
> +type_transition test_filesystem_t test_filesystem_file_t:file test_filesystem_filetranscon_t;
> +allow test_filesystem_t test_filesystem_filetranscon_t:file { create getattr open write relabelfrom };
> +dontaudit unconfined_t test_filesystem_filetranscon_t:file { getattr read };
> +
> +#################### Deny filesystem { relabelfrom } ######################
> +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM
> +type test_filesystem_sb_relabel_no_relabelfrom_t;
> +domain_type(test_filesystem_sb_relabel_no_relabelfrom_t)
> +unconfined_runs_test(test_filesystem_sb_relabel_no_relabelfrom_t)
> +typeattribute test_filesystem_sb_relabel_no_relabelfrom_t testdomain;
> +typeattribute test_filesystem_sb_relabel_no_relabelfrom_t filesystemdomain;
> +
> +allow test_filesystem_sb_relabel_no_relabelfrom_t self:capability { sys_admin };
> +fs_associate(test_filesystem_sb_relabel_no_relabelfrom_t)
> +allow test_filesystem_sb_relabel_no_relabelfrom_t test_file_t:dir { mounton write remove_name rmdir };
> +
> +#################### Deny filesystem { relabelto } ######################
> +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO
> +type test_filesystem_sb_relabel_no_relabelto_t;
> +domain_type(test_filesystem_sb_relabel_no_relabelto_t)
> +unconfined_runs_test(test_filesystem_sb_relabel_no_relabelto_t)
> +typeattribute test_filesystem_sb_relabel_no_relabelto_t testdomain;
> +typeattribute test_filesystem_sb_relabel_no_relabelto_t filesystemdomain;
> +
> +allow test_filesystem_sb_relabel_no_relabelto_t self:capability { sys_admin };
> +fs_mount_all_fs(test_filesystem_sb_relabel_no_relabelto_t)
> +fs_relabelfrom_all_fs(test_filesystem_sb_relabel_no_relabelto_t)
> +fs_associate(test_filesystem_sb_relabel_no_relabelto_t)
> +allow test_filesystem_sb_relabel_no_relabelto_t test_file_t:dir { mounton write remove_name rmdir };
> +
> +#################### Deny filesystem { relabelfrom } ######################
> +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM
> +type test_filesystem_no_inode_no_relabelfrom_t;
> +domain_type(test_filesystem_no_inode_no_relabelfrom_t)
> +unconfined_runs_test(test_filesystem_no_inode_no_relabelfrom_t)
> +typeattribute test_filesystem_no_inode_no_relabelfrom_t testdomain;
> +typeattribute test_filesystem_no_inode_no_relabelfrom_t filesystemdomain;
> +
> +allow test_filesystem_no_inode_no_relabelfrom_t self:capability { sys_admin };
> +fs_associate(test_filesystem_no_inode_no_relabelfrom_t)
> +allow test_filesystem_no_inode_no_relabelfrom_t test_file_t:dir { mounton write remove_name rmdir };
> +
> +#################### Deny filesystem { associate } ######################
> +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE
> +type test_filesystem_inode_relabel_no_associate_t;
> +domain_type(test_filesystem_inode_relabel_no_associate_t)
> +unconfined_runs_test(test_filesystem_inode_relabel_no_associate_t)
> +typeattribute test_filesystem_inode_relabel_no_associate_t testdomain;
> +typeattribute test_filesystem_inode_relabel_no_associate_t filesystemdomain;
> +
> +allow test_filesystem_inode_relabel_no_associate_t self:capability { sys_admin };
> +allow test_filesystem_inode_relabel_no_associate_t self:filesystem { relabelto mount relabelfrom };
> +fs_mount_all_fs(test_filesystem_inode_relabel_no_associate_t)
> +fs_relabelfrom_all_fs(test_filesystem_inode_relabel_no_associate_t)
> +allow test_filesystem_inode_relabel_no_associate_t test_file_t:dir { mounton write remove_name rmdir };
> +
> +########## Deny filesystem { associate } for create file ################
> +# hooks.c may_create() FILESYSTEM__ASSOCIATE
> +type test_filesystem_may_create_no_associate_t;
> +domain_type(test_filesystem_may_create_no_associate_t)
> +unconfined_runs_test(test_filesystem_may_create_no_associate_t)
> +typeattribute test_filesystem_may_create_no_associate_t testdomain;
> +typeattribute test_filesystem_may_create_no_associate_t filesystemdomain;
> +
> +allow test_filesystem_may_create_no_associate_t self:capability { sys_admin };
> +allow test_filesystem_may_create_no_associate_t self:filesystem { mount relabelfrom relabelto unmount associate };
> +allow test_filesystem_may_create_no_associate_t test_file_t:dir { mounton write remove_name rmdir };
> +allow test_filesystem_may_create_no_associate_t self:dir { mounton add_name write };
> +
> +fs_mount_all_fs(test_filesystem_may_create_no_associate_t)
> +fs_unmount_all_fs(test_filesystem_may_create_no_associate_t)
> +fs_relabelfrom_all_fs(test_filesystem_may_create_no_associate_t)
> +fs_associate(test_filesystem_may_create_no_associate_t)
> +fs_getattr_xattr_fs(test_filesystem_may_create_no_associate_t)
> +
> +# Create test file
> +# neverallow unlabeled_t test_filesystem_may_create_no_associate_t:filesystem { associate };
> +allow test_filesystem_may_create_no_associate_t self:file { create relabelfrom relabelto };
> +allow test_filesystem_may_create_no_associate_t unconfined_t:file { open read write };
> +allow test_filesystem_may_create_no_associate_t unlabeled_t:dir { add_name search write };
> +allow test_filesystem_may_create_no_associate_t unlabeled_t:file { create open relabelfrom write };
> +
> +#################### Deny filesystem { quotamod } ######################
> +# hooks.c selinux_quotactl() 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 test_file_t:dir { mounton write remove_name rmdir };
> +
> +#################### Deny filesystem { quotaget } ######################
> +# hooks.c selinux_quotactl() 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 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)
> +
> +#################### Deny file { quotaon } ######################
> +# hooks.c selinux_quota_on() FILE__QUOTAON
> +type test_file_no_quotaon_t;
> +domain_type(test_file_no_quotaon_t)
> +unconfined_runs_test(test_file_no_quotaon_t)
> +typeattribute test_file_no_quotaon_t testdomain;
> +typeattribute test_file_no_quotaon_t filesystemdomain;
> +
> +allow test_file_no_quotaon_t self:capability { sys_admin };
> +allow test_file_no_quotaon_t self:filesystem { quotamod relabelto mount unmount relabelfrom };
> +allow test_file_no_quotaon_t test_file_t:dir { mounton write remove_name rmdir };
> +# neverallow test_file_no_quotaon_t self:file { quotaon };
> +fs_mount_all_fs(test_file_no_quotaon_t)
> +fs_relabelfrom_all_fs(test_file_no_quotaon_t)
> +fs_associate(test_file_no_quotaon_t)
> +# Required as $private_path to quota files
> +files_search_all(test_file_no_quotaon_t)
> +# For running quotacheck(8)
> +files_type(test_file_no_quotaon_t)
> +
> +#################### Deny filesystem { mount } ######################
> +# hooks.c selinux_sb_kern_mount() 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 test_file_t:dir { mounton write remove_name rmdir };
> +
> +#################### Deny filesystem { getattr } ######################
> +# hooks.c selinux_sb_statfs() 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 test_file_t:dir { mounton write remove_name rmdir };
> +
> +#################### Deny filesystem { remount } ######################
> +# hooks.c selinux_mount() 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 test_file_t:dir { mounton write remove_name rmdir };
> +
> +#################### Deny filesystem { unmount } ######################
> +# hooks.c selinux_umount() 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 test_file_t:dir { mounton write remove_name rmdir };
> +
> +########## Deny filesystem { associate } for setxattr ################
> +# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE
> +type test_filesystem_inode_setxattr_no_associate_t;
> +domain_type(test_filesystem_inode_setxattr_no_associate_t)
> +unconfined_runs_test(test_filesystem_inode_setxattr_no_associate_t)
> +typeattribute test_filesystem_inode_setxattr_no_associate_t testdomain;
> +typeattribute test_filesystem_inode_setxattr_no_associate_t filesystemdomain;
> +
> +allow test_filesystem_inode_setxattr_no_associate_t self:capability { sys_admin };
> +allow test_filesystem_inode_setxattr_no_associate_t self:filesystem { mount relabelfrom relabelto unmount associate };
> +allow test_filesystem_inode_setxattr_no_associate_t self:dir { mounton add_name write };
> +allow test_filesystem_inode_setxattr_no_associate_t test_file_t:dir { mounton write remove_name rmdir };
> +
> +fs_mount_all_fs(test_filesystem_inode_setxattr_no_associate_t)
> +fs_unmount_all_fs(test_filesystem_inode_setxattr_no_associate_t)
> +fs_relabelfrom_all_fs(test_filesystem_inode_setxattr_no_associate_t)
> +fs_getattr_xattr_fs(test_filesystem_inode_setxattr_no_associate_t)
> +fs_associate(test_filesystem_inode_setxattr_no_associate_t)
> +
> +# Create test file
> +allow test_filesystem_inode_setxattr_no_associate_t self:file { create relabelfrom relabelto };
> +# neverallow unconfined_t test_filesystem_inode_setxattr_no_associate_t:filesystem { associate };
> +dontaudit unconfined_t test_filesystem_filecon_t:file { getattr read };
> +allow test_filesystem_inode_setxattr_no_associate_t unconfined_t:dir { add_name write };
> +allow test_filesystem_inode_setxattr_no_associate_t unconfined_t:file { create relabelfrom relabelto };
> +
> +#allow test_filesystem_inode_setxattr_no_associate_t unconfined_t:file { open read getattr write };
> +
> +#################### Deny filesystem { watch } ######################
> +# hooks.c selinux_path_notify() 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 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)
> +
> +################# 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 };
> +allow test_setfscreatecon_t test_file_t:dir { add_name write remove_name };
> +
> +# Set new context on fs:
> +type test_setfscreatecon_newcon_t;
> +unconfined_runs_test(test_setfscreatecon_newcon_t)
> +fs_associate(test_setfscreatecon_newcon_t)
> +allow test_setfscreatecon_t test_setfscreatecon_newcon_t:dir { create getattr rmdir };
> +
> +################# 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;
> +
> +type test_filesystem_fscontext_fs_t;
> +files_type(test_filesystem_fscontext_fs_t)
> +
> +allow test_filesystem_fscontext_t self:capability { sys_admin };
> +allow test_filesystem_fscontext_t test_file_t:dir { mounton };
> +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { getattr open read relabelto write };
> +allow test_filesystem_fscontext_t test_filesystem_fscontext_fs_t:dir { add_name search write };
> +allow test_filesystem_fscontext_t test_filesystem_fscontext_fs_t:file { create getattr open relabelfrom write };
> +allow test_filesystem_fscontext_t test_filesystem_fscontext_fs_t:filesystem { mount relabelto unmount };
> +fs_relabelfrom_all_fs(test_filesystem_fscontext_t)
> +files_search_all(test_filesystem_fscontext_t)
> +allow test_filesystem_filecon_t test_filesystem_fscontext_fs_t:filesystem associate;
> +
> +########### Test context= #################
> +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;
> +
> +type test_filesystem_context_file_t;
> +files_type(test_filesystem_context_file_t)
> +
> +allow test_filesystem_context_t self:capability { sys_admin };
> +allow test_filesystem_context_t test_file_t:dir { mounton };
> +allow test_filesystem_context_t test_filesystem_context_file_t:dir { add_name search write };
> +allow test_filesystem_context_t test_filesystem_context_file_t:file { create getattr open read relabelfrom write };
> +allow test_filesystem_context_t test_filesystem_context_file_t:filesystem { mount relabelfrom relabelto unmount };
> +allow test_filesystem_context_t test_filesystem_filecon_t:file { getattr open read relabelto write };
> +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)
> +
> +# For testing defcontext=
> +allow test_filesystem_fscontext_t test_filesystem_context_file_t:dir { add_name write };
> +allow test_filesystem_fscontext_t test_filesystem_context_file_t:file { create getattr open write };
> +
> +# 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 };
> +
> +#
> +########### 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/policy/test_filesystem_name_trans.te b/policy/test_filesystem_name_trans.te
> new file mode 100644
> index 0000000..ce04601
> --- /dev/null
> +++ b/policy/test_filesystem_name_trans.te
> @@ -0,0 +1,20 @@
> +#
> +######### Test filesystem name-base transition policy module ##########
> +#
> +
> +# Name-based type transition context:
> +type test_filesystem_filenametranscon1_t;
> +files_type(test_filesystem_filenametranscon1_t)
> +type test_filesystem_filenametranscon2_t;
> +files_type(test_filesystem_filenametranscon2_t)
> +
> +# Create file and change context via name-based type_transition rule:
> +fs_associate(test_filesystem_filenametranscon1_t)
> +type_transition test_filesystem_t test_filesystem_file_t:file test_filesystem_filenametranscon1_t "name_trans_test_file1";
> +allow test_filesystem_t test_filesystem_filenametranscon1_t:file { create getattr open write };
> +dontaudit unconfined_t test_filesystem_filenametranscon1_t:file { getattr read };
> +#
> +fs_associate(test_filesystem_filenametranscon2_t)
> +type_transition test_filesystem_t test_filesystem_file_t:file test_filesystem_filenametranscon2_t "name_trans_test_file2";
> +allow test_filesystem_t test_filesystem_filenametranscon2_t:file { create getattr open write };
> +dontaudit unconfined_t test_filesystem_filenametranscon2_t:file { getattr read };
> 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..a522e96
> --- /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 -f file -e cxt [-v]\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..2899dea
> --- /dev/null
> +++ b/tests/filesystem/check_mount_context.c
> @@ -0,0 +1,127 @@
> +#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 -m mp [-e ctx] [-r] [-v]\n"
> +		"Where:\n\t"
> +		"-m  Mount point\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;
> +	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");
> +			result = -1;
> +			goto err;
> +		}
> +
> +		if (context_type_set(con_t, type)) {
> +			fprintf(stderr, "Unable to set new type\n");
> +			free(con_t);
> +			result = -1;
> +			goto err;
> +		}
> +
> +		newcon = context_str(con_t);
> +		free(con_t);
> +		if (!newcon) {
> +			fprintf(stderr, "Unable to obtain new context string\n");
> +			result = -1;
> +			goto err;
> +		}
> +
> +		result = setfilecon(mount, newcon);
> +		free(newcon);
> +		if (result < 0) {
> +			fprintf(stderr, "setfilecon(3) Failed: %s\n",
> +				strerror(errno));
> +			result = -1;
> +			goto err;
> +		}
> +
> +		free(context);
> +
> +		result = getfilecon(mount, &context);
> +		if (result < 0) {
> +			fprintf(stderr, "getfilecon(3) Failed: %s\n",
> +				strerror(errno));
> +			return result;
> +		}
> +		result = 0;
> +
> +		if (verbose)
> +			printf("Set new MP context: %s\n", context);
> +
> +	} 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..ab8f20f
> --- /dev/null
> +++ b/tests/filesystem/create_file.c
> @@ -0,0 +1,117 @@
> +#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>
> +#include <selinux/context.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s -f file [-e type] [-v]\n"
> +		"Where:\n\t"
> +		"-f  File to create\n\t"
> +		"-e  Expected file context type\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, *type = NULL;
> +	const char *file_type;
> +	bool verbose = false;
> +	context_t con_t;
> +
> +	while ((opt = getopt(argc, argv, "f:e:v")) != -1) {
> +		switch (opt) {
> +		case 'f':
> +			file = optarg;
> +			break;
> +		case 'e':
> +			type = 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;
> +	}
> +
> +	if (verbose)
> +		printf("Created file: %s\n", file);
> +
> +	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: %s\n", context);
> +
> +	if (type) {
> +		con_t = context_new(context);
> +		if (!con_t) {
> +			fprintf(stderr, "Unable to create context structure\n");
> +			result = -1;
> +			goto err;
> +		}
> +
> +		file_type = context_type_get(con_t);
> +		if (!file_type) {
> +			fprintf(stderr, "Unable to get new type\n");
> +			free(con_t);
> +			result = -1;
> +			goto err;
> +		}
> +
> +		if (strcmp(type, file_type)) {
> +			fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n",
> +				type, file_type);
> +			result = -1;
> +		} else {
> +			result = 0;
> +			if (verbose)
> +				printf("File context is correct\n");
> +		}
> +		free(con_t);
> +	}
> +
> +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..83f780e
> --- /dev/null
> +++ b/tests/filesystem/create_file_change_context.c
> @@ -0,0 +1,146 @@
> +#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 -f file -t type [-v]\n"
> +		"Where:\n\t"
> +		"-f  File to create\n\t"
> +		"-t  Type for context of created file\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int opt, result, fd, save_err;
> +	char *newfcon = NULL, *orgfcon = NULL, *type = NULL, *file = NULL;
> +	char *context;
> +	bool verbose = false;
> +	context_t con_t;
> +
> +	while ((opt = getopt(argc, argv, "f:t:v")) != -1) {
> +		switch (opt) {
> +		case 'f':
> +			file = optarg;
> +			break;
> +		case 't':
> +			type = optarg;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!type || !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);
> +	}
> +
> +	/* 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));
> +		return save_err;
> +	}
> +	if (verbose)
> +		printf("Created file: %s\n", file);
> +
> +	result = fgetfilecon(fd, &orgfcon);
> +	if (result < 0) {
> +		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> +			strerror(errno));
> +		close(fd);
> +		return -1;
> +	}
> +	if (verbose)
> +		printf("Current file context is: %s\n", orgfcon);
> +
> +	/* Build new file context */
> +	con_t = context_new(orgfcon);
> +	if (!con_t) {
> +		fprintf(stderr, "Unable to create context structure\n");
> +		result = -1;
> +		goto err;
> +	}
> +
> +	if (context_type_set(con_t, type)) {
> +		fprintf(stderr, "Unable to set new type\n");
> +		free(con_t);
> +		result = -1;
> +		goto err;
> +	}
> +
> +	newfcon = context_str(con_t);
> +	free(con_t);
> +	if (!newfcon) {
> +		fprintf(stderr, "Unable to obtain new context string\n");
> +		result = -1;
> +		goto err;
> +	}
> +
> +	/* hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE */
> +	result = fsetfilecon(fd, newfcon);
> +	save_err = errno;
> +	close(fd);
> +	if (result < 0) {
> +		fprintf(stderr, "fsetfilecon(3) Failed: %s\n",
> +			strerror(errno));
> +		result = save_err;
> +		goto err1;
> +	}
> +
> +	fd = open(file, O_RDWR);
> +	if (fd < 0) {
> +		fprintf(stderr, "open(2) Failed: %s\n", strerror(errno));
> +		result = -1;
> +		goto err1;
> +	}
> +
> +	result = fgetfilecon(fd, &context);
> +	if (result < 0) {
> +		fprintf(stderr, "fgetfilecon(3) Failed: %s\n",
> +			strerror(errno));
> +		result = -1;
> +		goto err1;
> +	}
> +	if (verbose)
> +		printf("New 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(orgfcon);
> +err1:
> +	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..c525d69
> --- /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 -t path [-v]\n"
> +		"Where:\n\t"
> +		"-t  Target mount point to mark\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..8ebc0bf
> --- /dev/null
> +++ b/tests/filesystem/fs_relabel.c
> @@ -0,0 +1,138 @@
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdbool.h>
> +#include <sys/stat.h>
> +#include <sys/types.h>
> +#include <linux/unistd.h>
> +#include <linux/limits.h>
> +#include <selinux/selinux.h>
> +#include <selinux/context.h>
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s -b path -t type [-v]\n"
> +		"Where:\n\t"
> +		"-b  base directory\n\t"
> +		"-t  Type for fs context to generate on base/mp1\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char **argv)
> +{
> +	int opt, result, save_err;
> +	char *context, *fs_con = NULL, *newcon = NULL, *base_dir, *type;
> +	char fs_mount[PATH_MAX];
> +	bool verbose = false;
> +	context_t con_t;
> +
> +	while ((opt = getopt(argc, argv, "b:t:v")) != -1) {
> +		switch (opt) {
> +		case 'b':
> +			base_dir = optarg;
> +			break;
> +		case 't':
> +			type = optarg;
> +			break;
> +		case 'v':
> +			verbose = true;
> +			break;
> +		default:
> +			print_usage(argv[0]);
> +		}
> +	}
> +
> +	if (!type || !base_dir)
> +		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 = getfilecon(base_dir, &context);
> +	if (result < 0) {
> +		fprintf(stderr, "getfilecon(3) Failed: %s\n",
> +			strerror(errno));
> +		return -1;
> +	}
> +	if (verbose)
> +		printf("%s context is: %s\n", base_dir, context);
> +
> +	/* Build new context for fs */
> +	con_t = context_new(context);
> +	if (!con_t) {
> +		fprintf(stderr, "Unable to create context structure\n");
> +		result = -1;
> +		goto err;
> +	}
> +
> +	if (context_type_set(con_t, type)) {
> +		fprintf(stderr, "Unable to set new type\n");
> +		free(con_t);
> +		result = -1;
> +		goto err;
> +	}
> +
> +	newcon = context_str(con_t);
> +	free(con_t);
> +	if (!newcon) {
> +		fprintf(stderr, "Unable to obtain new context string\n");
> +		result = -1;
> +		goto err;
> +	}
> +
> +	result = setfscreatecon(newcon);
> +	save_err = errno;
> +	if (result < 0) {
> +		fprintf(stderr, "Failed setfscreatecon(3): %s\n",
> +			strerror(errno));
> +		result = save_err;
> +		goto err;
> +	}
> +
> +	sprintf(fs_mount, "%s/%s", base_dir, "mp1");
> +
> +	result = mkdir(fs_mount, 0777);
> +	if (result < 0) {
> +		fprintf(stderr, "mkdir(2) Failed: %s\n", strerror(errno));
> +		goto err;
> +	}
> +
> +	result = getfilecon(fs_mount, &fs_con);
> +	if (result < 0) {
> +		fprintf(stderr, "getfilecon(3) Failed: %s\n",
> +			strerror(errno));
> +		goto err;
> +	}
> +	if (verbose)
> +		printf("%s context is: %s\n", fs_mount, fs_con);
> +
> +	result = rmdir(fs_mount);
> +	if (result < 0) {
> +		fprintf(stderr, "rmdir(2) Failed: %s\n", strerror(errno));
> +		goto err;
> +	}
> +
> +	if (strcmp(newcon, fs_con)) {
> +		fprintf(stderr, "FS context error, expected:\n\t%s\ngot:\n\t%s\n",
> +			newcon, fs_con);
> +		result = -1;
> +	}
> +err:
> +	free(context);
> +	free(newcon);
> +	free(fs_con);
> +
> +	return result;
> +}
> diff --git a/tests/filesystem/grim_reaper.c b/tests/filesystem/grim_reaper.c
> new file mode 100644
> index 0000000..340546a
> --- /dev/null
> +++ b/tests/filesystem/grim_reaper.c
> @@ -0,0 +1,89 @@
> +#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
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s -t tgt [-v]\n"
> +		"Where:\n\t"
> +		"-t  target to unmount if active\n\t"
> +		"-v  Print information.\n", progname);
> +	exit(-1);
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	FILE *fp;
> +	size_t len;
> +	ssize_t num;
> +	int opt, index = 0, i, result = 0;
> +	char *mount_info[2], *buf = NULL, *item, *tgt;
> +	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]);
> +
> +	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], tgt) == 0) {
> +			if (verbose)
> +				printf("Unmounting %s from %s\n",
> +				       mount_info[1], mount_info[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..8359811
> --- /dev/null
> +++ b/tests/filesystem/quotas_test.c
> @@ -0,0 +1,143 @@
> +#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>
> +
> +/*
> + * This is required 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>
> + */
> +#ifndef QFMT_VFS_V0
> +#define QFMT_VFS_V0 2
> +#endif
> +
> +static void print_usage(char *progname)
> +{
> +	fprintf(stderr,
> +		"usage:  %s -s src -t tgt [-v]\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..310b66d
> --- /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 -t path [-v]\n"
> +		"Where:\n\t"
> +		"-t  Target path to statfs(2)\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..f53ccfe
> --- /dev/null
> +++ b/tests/filesystem/test
> @@ -0,0 +1,966 @@
> +#!/usr/bin/perl
> +use Test::More;
> +
> +BEGIN {
> +    $basedir = $0;
> +    $basedir =~ s|(.*)/[^/]*|$1|;
> +
> +    $test_count = 68;
> +
> +    # Options: -v = Verbose, -d disable udisks(8) daemon
> +    $v              = " ";
> +    $disable_udisks = 0;
> +    $udisks2_status = 0;
> +    foreach $arg (@ARGV) {
> +        if ( $arg eq "-v" ) {
> +            $v = $arg;
> +        }
> +        elsif ( $arg eq "-d" ) {
> +            $disable_udisks = 1;
> +        }
> +    }
> +
> +    # 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;
> +    }
> +
> +    $test_name_trans = 0;
> +    $pol_vers        = `checkpolicy -V | cut -f 1 -d ' '`;
> +    $mod_pol_vers    = `checkmodule -V | cut -f 2 -d '-'`;
> +
> +    if ( $mod_pol_vers >= 11 and $pol_vers >= 25 ) {
> +        $test_name_trans = 1;
> +        $test_count += 2;
> +    }
> +
> +    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;
> +
> +# Optionally stop the udisks(8) daemon, then restart on exit.
> +sub udisks2_stop {
> +    $status = 0;
> +
> +    if ( -e "/usr/bin/systemctl" ) {
> +        $u_status_cmd = "/usr/bin/systemctl status udisks2 >& /dev/null";
> +        $u_stop_cmd   = "/usr/bin/systemctl stop udisks2 >& /dev/null";
> +    }
> +    elsif ( -e "/usr/sbin/service" ) {
> +        $u_status_cmd = "/usr/sbin/service udisks2 status >& /dev/null";
> +        $u_stop_cmd   = "/usr/sbin/service udisks2 stop >& /dev/null";
> +    }
> +
> +    if ($u_status_cmd) {
> +        $result = system("$u_status_cmd");
> +        $status = $result >> 8;
> +        if ( $status eq 0 ) {
> +            print "Stopping udisks2 service for these tests.\n";
> +            system("$u_stop_cmd");
> +            $status = 3;
> +        }
> +        else {
> +            $status = 4;
> +        }
> +    }
> +    return $status;
> +}
> +
> +sub udisks2_restart {
> +    my ($status) = @_;
> +
> +    if ( $status eq 3 ) {
> +        print "Restarting udisks2 service.\n";
> +        if ( -e "/usr/bin/systemctl" ) {
> +            system("/usr/bin/systemctl start udisks2 >& /dev/null");
> +        }
> +        elsif ( -e "/usr/sbin/service" ) {
> +            system("/usr/sbin/service udisks2 start >& /dev/null");
> +        }
> +    }
> +}
> +
> +sub get_loop_dev {
> +    system("udevadm settle");
> +    print "Finding free /dev/loop entry\n";
> +    $get_dev = `losetup -f 2>/dev/null`;
> +    chomp($get_dev);
> +    if ( $get_dev eq "" ) {
> +        print "losetup failed to obtain /dev/loop entry\n";
> +    }
> +
> +    # Keep list of devices for cleanup later
> +    if ( $device_count eq 0 ) {
> +        $device_list[$device_count] = $get_dev;
> +        $device_count += 1;
> +    }
> +    elsif ( $get_dev ne $device_list[ $device_count - 1 ] ) {
> +        $device_list[$device_count] = $get_dev;
> +        $device_count += 1;
> +    }
> +    return $get_dev;
> +}
> +
> +sub attach_dev {
> +    my ( $att_dev, $base ) = @_;
> +    system("udevadm settle");
> +    print "Attaching $base/fstest to $att_dev\n";
> +    $result = system("losetup $att_dev $base/fstest 2>/dev/null");
> +    if ( $result != 0 ) {
> +        print "Failed to attach $base/fstest to $att_dev\n";
> +    }
> +    system("udevadm settle");
> +}
> +
> +sub make_fs {
> +    my ( $mk_type, $mk_dev, $mk_dir ) = @_;
> +    print "Create $mk_dir/fstest with dd\n";
> +    $result = system(
> +        "dd if=/dev/zero of=$mk_dir/fstest bs=1024 count=10240 2>/dev/null");
> +    if ( $result != 0 ) {
> +        print "dd failed to create $mk_dir/fstest\n";
> +    }
> +
> +    attach_dev( $mk_dev, $mk_dir );
> +
> +    print "Make $mk_type filesystem on $mk_dev\n";
> +    $result = system("mkfs.$mk_type -I 256 $mk_dev >& /dev/null");
> +    if ( $result != 0 ) {
> +        system("losetup -d $mk_dev 2>/dev/null");
> +        print "mkfs.$mk_type failed to create filesystem on $mk_dev\n";
> +    }
> +}
> +
> +sub mk_mntpoint_1 {
> +    my ($path) = @_;
> +    system("rm -rf $path/mp1 2>/dev/null");
> +    system("mkdir -p $path/mp1 2>/dev/null");
> +}
> +
> +sub mk_mntpoint_2 {
> +    my ($path) = @_;
> +    system("rm -rf $path/mp2 2>/dev/null");
> +    system("mkdir -p $path/mp2 2>/dev/null");
> +}
> +
> +sub cleanup {
> +    my ($base) = @_;
> +    system("rm -rf $base/fstest 2>/dev/null");
> +    system("rm -rf $base/mntpoint 2>/dev/null");
> +}
> +
> +sub cleanup1 {
> +    my ( $base, $d ) = @_;
> +    system("udevadm settle");
> +    system("losetup -d $d 2>/dev/null");
> +    system("udevadm settle");
> +    system("rm -rf $base/fstest 2>/dev/null");
> +    system("rm -rf $base/mntpoint 2>/dev/null");
> +}
> +
> +# Cleanup any attached /dev/loop entries
> +sub reaper {
> +    my ( $base, $v ) = @_;
> +
> +    foreach my $n (@device_list) {
> +        system("$base/grim_reaper -t $n $v 2>/dev/null");
> +    }
> +}
> +
> +# End subroutines
> +
> +if ($disable_udisks) {
> +    $udisks2_status = udisks2_stop();
> +}
> +
> +cleanup($basedir);
> +
> +############### Test setfscreatecon(3) ##########################
> +system("mkdir -p $basedir/mntpoint 2>/dev/null");
> +
> +print "Test setfscreatecon(3)\n";
> +$result = system
> +"runcon -t test_setfscreatecon_t $basedir/fs_relabel $v -b $basedir/mntpoint -t test_setfscreatecon_newcon_t";
> +ok( $result eq 0 );
> +
> +$result = system
> +"runcon -t test_no_setfscreatecon_t $basedir/fs_relabel $v -b $basedir/mntpoint -t test_setfscreatecon_newcon_t 2>&1";
> +ok( $result >> 8 eq 13 );
> +
> +system("rm -rf $basedir/mntpoint 2>/dev/null");
> +
> +############### Test Basic Mount/Unmount ##########################
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$mount_opts1 =
> +"quota,usrquota,grpquota,defcontext=system_u:object_r:test_filesystem_file_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";
> +
> +# On RHEL-6, there is a type transition to quota_t when running quotacheck
> +# as unconfined_t. Using "runcon `id -Z` quotacheck ..." resolves this.
> +$result = system("runcon `id -Z` 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 'trans_test_file' and checking context changed via type_transition rule\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_t $basedir/create_file -f $private_path/mp1/trans_test_file -e test_filesystem_filetranscon_t $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Creating 'test_file' and changing its context via setfilecon(3)\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_name_trans) {
> +    print
> +"Creating 'name_trans_test_file1' and checking context changed via name-based type_transition rule\n";
> +    $result = system(
> +"runcon -t test_filesystem_t $basedir/create_file -f $private_path/mp1/name_trans_test_file1 -e test_filesystem_filenametranscon1_t $v"
> +    );
> +    ok( $result eq 0 );
> +
> +    print
> +"Creating 'name_trans_test_file2' and checking context changed via name-based type_transition rule\n";
> +    $result = system(
> +"runcon -t test_filesystem_t $basedir/create_file -f $basedir/mntpoint/mp1/name_trans_test_file2 -e test_filesystem_filenametranscon2_t $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( $basedir, $dev );
> +
> +############### Test Move Mount ##########################
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$mount_opts2 =
> +"quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_file_t:s0";
> +
> +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_2($private_path);
> +
> +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( $basedir, $dev );
> +
> +############### Deny filesystem { relabelfrom } ##########################
> +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_relabelfrom =
> +  "defcontext=system_u:object_r:test_filesystem_sb_relabel_no_relabelfrom_t:s0";
> +
> +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_sb_relabel_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( $basedir, $dev );
> +
> +############### Deny filesystem { relabelto } ##########################
> +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_relabelto =
> +  "fscontext=system_u:object_r:test_filesystem_sb_relabel_no_relabelto_t:s0";
> +
> +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_sb_relabel_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( $basedir, $dev );
> +
> +############### Deny filesystem { relabelfrom } ##########################
> +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_relabelfrom =
> +  "rootcontext=system_u:object_r:test_filesystem_no_inode_no_relabelfrom_t:s0";
> +
> +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_inode_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( $basedir, $dev );
> +
> +############### Deny filesystem { associate } ##########################
> +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +
> +# This defcontext will trigger denial.
> +$opts_no_associate =
> +"defcontext=system_u:object_r:test_filesystem_inode_relabel_no_associate_t:s0";
> +
> +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_inode_relabel_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( $basedir, $dev );
> +
> +############### Deny filesystem { associate } ##########################
> +# hooks.c may_create() FILESYSTEM__ASSOCIATE
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +
> +# Use this fscontext= to get sensible audit log entry of:
> +#  "allow unlabeled_t test_filesystem_may_create_no_associate_t:filesystem associate;"
> +$opts_no_associate_file =
> +  "fscontext=system_u:object_r:test_filesystem_may_create_no_associate_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_may_create_no_associate_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_may_create_no_associate_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_may_create_no_associate_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1( $basedir, $dev );
> +
> +############### Deny filesystem { quotamod } ##########################
> +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_quotamod =
> +"quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesystem_no_quotamod_t:s0";
> +
> +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( $basedir, $dev );
> +
> +############### Deny filesystem { quotaget } ##########################
> +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_quotaget =
> +"quota,usrquota,grpquota,context=system_u:object_r:test_filesystem_no_quotaget_t:s0";
> +
> +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("runcon `id -Z` 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( $basedir, $dev );
> +
> +############### Deny file { quotaon } ##########################
> +# hooks.c selinux_quota_on() FILE__QUOTAON
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_quotaon =
> +  "quota,usrquota,grpquota,context=system_u:object_r:test_file_no_quotaon_t:s0";
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_quotaon\n";
> +$result = system(
> +"runcon -t test_file_no_quotaon_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotaon $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Running quotacheck(8) to init user/group quota files\n";
> +$result = system("runcon `id -Z` quotacheck -ugF vfsv0 $private_path/mp1");
> +ok( $result eq 0 );
> +
> +print "Toggle User quotas on/off\n";    # Must have full path
> +$result = system(
> +"runcon -t test_file_no_quotaon_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_file_no_quotaon_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1( $basedir, $dev );
> +
> +############### Deny filesystem { mount } ##########################
> +# hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_mount = "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0";
> +
> +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( $basedir, $dev );
> +
> +############### Deny filesystem { getattr } ##########################
> +# hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_getattr =
> +  "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0";
> +
> +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( $basedir, $dev );
> +
> +############### Deny filesystem { remount } ##########################
> +# hooks.c selinux_mount() FILESYSTEM__REMOUNT
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_remount =
> +  "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0";
> +
> +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( $basedir, $dev );
> +
> +############### Deny filesystem { unmount } ##########################
> +# hooks.c selinux_umount() FILESYSTEM__UNMOUNT
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_unmount =
> +  "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0";
> +
> +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( $basedir, $dev );
> +
> +############### Deny filesystem { associate }  ##########################
> +# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$opts_no_associate_xattr =
> +"defcontext=system_u:object_r:test_filesystem_inode_setxattr_no_associate_t:s0,fscontext=system_u:object_r:test_filesystem_inode_setxattr_no_associate_t:s0";
> +
> +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n";
> +print "Using mount options:\n\t$opts_no_associate_xattr\n";
> +$result = system(
> +"runcon -t test_filesystem_inode_setxattr_no_associate_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_xattr $v"
> +);
> +ok( $result eq 0 );
> +
> +print "Creating test file $basedir/mntpoint/mp1/test_file\n";
> +$result =
> +  system(
> +"runcon -t test_filesystem_inode_setxattr_no_associate_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_inode_setxattr_no_associate_t $basedir/umount -t $basedir/mntpoint/mp1 $v"
> +  );
> +ok( $result eq 0 );
> +
> +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n";
> +cleanup1( $basedir, $dev );
> +
> +############### Deny filesystem { watch }  ##########################
> +# hooks.c selinux_path_notify() FILESYSTEM__WATCH
> +if ($test_watch) {
> +    mk_mntpoint_1($private_path);
> +    $dev = get_loop_dev();
> +    make_fs( $fs_type, $dev, $basedir );
> +    $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( $basedir, $dev );
> +}
> +
> +##########################################################################
> +# 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.
> +##########################################################################
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +
> +# Mount with xttrs to create a file with specific context.
> +$context1_opts =
> +  "defcontext=system_u:object_r:test_filesystem_context_file_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 one and attach
> +system("losetup -d $dev 2>/dev/null");
> +$dev = get_loop_dev();
> +attach_dev( $dev, $basedir );
> +
> +# Mount again with no xttr support
> +$context2_opts = "context=system_u:object_r:test_filesystem_context_file_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_file_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_file_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( $basedir, $dev );
> +
> +##########################################################################
> +# 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.
> +##########################################################################
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$root_opts = "rootcontext=system_u:object_r:test_filesystem_context_file_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_file_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( $basedir, $dev );
> +
> +##########################################################################
> +# 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.
> +##########################################################################
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +make_fs( $fs_type, $dev, $basedir );
> +$test_opts = "context=system_u:object_r:test_filesystem_context_file_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_file_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 -e test_filesystem_context_file_t $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");
> +$dev = get_loop_dev();
> +attach_dev( $dev, $basedir );
> +
> +# 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( $basedir, $dev );
> +
> +##########################################################################
> +# 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";
> +mk_mntpoint_1($private_path);
> +$dev = get_loop_dev();
> +$fscontext_opts =
> +"fscontext=system_u:object_r:test_filesystem_fscontext_fs_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( $basedir, $dev );
> +
> +reaper( $basedir, $v );
> +
> +if ($disable_udisks) {
> +    udisks2_restart($udisks2_status);
> +}
> +
> +exit;
> diff --git a/tests/filesystem/umount.c b/tests/filesystem/umount.c
> new file mode 100644
> index 0000000..3029741
> --- /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 [-t] [-v]\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] 4+ messages in thread

* Re: [PATCH V6 1/1] selinux-testsuite: Add filesystem tests
       [not found]     ` <0556d72199ca519fa295449bce6aabc51061c486.camel@btinternet.com>
@ 2020-01-17 20:25       ` Ondrej Mosnacek
  0 siblings, 0 replies; 4+ messages in thread
From: Ondrej Mosnacek @ 2020-01-17 20:25 UTC (permalink / raw)
  To: Richard Haines; +Cc: Stephen Smalley, SElinux list

On Fri, Jan 17, 2020 at 7:22 PM Richard Haines
<richard_c_haines@btinternet.com> wrote:
> On Fri, 2020-01-17 at 12:32 -0500, Stephen Smalley wrote:
> > On 1/16/20 1:51 PM, Richard Haines wrote:
> > > Test filesystem permissions, setfscreatecon(3), file { quotaon }
> > > and
> > > changing file context via non and name-based type_transition rules.
> > > The name-based rules only apply to MOD_POL_VERS=>11 and
> > > POL_VERS=>25
> > >
> > >  From kernels 5.5 filesystem { watch } is also tested.
> > >
> > > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
> >
> > This passes travis-ci and testing on Fedora and generally looks good
> > to
> > me.  Only question I had was whether we should be checking the
> > kernel's
> > max supported policyvers (/sys/fs/selinux/policyvers,
> > MAX_KERNEL_POLICY
> > in the policy Makefile) as well as that of checkpolicy/checkmodule,
> > because otherwise the policy might compile ok but the name-based
> > transitions will be discarded upon automatic downgrade at policy
> > load
> > time and the tests will fail.
>
> Ok I'll fix that.
>
> Ondrej - Does this work on RHEL-6. Checking just in case it fails so I
> can include any further fixes in next patch.

Yes, it passes on RHEL-6 now, thanks!

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


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

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

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-01-16 18:51 [PATCH V6 0/1] selinux-testsuite: Add filesystem tests Richard Haines
2020-01-16 18:51 ` [PATCH V6 1/1] " Richard Haines
2020-01-17 17:32   ` Stephen Smalley
     [not found]     ` <0556d72199ca519fa295449bce6aabc51061c486.camel@btinternet.com>
2020-01-17 20:25       ` Ondrej Mosnacek

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).