From patchwork Mon Jan 20 11:11:12 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Haines X-Patchwork-Id: 11341739 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 24805921 for ; Mon, 20 Jan 2020 11:11:23 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id D924F2087E for ; Mon, 20 Jan 2020 11:11:22 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=btinternet.com header.i=@btinternet.com header.b="E07ShUmj" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726621AbgATLLW (ORCPT ); Mon, 20 Jan 2020 06:11:22 -0500 Received: from mailomta24-re.btinternet.com ([213.120.69.117]:25715 "EHLO re-prd-fep-043.btinternet.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1727011AbgATLLW (ORCPT ); Mon, 20 Jan 2020 06:11:22 -0500 Received: from re-prd-rgout-001.btmx-prd.synchronoss.net ([10.2.54.4]) by re-prd-fep-043.btinternet.com with ESMTP id <20200120111117.GWUP11959.re-prd-fep-043.btinternet.com@re-prd-rgout-001.btmx-prd.synchronoss.net>; Mon, 20 Jan 2020 11:11:17 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=btinternet.com; s=btmx201904; t=1579518677; bh=0X025A2E+An8VImVtF4VuREXathbM6pIJZMbsdMH538=; h=From:To:Cc:Subject:Date:Message-Id:X-Mailer:In-Reply-To:References:MIME-Version; b=E07ShUmjlsVLs/qp47sOks/70BbX10To6BweQDcf5u965TGMTXL7v59znd4SShqu0NdJNInxqKphOmB0Lj8hfATGiIB0aDl0t8sGYRn8qz7en7cOMNkMcuWaxa3qow7fpv8TqmaK73xItocwxIjNnZO0WE5+rnpi8vfo3ZMsKowiHM909qzS7q7uAWrbIcuSRgPgW7MM3c6tWsALoPtaExxR7sl20KIMTES/ONa0nCLqHSCgLf0jVSTETMJqhYREBvb4rFXXkXuIDx+XCSjimTfH32nFH93tA5aTzwutHU6+kkFk58XUB0H0ziyHQL6G9VKGB5g/q+p6J4WRpe8Pzw== Authentication-Results: btinternet.com; none X-Originating-IP: [31.49.56.209] X-OWM-Source-IP: 31.49.56.209 (GB) X-OWM-Env-Sender: richard_c_haines@btinternet.com X-VadeSecure-score: verdict=clean score=0/300, class=clean X-RazorGate-Vade: gggruggvucftvghtrhhoucdtuddrgedugedrudehgddujecutefuodetggdotefrodftvfcurfhrohhfihhlvgemuceutffkvffkuffjvffgnffgvefqofdpqfgfvfenuceurghilhhouhhtmecufedttdenucenucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomheptfhitghhrghrugcujfgrihhnvghsuceorhhitghhrghruggptggphhgrihhnvghssegsthhinhhtvghrnhgvthdrtghomheqnecukfhppeefuddrgeelrdehiedrvddtleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhephhgvlhhopehlohgtrghlhhhoshhtrdhlohgtrghlughomhgrihhnpdhinhgvthepfedurdegledrheeirddvtdelpdhmrghilhhfrhhomhepoehrihgthhgrrhgupggtpghhrghinhgvshessghtihhnthgvrhhnvghtrdgtohhmqedprhgtphhtthhopeeorhhitghhrghruggptggphhgrihhnvghssegsthhinhhtvghrnhgvthdrtghomhequcfqtfevrffvpehrfhgtkedvvdenrhhitghhrghruggptggphhgrihhnvghssegsthhinhhtvghrnhgvthdrtghomhdprhgtphhtthhopeeoshgvlhhinhhugiesvhhgvghrrdhkvghrnhgvlhdrohhrgheq X-RazorGate-Vade-Verdict: clean 0 X-RazorGate-Vade-Classification: clean Received: from localhost.localdomain (31.49.56.209) by re-prd-rgout-001.btmx-prd.synchronoss.net (5.8.337) (authenticated as richard_c_haines@btinternet.com) id 5DEE078D0731A0FA; Mon, 20 Jan 2020 11:11:16 +0000 From: Richard Haines To: selinux@vger.kernel.org Cc: Richard Haines Subject: [PATCH 1/2] selinux-testsuite: Prepare for adding fs*(2) API tests Date: Mon, 20 Jan 2020 11:11:12 +0000 Message-Id: <20200120111113.23349-2-richard_c_haines@btinternet.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200120111113.23349-1-richard_c_haines@btinternet.com> References: <20200120111113.23349-1-richard_c_haines@btinternet.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Update the current tests/filesystem to share code and perl subroutines. Also update tools/check-syntax to handle *.pm files. Signed-off-by: Richard Haines Acked-by: Stephen Smalley --- policy/test_filesystem.te | 18 ++- tests/filesystem/Filesystem.pm | 166 +++++++++++++++++++++++++ tests/filesystem/test | 219 ++++++--------------------------- tools/check-syntax | 2 +- 4 files changed, 222 insertions(+), 183 deletions(-) create mode 100644 tests/filesystem/Filesystem.pm diff --git a/policy/test_filesystem.te b/policy/test_filesystem.te index a029a1b..9cf8903 100644 --- a/policy/test_filesystem.te +++ b/policy/test_filesystem.te @@ -233,6 +233,22 @@ 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 file { mounton } ###################### +# hooks.c selinux_move_mount() FILE__MOUNTON +type test_move_mount_no_mounton_t; +domain_type(test_move_mount_no_mounton_t) +unconfined_runs_test(test_move_mount_no_mounton_t) +typeattribute test_move_mount_no_mounton_t testdomain; +typeattribute test_move_mount_no_mounton_t filesystemdomain; + +allow test_move_mount_no_mounton_t self:capability { sys_admin }; +fs_mount_all_fs(test_move_mount_no_mounton_t) +fs_unmount_all_fs(test_move_mount_no_mounton_t) +fs_relabelfrom_all_fs(test_move_mount_no_mounton_t) +fs_associate(test_move_mount_no_mounton_t) +allow test_move_mount_no_mounton_t test_file_t:dir { mounton write remove_name rmdir }; +# neverallow test_move_mount_no_mounton_t self:dir { mounton }; + #################### Deny filesystem { unmount } ###################### # hooks.c selinux_umount() FILESYSTEM__UNMOUNT type test_filesystem_no_unmount_t; @@ -273,8 +289,6 @@ 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; diff --git a/tests/filesystem/Filesystem.pm b/tests/filesystem/Filesystem.pm new file mode 100644 index 0000000..3d4194d --- /dev/null +++ b/tests/filesystem/Filesystem.pm @@ -0,0 +1,166 @@ +package Filesystem; +use Exporter qw(import); +our @EXPORT_OK = + qw(check_config udisks2_stop udisks2_restart get_loop_dev attach_dev make_fs mk_mntpoint_1 mk_mntpoint_2 cleanup cleanup1 reaper); + +sub check_config { + my ( $base, $fanotify_fs ) = @_; + + $tst_count = 0; + + # From kernel 5.5 support for fanotify(7) with filesystem { watch } + $kvercur = `uname -r`; + chomp($kvercur); + $kverminstream = "5.5"; + $watch = 0; + + $result = `$base/../kvercmp $kvercur $kverminstream`; + if ( $result > 0 && -e $fanotify_fs ) { + $watch = 1; + $tst_count += 4; + } + + $name_trans = 0; + $pol_vers = `checkpolicy -V | cut -f 1 -d ' '`; + $mod_pol_vers = `checkmodule -V | cut -f 2 -d '-'`; + $max_kernel_policy = `cat /sys/fs/selinux/policyvers`; + + if ( $mod_pol_vers >= 11 and $pol_vers >= 25 and $max_kernel_policy >= 25 ) + { + $name_trans = 1; + $tst_count += 2; + } + return ( $tst_count, $watch, $name_trans ); +} + +# 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 { + my ( $dev_list, $dev_count ) = @_; + + system("udevadm settle"); + print "Finding free /dev/loop entry\n"; + $new_dev = `losetup -f 2>/dev/null`; + chomp($new_dev); + if ( $new_dev eq "" ) { + print "losetup failed to obtain /dev/loop entry\n"; + } + + # Keep list of devices for cleanup later + if ( $dev_count eq 0 ) { + $dev_list[$dev_count] = $new_dev; + $dev_count += 1; + } + elsif ( $new_dev ne $dev_list[ $dev_count - 1 ] ) { + $dev_list[$dev_count] = $new_dev; + $dev_count += 1; + } + return ( $new_dev, $dev_count ); +} + +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 ( $dev_list, $base, $v ) = @_; + + foreach my $n (@dev_list) { + system("udevadm settle"); + system("$base/grim_reaper -t $n $v 2>/dev/null"); + } +} diff --git a/tests/filesystem/test b/tests/filesystem/test index 1d90fdf..5bdd124 100755 --- a/tests/filesystem/test +++ b/tests/filesystem/test @@ -5,6 +5,13 @@ 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); + use Filesystem + qw(check_config udisks2_stop udisks2_restart get_loop_dev attach_dev make_fs mk_mntpoint_1 mk_mntpoint_2 cleanup cleanup1 reaper); + $test_count = 68; # Options: -v = Verbose, -d disable udisks(8) daemon @@ -20,29 +27,11 @@ BEGIN { } } - # 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 '-'`; - $max_kernel_policy = `cat /sys/fs/selinux/policyvers`; + # Check if watch and/or named type_transition rules configured + ( $addit, $test_watch, $test_name_trans ) = + check_config( $basedir, "$basedir/fanotify_fs" ); - if ( $mod_pol_vers >= 11 and $pol_vers >= 25 and $max_kernel_policy >= 25 ) - { - $test_name_trans = 1; - $test_count += 2; - } - - plan tests => $test_count; + plan tests => ( $test_count += $addit ); } # mount(2) MS_BIND | MS_PRIVATE requires an absolute path to a private mount @@ -60,139 +49,9 @@ else { # Set initial filesystem type $fs_type = "ext4"; -# For list of devices used +# Keep a list of devices used for removal at end of test. $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 +my @device_list; if ($disable_udisks) { $udisks2_status = udisks2_stop(); @@ -216,7 +75,7 @@ system("rm -rf $basedir/mntpoint 2>/dev/null"); ############### Test Basic Mount/Unmount ########################## mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $mount_opts1 = "quota,usrquota,grpquota,defcontext=system_u:object_r:test_filesystem_file_t:s0"; @@ -306,7 +165,7 @@ cleanup1( $basedir, $dev ); ############### Test Move Mount ########################## mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $mount_opts2 = "quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_file_t:s0"; @@ -353,7 +212,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { relabelfrom } ########################## # hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_relabelfrom = "defcontext=system_u:object_r:test_filesystem_sb_relabel_no_relabelfrom_t:s0"; @@ -371,7 +230,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { relabelto } ########################## # hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_relabelto = "fscontext=system_u:object_r:test_filesystem_sb_relabel_no_relabelto_t:s0"; @@ -389,7 +248,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { relabelfrom } ########################## # hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_relabelfrom = "rootcontext=system_u:object_r:test_filesystem_no_inode_no_relabelfrom_t:s0"; @@ -407,7 +266,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { associate } ########################## # hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); # This defcontext will trigger denial. @@ -427,7 +286,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { associate } ########################## # hooks.c may_create() FILESYSTEM__ASSOCIATE mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); # Use this fscontext= to get sensible audit log entry of: @@ -462,7 +321,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { quotamod } ########################## # hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_quotamod = "quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesystem_no_quotamod_t:s0"; @@ -475,7 +334,7 @@ $result = system( 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 +print "Toggle User & Group quotas on/off\n"; $result = system( "runcon -t test_filesystem_no_quotamod_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1" ); @@ -493,7 +352,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { quotaget } ########################## # hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_quotaget = "quota,usrquota,grpquota,context=system_u:object_r:test_filesystem_no_quotaget_t:s0"; @@ -509,7 +368,7 @@ 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 +print "Toggle User & Group quotas on/off\n"; $result = system( "runcon -t test_filesystem_no_quotaget_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1" ); @@ -527,7 +386,7 @@ cleanup1( $basedir, $dev ); ############### Deny file { quotaon } ########################## # hooks.c selinux_quota_on() FILE__QUOTAON mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_quotaon = "quota,usrquota,grpquota,context=system_u:object_r:test_file_no_quotaon_t:s0"; @@ -543,7 +402,7 @@ 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 +print "Toggle User quotas on/off\n"; $result = system( "runcon -t test_file_no_quotaon_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1" ); @@ -561,7 +420,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { mount } ########################## # hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_mount = "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0"; @@ -578,7 +437,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { getattr } ########################## # hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_getattr = "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0"; @@ -607,7 +466,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { remount } ########################## # hooks.c selinux_mount() FILESYSTEM__REMOUNT mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_remount = "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0"; @@ -637,7 +496,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { unmount } ########################## # hooks.c selinux_umount() FILESYSTEM__UNMOUNT mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_unmount = "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0"; @@ -668,7 +527,7 @@ cleanup1( $basedir, $dev ); ############### Deny filesystem { associate } ########################## # hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); 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"; @@ -701,7 +560,7 @@ cleanup1( $basedir, $dev ); # hooks.c selinux_path_notify() FILESYSTEM__WATCH if ($test_watch) { mk_mntpoint_1($private_path); - $dev = get_loop_dev(); + ( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $opts_no_watch = "context=system_u:object_r:test_filesystem_no_watch_t:s0"; @@ -738,7 +597,7 @@ if ($test_watch) { # files within the mount fails with errno EOPNOTSUPP. ########################################################################## mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); # Mount with xttrs to create a file with specific context. @@ -769,7 +628,7 @@ 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(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); attach_dev( $dev, $basedir ); # Mount again with no xttr support @@ -816,7 +675,7 @@ cleanup1( $basedir, $dev ); # the mount operation. ########################################################################## mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $root_opts = "rootcontext=system_u:object_r:test_filesystem_context_file_t:s0"; @@ -863,7 +722,7 @@ cleanup1( $basedir, $dev ); # where defcontext differs from the policy default. ########################################################################## mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); make_fs( $fs_type, $dev, $basedir ); $test_opts = "context=system_u:object_r:test_filesystem_context_file_t:s0"; @@ -891,7 +750,7 @@ 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(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); attach_dev( $dev, $basedir ); # Mount again with defcontext= @@ -930,7 +789,7 @@ cleanup1( $basedir, $dev ); ########################################################################## $fs_type = "tmpfs"; mk_mntpoint_1($private_path); -$dev = get_loop_dev(); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); $fscontext_opts = "fscontext=system_u:object_r:test_filesystem_fscontext_fs_t:s0,size=10M,mode=0770"; @@ -959,7 +818,7 @@ ok( $result eq 0 ); print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; cleanup1( $basedir, $dev ); -reaper( $basedir, $v ); +reaper( \@device_list, $basedir, $v ); if ($disable_udisks) { udisks2_restart($udisks2_status); diff --git a/tools/check-syntax b/tools/check-syntax index 7f9768d..0ca79e2 100755 --- a/tools/check-syntax +++ b/tools/check-syntax @@ -13,7 +13,7 @@ CHK_C_LIST="$(find tests/ -name "*.c") $(find tests/ -name "*.h")" CHK_C_EXCLUDE="" -CHK_PERL_LIST="$(find tests/ -name "*.pl") $(find tests/ -name "test")" +CHK_PERL_LIST="$(find tests/ -name "*.pl") $(find tests/ -name "test") $(find tests/ -name "*.pm")" CHK_PERL_EXCLUDE="" #### From patchwork Mon Jan 20 11:11:13 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Haines X-Patchwork-Id: 11341741 Return-Path: Received: from mail.kernel.org (pdx-korg-mail-1.web.codeaurora.org [172.30.200.123]) by pdx-korg-patchwork-2.web.codeaurora.org (Postfix) with ESMTP id 2BC52921 for ; Mon, 20 Jan 2020 11:11:24 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id DFD9220674 for ; Mon, 20 Jan 2020 11:11:23 +0000 (UTC) Authentication-Results: mail.kernel.org; dkim=pass (2048-bit key) header.d=btinternet.com header.i=@btinternet.com header.b="c0caiG8V" Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1727011AbgATLLX (ORCPT ); Mon, 20 Jan 2020 06:11:23 -0500 Received: from mailomta21-re.btinternet.com ([213.120.69.114]:36506 "EHLO re-prd-fep-043.btinternet.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1726451AbgATLLX (ORCPT ); Mon, 20 Jan 2020 06:11:23 -0500 Received: from re-prd-rgout-001.btmx-prd.synchronoss.net ([10.2.54.4]) by re-prd-fep-043.btinternet.com with ESMTP id <20200120111118.GWUQ11959.re-prd-fep-043.btinternet.com@re-prd-rgout-001.btmx-prd.synchronoss.net>; Mon, 20 Jan 2020 11:11:18 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=btinternet.com; s=btmx201904; t=1579518678; bh=UYf43kSmNIecqwEjploXH/5XhCtbKaspomIWeP6o/iE=; h=From:To:Cc:Subject:Date:Message-Id:X-Mailer:In-Reply-To:References:MIME-Version; b=c0caiG8VXkWAUHGE95r1Tf85I7T5ZLxRnz5JRiO8fEyq3Y3QYz/wCskTgSlALFQtoU4cSz0NNZfptmVHWycFU1IBzTJdx56eK6yTeElNLH8XhlNKq9aGebCOl7X0DNpIIJR8kXgiifyDoDyX+/B5lrmXSDie0coxvRdik3Z/h7y4NS3zlMZ0bbwCRl9zWE/orqT8peIfHil7PhPwJOqL7LEJP9SsMp4ANuCd3FD3k6hXLhPFuPqsonMSyoV0C0U7ktvpHEvs1bBIfq0idQ0BDwGmTN/WSbsHAfcbTLS4uEn1g2LSL0TrP9eofALWruijB1XZwUS/nbhnt0LbGAni+A== Authentication-Results: btinternet.com; none X-Originating-IP: [31.49.56.209] X-OWM-Source-IP: 31.49.56.209 (GB) X-OWM-Env-Sender: richard_c_haines@btinternet.com X-VadeSecure-score: verdict=clean score=0/300, class=clean X-RazorGate-Vade: gggruggvucftvghtrhhoucdtuddrgedugedrudehgddujecutefuodetggdotefrodftvfcurfhrohhfihhlvgemuceutffkvffkuffjvffgnffgvefqofdpqfgfvfenuceurghilhhouhhtmecufedttdenucenucfjughrpefhvffufffkofgjfhgggfestdekredtredttdenucfhrhhomheptfhitghhrghrugcujfgrihhnvghsuceorhhitghhrghruggptggphhgrihhnvghssegsthhinhhtvghrnhgvthdrtghomheqnecukfhppeefuddrgeelrdehiedrvddtleenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhephhgvlhhopehlohgtrghlhhhoshhtrdhlohgtrghlughomhgrihhnpdhinhgvthepfedurdegledrheeirddvtdelpdhmrghilhhfrhhomhepoehrihgthhgrrhgupggtpghhrghinhgvshessghtihhnthgvrhhnvghtrdgtohhmqedprhgtphhtthhopeeorhhitghhrghruggptggphhgrihhnvghssegsthhinhhtvghrnhgvthdrtghomhequcfqtfevrffvpehrfhgtkedvvdenrhhitghhrghruggptggphhgrihhnvghssegsthhinhhtvghrnhgvthdrtghomhdprhgtphhtthhopeeoshgvlhhinhhugiesvhhgvghrrdhkvghrnhgvlhdrohhrgheq X-RazorGate-Vade-Verdict: clean 0 X-RazorGate-Vade-Classification: clean Received: from localhost.localdomain (31.49.56.209) by re-prd-rgout-001.btmx-prd.synchronoss.net (5.8.337) (authenticated as richard_c_haines@btinternet.com) id 5DEE078D0731A120; Mon, 20 Jan 2020 11:11:18 +0000 From: Richard Haines To: selinux@vger.kernel.org Cc: Richard Haines Subject: [PATCH 2/2] selinux-testsuite: Add fs*(2) API filesystem tests Date: Mon, 20 Jan 2020 11:11:13 +0000 Message-Id: <20200120111113.23349-3-richard_c_haines@btinternet.com> X-Mailer: git-send-email 2.24.1 In-Reply-To: <20200120111113.23349-1-richard_c_haines@btinternet.com> References: <20200120111113.23349-1-richard_c_haines@btinternet.com> MIME-Version: 1.0 Sender: selinux-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Test filesystem permissions using the fsopen(2), fsconfig(2), fsmount(2), fspick(2) and fsmount(2) api's introduced in kernel 5.2. Also tests move_mount(2) using open_tree(2). These tests use common code from tests/filesystem. Signed-off-by: Richard Haines Acked-by: Stephen Smalley --- tests/Makefile | 6 + tests/fs_filesystem/.gitignore | 3 + tests/fs_filesystem/Makefile | 16 + tests/fs_filesystem/fs_common.c | 110 ++++ tests/fs_filesystem/fs_common.h | 30 ++ tests/fs_filesystem/fsmount.c | 89 ++++ tests/fs_filesystem/fspick.c | 68 +++ tests/fs_filesystem/move_mount.c | 76 +++ tests/fs_filesystem/test | 833 +++++++++++++++++++++++++++++++ 9 files changed, 1231 insertions(+) create mode 100644 tests/fs_filesystem/.gitignore create mode 100644 tests/fs_filesystem/Makefile create mode 100644 tests/fs_filesystem/fs_common.c create mode 100644 tests/fs_filesystem/fs_common.h create mode 100644 tests/fs_filesystem/fsmount.c create mode 100644 tests/fs_filesystem/fspick.c create mode 100644 tests/fs_filesystem/move_mount.c create mode 100755 tests/fs_filesystem/test diff --git a/tests/Makefile b/tests/Makefile index a1478f1..46a1641 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -98,6 +98,12 @@ export CFLAGS += -DHAVE_FS_WATCH_PERM endif 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 +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/fs_filesystem/.gitignore b/tests/fs_filesystem/.gitignore new file mode 100644 index 0000000..449f625 --- /dev/null +++ b/tests/fs_filesystem/.gitignore @@ -0,0 +1,3 @@ +fsmount +fspick +move_mount diff --git a/tests/fs_filesystem/Makefile b/tests/fs_filesystem/Makefile new file mode 100644 index 0000000..f7ae89d --- /dev/null +++ b/tests/fs_filesystem/Makefile @@ -0,0 +1,16 @@ +TARGETS = fsmount fspick move_mount + +DEPS = fs_common.c fs_common.h + +LDLIBS += -lselinux + +USE_FS = ../filesystem + +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_filesystem/fs_common.c b/tests/fs_filesystem/fs_common.c new file mode 100644 index 0000000..79200ac --- /dev/null +++ b/tests/fs_filesystem/fs_common.c @@ -0,0 +1,110 @@ +#include "fs_common.h" + +int fsopen(const char *fs_name, unsigned int flags) +{ + return syscall(__NR_fsopen, fs_name, flags); +} + +int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags) +{ + return syscall(__NR_fsmount, fsfd, flags, ms_flags); +} + +int fsconfig(int fsfd, unsigned int cmd, const char *key, + const void *val, int aux) +{ + return syscall(__NR_fsconfig, fsfd, cmd, key, val, aux); +} + +int fspick(int dirfd, const char *pathname, unsigned int flags) +{ + return syscall(__NR_fspick, dirfd, pathname, flags); +} + +int move_mount(int from_dfd, const char *from_pathname, int to_dfd, + const char *to_pathname, unsigned int flags) +{ + return syscall(__NR_move_mount, from_dfd, from_pathname, + to_dfd, to_pathname, flags); +} + +int open_tree(int dirfd, const char *pathname, unsigned int flags) +{ + return syscall(__NR_open_tree, dirfd, pathname, flags); +} + +int fsconfig_opts(int fd, char *src, char *tgt, char *opts, bool verbose) +{ + int result, i, save_errno, start_count, max_entries = 0; + int cmd[MAX_OPS]; + char *key[MAX_OPS], *value[MAX_OPS]; + char *src_str = "source"; + + /* If src then fsmount(2), else its going to be fspick(2) */ + if (src) { + cmd[0] = FSCONFIG_SET_STRING; + key[0] = src_str; + value[0] = src; + start_count = 1; + } else { + start_count = 0; + } + + for (i = start_count; i < MAX_OPS; i++) { + value[i] = strsep(&opts, ","); + if (!value[i]) { + max_entries = i + 1; + break; + } + cmd[i] = FSCONFIG_SET_STRING; + } + + for (i = start_count; value[i] != NULL; i++) { + key[i] = strsep(&value[i], "="); + if (!value[i]) + cmd[i] = FSCONFIG_SET_FLAG; + } + + if (src) { + cmd[i] = FSCONFIG_CMD_CREATE; + key[i] = NULL; + value[i] = NULL; + } else { + cmd[i] = FSCONFIG_CMD_RECONFIGURE; + key[i] = NULL; + value[i] = NULL; + } + + for (i = 0; i != max_entries; i++) { + if (verbose) { + switch (cmd[i]) { + case FSCONFIG_CMD_CREATE: + printf("fsconfig(FSCONFIG_CMD_CREATE, %s, %s, 0)\n", + key[i], value[i]); + break; + case FSCONFIG_CMD_RECONFIGURE: + printf("fsconfig(FSCONFIG_CMD_RECONFIGURE, %s, %s, 0)\n", + key[i], value[i]); + break; + case FSCONFIG_SET_FLAG: + printf("fsconfig(FSCONFIG_SET_FLAG, %s, %s, 0)\n", + key[i], value[i]); + break; + case FSCONFIG_SET_STRING: + printf("fsconfig(FSCONFIG_SET_STRING, %s, %s, 0)\n", + key[i], value[i]); + break; + } + } + + result = fsconfig(fd, cmd[i], key[i], value[i], 0); + save_errno = errno; + if (result < 0) { + fprintf(stderr, "Failed fsconfig(2): %s\n", + strerror(save_errno)); + return save_errno; + } + } + + return 0; +} diff --git a/tests/fs_filesystem/fs_common.h b/tests/fs_filesystem/fs_common.h new file mode 100644 index 0000000..e2fd08f --- /dev/null +++ b/tests/fs_filesystem/fs_common.h @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef AT_EMPTY_PATH +#define AT_EMPTY_PATH 0x1000 +#endif +#ifndef AT_RECURSIVE +#define AT_RECURSIVE 0x8000 +#endif + +int fsopen(const char *fs_name, unsigned int flags); +int fsmount(int fsfd, unsigned int flags, unsigned int ms_flags); +int fsconfig(int fsfd, unsigned int cmd, const char *key, + const void *val, int aux); +int move_mount(int from_dfd, const char *from_pathname, int to_dfd, + const char *to_pathname, unsigned int flags); +int open_tree(int dirfd, const char *pathname, unsigned int flags); +int fspick(int dirfd, const char *pathname, unsigned int flags); + +#define MAX_OPS 40 +int fsconfig_opts(int fd, char *src, char *tgt, char *opts, bool verbose); diff --git a/tests/fs_filesystem/fsmount.c b/tests/fs_filesystem/fsmount.c new file mode 100644 index 0000000..320d82a --- /dev/null +++ b/tests/fs_filesystem/fsmount.c @@ -0,0 +1,89 @@ +#include "fs_common.h" + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s -s src -t tgt -f fs_type [-o options] [-v]\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" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char *argv[]) +{ + int opt, result, fsfd, mfd; + char *context, *src = NULL, *tgt = NULL, *fs_type = NULL, *opts = NULL; + bool verbose = false; + + while ((opt = getopt(argc, argv, "s:t:f:o:v")) != -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 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!src || !tgt || !fs_type) + 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\n\topts: %s\n", + src, tgt, fs_type, opts); + + fsfd = fsopen(fs_type, 0); + if (fsfd < 0) { + fprintf(stderr, "Failed fsopen(2): %s\n", strerror(errno)); + return -1; + } + + /* config_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; + } + + mfd = fsmount(fsfd, 0, 0); + if (mfd < 0) { + fprintf(stderr, "Failed fsmount(2): %s\n", strerror(errno)); + return -1; + } + close(fsfd); + + result = move_mount(mfd, "", AT_FDCWD, tgt, MOVE_MOUNT_F_EMPTY_PATH); + if (result < 0) { + fprintf(stderr, "Failed move_mount(2): %s\n", strerror(errno)); + return -1; + } + close(mfd); + + return 0; +} diff --git a/tests/fs_filesystem/fspick.c b/tests/fs_filesystem/fspick.c new file mode 100644 index 0000000..b1e221d --- /dev/null +++ b/tests/fs_filesystem/fspick.c @@ -0,0 +1,68 @@ +#include "fs_common.h" + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s -t tgt -o options [-v]\n" + "Where:\n\t" + "-t Target 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, pfd; + char *context, *tgt = NULL, *opts = NULL; + bool verbose = false; + + while ((opt = getopt(argc, argv, "t:o:v")) != -1) { + switch (opt) { + case 't': + tgt = optarg; + break; + case 'o': + opts = optarg; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!tgt || !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); + } + + if (verbose) + printf("Mounting\n\ttgt: %s\n\topts: %s\n", tgt, opts); + + pfd = fspick(AT_FDCWD, tgt, 0); + if (pfd < 0) { + fprintf(stderr, "Failed fspick(2): %s\n", strerror(errno)); + return -1; + } + + /* config_opts() will return 0 or errno from fsconfig(2) */ + result = fsconfig_opts(pfd, NULL, tgt, opts, verbose); + if (result) { + fprintf(stderr, "Failed config_opts\n"); + return result; + } + + close(pfd); + return 0; +} diff --git a/tests/fs_filesystem/move_mount.c b/tests/fs_filesystem/move_mount.c new file mode 100644 index 0000000..1b17df9 --- /dev/null +++ b/tests/fs_filesystem/move_mount.c @@ -0,0 +1,76 @@ +#include "fs_common.h" + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s -s src -t tgt [-v]\n" + "Where:\n\t" + "-s Source path\n\t" + "-t Target path\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char *argv[]) +{ + int opt, result, fd1, fd2, save_errno; + char *context, *src = NULL, *tgt = NULL; + bool verbose = false; + + 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 (verbose) + printf("Mounting\n\tsrc: %s\n\ttgt: %s\n", src, tgt); + + fd1 = open_tree(AT_FDCWD, src, 0); + if (fd1 < 0) { + fprintf(stderr, "Failed fd1 open_tree(2): %s\n", + strerror(errno)); + return -1; + } + + fd2 = open_tree(fd1, "", AT_EMPTY_PATH | OPEN_TREE_CLONE | AT_RECURSIVE); + if (fd2 < 0) { + fprintf(stderr, "Failed fd2 open_tree(2): %s\n", + strerror(errno)); + return -1; + } + + result = move_mount(fd2, "", AT_FDCWD, tgt, MOVE_MOUNT_F_EMPTY_PATH); + save_errno = errno; + if (result < 0) { + fprintf(stderr, "Failed move_mount(2): %s\n", strerror(errno)); + return save_errno; + } + + close(fd1); + close(fd2); + return 0; +} diff --git a/tests/fs_filesystem/test b/tests/fs_filesystem/test new file mode 100755 index 0000000..bda7fcf --- /dev/null +++ b/tests/fs_filesystem/test @@ -0,0 +1,833 @@ +#!/usr/bin/perl +use Test::More; + +BEGIN { + $basedir = $0; + $basedir =~ s|(.*)/[^/]*|$1|; + + # Load common subroutines from filesystem/Filesystem.pm + use File::Basename qw(dirname); + use Cwd qw(abs_path); + use lib dirname( abs_path $0) . '/../filesystem'; + use Filesystem + qw(check_config udisks2_stop udisks2_restart get_loop_dev attach_dev make_fs mk_mntpoint_1 mk_mntpoint_2 cleanup cleanup1 reaper); + + # Some code in tests/filesystem is reused + $filesystem_dir = "$basedir/../filesystem"; + $test_count = 63; + + # 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; + } + } + + # Check if watch and/or named type_transition rules configured + ( $addit, $test_watch, $test_name_trans ) = + check_config( $basedir, "$filesystem_dir/fanotify_fs" ); + + # Set to '1' for testing 'hooks.c selinux_move_mount() FILE__MOUNTON' + # Once kernel patch is mainline, add kernel version test. + $test_move_mount = 0; + if ($test_move_mount) { + $test_count += 3; + } + + plan tests => ( $test_count += $addit ); +} + +# Set initial filesystem type +$fs_type = "ext4"; + +# 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(); +} + +cleanup($basedir); + +############### Test Basic Mount/Unmount ########################## +mk_mntpoint_1("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $mount_opts1 $v" +); +ok( $result eq 0 ); + +# On RHEL-6, there is a type transition to quota_t when running quotacheck +# as unconfined_t. Using "runcon `id -Z` quotacheck ..." resolves this. +print "Running quotacheck(8) to init user/group quota files\n"; +$result = system("runcon `id -Z` quotacheck -ugF vfsv0 $basedir/mntpoint/mp1"); +ok( $result eq 0 ); + +print "Toggle User & Group quotas on/off\n"; +$result = system( +"runcon -t test_filesystem_t $filesystem_dir/quotas_test -s $dev -t $basedir/mntpoint/mp1/aquota.user $v" +); +ok( $result eq 0 ); +$result = system( +"runcon -t test_filesystem_t $filesystem_dir/quotas_test -s $dev -t $basedir/mntpoint/mp1/aquota.group $v" +); +ok( $result eq 0 ); + +print "Get statfs(2)\n"; +$result = + system( +"runcon -t test_filesystem_t $filesystem_dir/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 $filesystem_dir/create_file -f $basedir/mntpoint/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 $filesystem_dir/create_file_change_context -t test_filesystem_filecon_t -f $basedir/mntpoint/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 $filesystem_dir/create_file -f $basedir/mntpoint/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 $filesystem_dir/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 $filesystem_dir/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 $filesystem_dir/umount -t $basedir/mntpoint/mp1 $v" + ); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1( $basedir, $dev ); + +############### Test Move Mount ########################## +mk_mntpoint_1("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +make_fs( $fs_type, $dev, $basedir ); +$mount_opts2 = +"quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_file_t:s0"; + +print "Mount on $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_t $basedir/fsmount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $mount_opts2 $v" +); +ok( $result eq 0 ); + +mk_mntpoint_2("$basedir/mntpoint"); + +print "Now move_mount(2) filesystem to $basedir/mntpoint/mp2\n"; +$result = system( +"runcon -t test_filesystem_t $basedir/move_mount -s $basedir/mntpoint/mp1 -t $basedir/mntpoint/mp2 $v" +); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp2\n"; +$result = + system( +"runcon -t test_filesystem_t $filesystem_dir/umount -t $basedir/mntpoint/mp2 $v" + ); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = + system( +"runcon -t test_filesystem_t $filesystem_dir/umount -t $basedir/mntpoint/mp1 $v" + ); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1( $basedir, $dev ); + +############### Test Change Mount Options ########################## +mk_mntpoint_1("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +make_fs( $fs_type, $dev, $basedir ); +$mount_opts2 = +"quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_file_t:s0"; + +print "Mount on $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_t $basedir/fsmount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $mount_opts2 $v" +); +ok( $result eq 0 ); + +$change_opts = "rootcontext=system_u:object_r:test_filesystem_file_t:s0"; +print "Now change options with fspick(2)\n"; +$result = system( +"runcon -t test_filesystem_t $basedir/fspick -t $basedir/mntpoint/mp1 -o $change_opts $v" +); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = + system( +"runcon -t test_filesystem_t $filesystem_dir/umount -t $basedir/mntpoint/mp1 $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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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 $filesystem_dir/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 $filesystem_dir/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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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"; +$result = system( +"runcon -t test_filesystem_no_quotamod_t $filesystem_dir/quotas_test -s $dev -t $basedir/mntpoint/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 $filesystem_dir/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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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 $basedir/mntpoint/mp1"); +ok( $result eq 0 ); + +print "Toggle User & Group quotas on/off\n"; +$result = system( +"runcon -t test_filesystem_no_quotaget_t $filesystem_dir/quotas_test -s $dev -t $basedir/mntpoint/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 $filesystem_dir/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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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 $basedir/mntpoint/mp1"); +ok( $result eq 0 ); + +print "Toggle User quotas on/off\n"; +$result = system( +"runcon -t test_file_no_quotaon_t $filesystem_dir/quotas_test -s $dev -t $basedir/mntpoint/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 $filesystem_dir/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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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 $filesystem_dir/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 $filesystem_dir/umount -t $basedir/mntpoint/mp1 $v" +); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1( $basedir, $dev ); + +################ Deny file { mounton } ########################## +# hooks.c selinux_move_mount() FILE__MOUNTON +if ($test_move_mount) { + mk_mntpoint_1("$basedir/mntpoint"); + ( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); + make_fs( $fs_type, $dev, $basedir ); + $opts_no_remount = + "rootcontext=system_u:object_r:test_move_mount_no_mounton_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_move_mount_no_mounton_t $basedir/fsmount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v" + ); + ok( $result eq 0 ); + + mk_mntpoint_2("$basedir/mntpoint"); + + print "Now move filesystem, should fail\n"; + $result = system( +"runcon -t test_move_mount_no_mounton_t $basedir/move_mount -s $basedir/mntpoint/mp2 -t $basedir/mntpoint/mp1 $v 2>&1" + ); + ok( $result >> 8 eq 13 ); + + print "Unmount filesystem from $basedir/mntpoint/mp1\n"; + $result = system( +"runcon -t test_move_mount_no_mounton_t $filesystem_dir/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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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 $filesystem_dir/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 $filesystem_dir/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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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 $filesystem_dir/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 $filesystem_dir/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("$basedir/mntpoint"); + ( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); + 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/fsmount -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 $filesystem_dir/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 $filesystem_dir/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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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 $filesystem_dir/create_file_change_context -t test_filesystem_filecon_t -f $basedir/mntpoint/mp1/test_file $v" + ); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_context_t $filesystem_dir/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, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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 $filesystem_dir/check_file_context -f $basedir/mntpoint/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 $filesystem_dir/create_file_change_context -t test_filesystem_filecon_t -f $basedir/mntpoint/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 $filesystem_dir/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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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 $filesystem_dir/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/fsmount -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 $filesystem_dir/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 $filesystem_dir/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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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 $filesystem_dir/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 $filesystem_dir/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, $device_count ) = get_loop_dev( \@device_list, $device_count ); +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/fsmount -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 $filesystem_dir/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 $filesystem_dir/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("$basedir/mntpoint"); +( $dev, $device_count ) = get_loop_dev( \@device_list, $device_count ); +$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/fsmount -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 $filesystem_dir/create_file_change_context -t test_filesystem_filecon_t -f $basedir/mntpoint/mp1/test_file $v" + ); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = + system( +"runcon -t test_filesystem_fscontext_t $filesystem_dir/umount -t $basedir/mntpoint/mp1 $v" + ); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1( $basedir, $dev ); + +reaper( \@device_list, $filesystem_dir, $v ); + +if ($disable_udisks) { + udisks2_restart($udisks2_status); +} + +exit;