Test supported filesystems for mount options: context, defcontext, rootcontext and fscontext. The tests use fsconfig(2) and therefore does not actually mount the filesystem to a target. All /sbin/mkfs.* entries are read and if supported, tested with each option. Signed-off-by: Richard Haines <richard_c_haines@xxxxxxxxxxxxxx> --- policy/test_filesystem.te | 12 +++ tests/Makefile | 2 +- tests/filesystem/Filesystem.pm | 19 +++- tests/fs_contexts/.gitignore | 1 + tests/fs_contexts/Makefile | 13 +++ tests/fs_contexts/fsconfig.c | 72 ++++++++++++++++ tests/fs_contexts/test | 153 +++++++++++++++++++++++++++++++++ 7 files changed, 268 insertions(+), 4 deletions(-) create mode 100644 tests/fs_contexts/.gitignore create mode 100644 tests/fs_contexts/Makefile create mode 100644 tests/fs_contexts/fsconfig.c create mode 100755 tests/fs_contexts/test diff --git a/policy/test_filesystem.te b/policy/test_filesystem.te index 4ff493a..220f79e 100644 --- a/policy/test_filesystem.te +++ b/policy/test_filesystem.te @@ -6,6 +6,9 @@ attribute filesystemdomain; kernel_setsched(filesystemdomain) +# For module filesystems +kernel_request_load_module(filesystemdomain) + #################### Create test file contexts ###################### type test_filesystem_filecon_t; files_type(test_filesystem_filecon_t) @@ -58,6 +61,15 @@ type_transition test_filesystem_t test_filesystem_file_t:file test_filesystem_fi allow test_filesystem_t test_filesystem_filetranscon_t:file { create getattr open write relabelfrom }; dontaudit unconfined_t test_filesystem_filetranscon_t:file { getattr read }; +# +# For fs_contexts tests +# +allow test_filesystem_t test_filesystem_file_t:filesystem { mount relabelfrom relabelto }; +allow test_filesystem_t unlabeled_t:filesystem { relabelfrom }; +# For fs_context test rootcontext= minix +allow test_filesystem_file_t unlabeled_t:filesystem { associate }; +allow test_filesystem_t unlabeled_t:filesystem { mount }; + #################### Deny filesystem { relabelfrom } ###################### # hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM type test_filesystem_sb_relabel_no_relabelfrom_t; diff --git a/tests/Makefile b/tests/Makefile index 46a1641..87708fb 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -100,7 +100,7 @@ endif ifeq ($(shell grep -q filesystem $(POLDEV)/include/support/all_perms.spt && echo true),true) ifneq ($(shell ./kvercmp $$(uname -r) 5.2),-1) -SUBDIRS += fs_filesystem +SUBDIRS += fs_filesystem fs_contexts endif endif diff --git a/tests/filesystem/Filesystem.pm b/tests/filesystem/Filesystem.pm index 3d4194d..680bf0b 100644 --- a/tests/filesystem/Filesystem.pm +++ b/tests/filesystem/Filesystem.pm @@ -111,17 +111,30 @@ sub attach_dev { sub make_fs { my ( $mk_type, $mk_dev, $mk_dir ) = @_; + + if ( $mk_type eq "btrfs" or $mk_type eq "reiserfs" ) { + $count = "count=27904"; + } + else { + $count = "count=4096"; + } + 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"); + $result = + system("dd if=/dev/zero of=$mk_dir/fstest bs=4096 $count 2>/dev/null"); if ( $result != 0 ) { print "dd failed to create $mk_dir/fstest\n"; } attach_dev( $mk_dev, $mk_dir ); + $opt = " "; + if ( $mk_type eq "reiserfs" ) { + $opt = "-q"; # Otherwise asks to proceed + } + print "Make $mk_type filesystem on $mk_dev\n"; - $result = system("mkfs.$mk_type -I 256 $mk_dev >& /dev/null"); + $result = system("mkfs.$mk_type $opt $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"; diff --git a/tests/fs_contexts/.gitignore b/tests/fs_contexts/.gitignore new file mode 100644 index 0000000..c870437 --- /dev/null +++ b/tests/fs_contexts/.gitignore @@ -0,0 +1 @@ +fsconfig diff --git a/tests/fs_contexts/Makefile b/tests/fs_contexts/Makefile new file mode 100644 index 0000000..012c4fa --- /dev/null +++ b/tests/fs_contexts/Makefile @@ -0,0 +1,13 @@ +TARGETS = fsconfig +USE_FS = ../fs_filesystem +DEPS = $(USE_FS)/fs_common.c $(USE_FS)/fs_common.h +LDLIBS += -lselinux + +all: $(TARGETS) + @set -e; for i in $(USE_FS); do $(MAKE) -C $$i all ; done + +clean: + rm -f $(TARGETS) + @set -e; for i in $(USE_FS); do $(MAKE) -C $$i clean ; done + +$(TARGETS): $(DEPS) diff --git a/tests/fs_contexts/fsconfig.c b/tests/fs_contexts/fsconfig.c new file mode 100644 index 0000000..e4cd8d8 --- /dev/null +++ b/tests/fs_contexts/fsconfig.c @@ -0,0 +1,72 @@ +#include "../fs_filesystem/fs_common.h" + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s -s src -f fs_type -o options [-v]\n" + "Where:\n\t" + "-s Source path\n\t" + "-f Filesystem type\n\t" + "-o Options list (comma separated list)\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char *argv[]) +{ + int opt, result, fsfd; + char *context, *src = NULL, *opts1, *fs_type = NULL, *opts = NULL; + bool verbose = false; + + while ((opt = getopt(argc, argv, "s:f:o:v")) != -1) { + switch (opt) { + case 's': + src = optarg; + break; + case 'f': + fs_type = optarg; + break; + case 'o': + opts = optarg; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!src || !fs_type || !opts) + 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); + } + + fsfd = fsopen(fs_type, 0); + if (fsfd < 0) { + fprintf(stderr, "Failed fsopen(2): %s\n", strerror(errno)); + return -1; + } + + opts1 = strdup(opts); + + /* fsconfig_opts() will return 0 or errno from fsconfig(2) */ + result = fsconfig_opts(fsfd, src, NULL, opts, verbose); + if (result) { + fprintf(stderr, "Failed config_opts\n"); + return result; + } + if (verbose) + printf("Successfully added options: %s\n", opts1); + + close(fsfd); + return 0; +} diff --git a/tests/fs_contexts/test b/tests/fs_contexts/test new file mode 100755 index 0000000..8437dcb --- /dev/null +++ b/tests/fs_contexts/test @@ -0,0 +1,153 @@ +#!/usr/bin/perl +use Test::More; + +my @mkfs_list; +my @fs_type_list; + +BEGIN { + $basedir = $0; + $basedir =~ s|(.*)/[^/]*|$1|; + + # Load common subroutines. + use File::Basename qw(dirname); + use Cwd qw(abs_path); + use lib dirname( abs_path $0) . '/../filesystem'; + use Filesystem + qw(udisks2_stop udisks2_restart get_loop_dev make_fs mk_mntpoint_1 cleanup1 reaper); + + # Options: -v = Verbose, -e enable udisks(8) daemon + $v = " "; + + # MUST stop udisksd(8) as it interferes with creating/deleting + # filesystems during these tests + $disable_udisks = 1; + $udisks2_status = 0; + foreach $arg (@ARGV) { + if ( $arg eq "-v" ) { + $v = $arg; + } + elsif ( $arg eq "-e" ) { + $disable_udisks = 0; + } + } + + my @mkfs_list = map { chomp; $_ } `find /sbin/mkfs.* -printf "%f\n"`; + $i = 0; + foreach my $fstype (@mkfs_list) { + @split_fn = split( /\./, $fstype ); + if ( $split_fn[1] eq "cramfs" ) { + print "$split_fn[1] - unsupported\n"; + next; + } + elsif ($split_fn[1] eq "btrfs" + or $split_fn[1] eq "ext2" + or $split_fn[1] eq "ext3" + or $split_fn[1] eq "ext4" + or $split_fn[1] eq "fat" + or $split_fn[1] eq "hfsplus" + or $split_fn[1] eq "minix" + or $split_fn[1] eq "msdos" + or $split_fn[1] eq "ntfs" + or $split_fn[1] eq "reiserfs" + or $split_fn[1] eq "vfat" + or $split_fn[1] eq "xfs" ) + { + $fs_type_list[$i] = $split_fn[1]; + print "$split_fn[1] - supported\n"; + $i++; + } + } + + plan tests => ( $i * 4 ); +} + +# Keep a list of devices used for removal at end of test. +$device_count = 0; +my @device_list; + +if ($disable_udisks) { + $udisks2_status = udisks2_stop(); +} + +$context_opt = "context=system_u:object_r:test_filesystem_file_t:s0"; +$rootcontext_opt = "rootcontext=system_u:object_r:test_filesystem_file_t:s0"; +$defcontext_opt = "defcontext=system_u:object_r:test_filesystem_file_t:s0"; +$fscontext_opt = "fscontext=system_u:object_r:test_filesystem_file_t:s0"; + +foreach my $fs_type (@fs_type_list) { + mk_mntpoint_1("$basedir/mntpoint"); + ( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); + make_fs( $fs_type, $dev, $basedir ); + + if ( $fs_type eq "ntfs" ) { + $fs_type = "fuseblk"; + } + if ( $fs_type eq "fat" ) { + $fs_type = "vfat"; + } + + # Test context + print "Testing context= for $fs_type\n"; + $result = system( +"runcon -t test_filesystem_t $basedir/fsconfig $v -f $fs_type -s $dev -o $context_opt 2>&1" + ); + if ( $fs_type eq "fuseblk" ) { # This is expected to fail + ok(1); + } + else { + ok( $result eq 0 ); + } + + # Test defcontext + print "Testing defcontext= for $fs_type\n"; + $result = system( +"runcon -t test_filesystem_t $basedir/fsconfig $v -f $fs_type -s $dev -o $defcontext_opt 2>&1" + ); + if ( $fs_type eq "vfat" + or $fs_type eq "hfsplus" + or $fs_type eq "minix" + or $fs_type eq "msdos" + or $fs_type eq "fuseblk" + or $fs_type eq "reiserfs" ) + { # These are expected to fail + ok(1); + } + else { + ok( $result eq 0 ); + } + + # Test rootcontext + print "Testing rootcontext= for $fs_type\n"; + $result = system( +"runcon -t test_filesystem_t $basedir/fsconfig $v -f $fs_type -s $dev -o $rootcontext_opt 2>&1" + ); + if ( $fs_type eq "fuseblk" ) { # This is expected to fail + ok(1); + } + else { + ok( $result eq 0 ); + } + + # Test fscontext + print "Testing fscontext= for $fs_type\n"; + $result = system( +"runcon -t test_filesystem_t $basedir/fsconfig $v -f $fs_type -s $dev -o $fscontext_opt 2>&1" + ); + if ( $fs_type eq "fuseblk" ) { # This is expected to fail + ok(1); + } + else { + ok( $result eq 0 ); + } + + cleanup1( $basedir, $dev ); +} + +cleanup1( $basedir, $dev ); +reaper( \@device_list, $basedir, $v ); + +if ($disable_udisks) { + udisks2_restart($udisks2_status); +} + +exit; -- 2.24.1