Message ID | 20191220101104.40865-2-richard_c_haines@btinternet.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | selinux-testsuite: Add filesystem tests | expand |
On Fri, Dec 20, 2019 at 11:11 AM Richard Haines <richard_c_haines@btinternet.com> wrote: > Test filesystem permissions and setfscreatecon(3). > > From kernels 5.5 filesystem { watch } is also tested. > > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com> Please see a few inline comments below. [...] > diff --git a/tests/filesystem/create_file_change_context.c b/tests/filesystem/create_file_change_context.c > new file mode 100644 > index 0000000..2a3b995 > --- /dev/null > +++ b/tests/filesystem/create_file_change_context.c > @@ -0,0 +1,143 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <stdbool.h> > +#include <linux/unistd.h> > +#include <selinux/selinux.h> > +#include <selinux/context.h> > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s [-v] -t -f\n" > + "Where:\n\t" > + "-t Type for context of created file\n\t" > + "-f File to create\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +int main(int argc, char **argv) > +{ > + int opt, result, fd, save_err; > + char *context, *newfcon, *orgfcon, *type = NULL, *file = NULL; > + bool verbose = false; > + context_t con_t; > + > + while ((opt = getopt(argc, argv, "t:f:v")) != -1) { > + switch (opt) { > + case 't': > + type = optarg; > + break; > + case 'f': > + file = optarg; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!type || !file) > + print_usage(argv[0]); > + > + result = getcon(&context); > + if (result < 0) { > + fprintf(stderr, "Failed to obtain process context\n"); > + exit(-1); > + } > + > + /* Build new file context */ > + con_t = context_new(context); > + if (!con_t) { > + fprintf(stderr, "Unable to create context structure\n"); > + exit(-1); > + } > + > + if (context_type_set(con_t, type)) { > + fprintf(stderr, "Unable to set new type\n"); > + exit(-1); > + } Shouldn't you rather build the new context from the original file's context? If you build it from the process context, then the role and MLS/MCS range will be wrong. Somehow this code works on recent systems, but on RHEL-6 it causes the test to fail. > + > + newfcon = context_str(con_t); > + if (!newfcon) { > + fprintf(stderr, "Unable to obtain new context string\n"); > + exit(-1); > + } > + > + if (verbose) { > + printf("Process context:\n\t%s\n", context); > + printf("is creating test file:\n\t%s\n", file); > + printf("and changing its context to:\n\t%s\n", newfcon); > + } > + > + free(context); > + context = NULL; > + > + /* hooks.c may_create() FILESYSTEM__ASSOCIATE */ > + fd = creat(file, O_RDWR); > + save_err = errno; > + if (fd < 0) { > + fprintf(stderr, "creat(2) Failed: %s\n", strerror(errno)); > + result = save_err; > + goto err; > + } > + > + result = fgetfilecon(fd, &orgfcon); > + if (result < 0) { > + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", > + strerror(errno)); > + result = -1; > + goto err; > + } > + > + if (verbose) > + printf("Current test file context is: %s\n", orgfcon); > + > + free(orgfcon); > + > + /* hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE */ > + result = fsetfilecon(fd, newfcon); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "fsetfilecon(3) Failed: %s\n", > + strerror(errno)); > + result = save_err; > + goto err; > + } > + > + fd = open(file, O_RDWR); > + if (fd < 0) { > + fprintf(stderr, "open(2) Failed: %s\n", strerror(errno)); > + result = -1; > + } > + > + result = fgetfilecon(fd, &context); > + if (result < 0) { > + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", > + strerror(errno)); > + result = -1; > + goto err; > + } > + > + if (verbose) > + printf("New test file context is: %s\n", context); > + > + result = 0; > + if (strcmp(newfcon, context)) { > + fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n", > + newfcon, context); > + result = -1; > + } > +err: > + free(context); > + free(newfcon); > + close(fd); > + > + return result; > +} [...] > diff --git a/tests/filesystem/quotas_test.c b/tests/filesystem/quotas_test.c > new file mode 100644 > index 0000000..34aaca9 > --- /dev/null > +++ b/tests/filesystem/quotas_test.c > @@ -0,0 +1,134 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <stdbool.h> > +#include <sys/quota.h> > +#include <selinux/selinux.h> Could you please add: #ifndef QFMT_VFS_V0 #define QFMT_VFS_V0 2 #endif so that the code compiles on RHEL/CentOS 7 and below? (There <sys/quota.h> doesn't contain the definition and it conflicts with <linux/quota.h> so I don't see any better way to fix it...) > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s -s src -t tgt\n" > + "Where:\n\t" > + "-s Source path (e.g. /dev/loop0)\n\t" > + "-t Target quota file (Full path with either 'aquota.user'\n\t" > + " or 'aquota.group' appended)\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +int main(int argc, char *argv[]) > +{ > + int opt, result, qcmd, save_err, test_id = geteuid(); > + char *context, *src = NULL, *tgt = NULL; > + bool verbose = false; > + char fmt_buf[2]; > + > + while ((opt = getopt(argc, argv, "s:t:v")) != -1) { > + switch (opt) { > + case 's': > + src = optarg; > + break; > + case 't': > + tgt = optarg; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!src || !tgt) > + print_usage(argv[0]); > + > + if (verbose) { > + result = getcon(&context); > + if (result < 0) { > + fprintf(stderr, "Failed to obtain process context\n"); > + return -1; > + } > + printf("Process context:\n\t%s\n", context); > + free(context); > + } > + > + if (strstr(tgt, "aquota.user") != NULL) { > + qcmd = QCMD(Q_QUOTAON, USRQUOTA); > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_QUOTAON, USRQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("User Quota - ON\n"); > + > + qcmd = QCMD(Q_GETFMT, USRQUOTA); > + result = quotactl(qcmd, src, test_id, fmt_buf); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_GETFMT, USRQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("User Format: 0x%x\n", fmt_buf[0]); > + > + qcmd = QCMD(Q_QUOTAOFF, USRQUOTA); > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_QUOTAOFF, USRQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("User Quota - OFF\n"); > + > + return 0; > + > + } else if (strstr(tgt, "aquota.group") != NULL) { > + qcmd = QCMD(Q_QUOTAON, GRPQUOTA); > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_QUOTAON, GRPQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("Group Quota - ON\n"); > + > + qcmd = QCMD(Q_GETFMT, GRPQUOTA); > + result = quotactl(qcmd, src, test_id, fmt_buf); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_GETFMT, GRPQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("Group Format: 0x%x\n", fmt_buf[0]); > + > + qcmd = QCMD(Q_QUOTAOFF, GRPQUOTA); > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_QUOTAOFF, GRPQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("Group Quota - OFF\n"); > + > + return 0; > + } > + > + fprintf(stderr, "Required %s to specify 'aquota.user' or 'aquota.group' file\n", > + tgt); > + return -1; > +} [...] > diff --git a/tests/filesystem/test b/tests/filesystem/test > new file mode 100755 > index 0000000..00c69e1 > --- /dev/null > +++ b/tests/filesystem/test > @@ -0,0 +1,830 @@ > +#!/usr/bin/perl > +use Test::More; > + > +BEGIN { > + $basedir = $0; > + $basedir =~ s|(.*)/[^/]*|$1|; > + > + $test_count = 63; > + > + # Allow info to be shown. > + $v = $ARGV[0]; > + if ($v) { > + if ( $v ne "-v" ) { > + plan skip_all => "Invalid option (use -v)"; > + } > + } > + else { > + $v = " "; > + } > + > + # From kernel 5.5 support for fanotify(7) with filesystem { watch } > + $kvercur = `uname -r`; > + chomp($kvercur); > + $kverminstream = "5.5"; > + > + $result = `$basedir/../kvercmp $kvercur $kverminstream`; > + if ( $result > 0 && -e "$basedir/fanotify_fs" ) { > + $test_watch = 1; > + $test_count += 4; > + } > + > + plan tests => $test_count; > +} > + > +# mount(2) MS_BIND | MS_PRIVATE requires an absolute path to a private mount > +# point before MS_MOVE > +$cwd = `pwd 2>/dev/null`; > +chomp($cwd); > +$private_path = "$cwd"; > +if ( $basedir eq "." ) { > + $private_path = "$cwd/mntpoint"; > +} > +else { > + $private_path = "$cwd/$basedir/mntpoint"; > +} > + > +# Set initial filesystem type > +$fs_type = "ext4"; > + > +# For list of devices used > +$device_count = 0; > + > +sub get_loop_dev { > + print "Finding free /dev/loop entry\n"; > + $dev = `losetup -f 2>/dev/null`; > + chomp($dev); > + if ( $dev eq "" ) { > + print "losetup failed to obtain /dev/loop entry\n"; > + cleanup(); > + exit -1; > + } > + > + # Keep list of devices for cleanup later > + if ( $device_count eq 0 ) { > + $device_list[$device_count] = $dev; > + $device_count += 1; > + } > + elsif ( $dev ne $device_list[ $device_count - 1 ] ) { > + $device_list[$device_count] = $dev; > + $device_count += 1; > + } > +} > + > +sub attach_dev { > + print "Attaching $basedir/fstest to $dev\n"; > + $result = system("losetup $dev $basedir/fstest 2>/dev/null"); > + if ( $result != 0 ) { > + print "Failed to attach $basedir/fstest to $dev\n"; > + cleanup(); > + exit -1; > + } > +} > + > +sub make_fs { > + my ($mk_type) = @_; > + > + get_loop_dev(); > + > + if ( $mk_type eq "tmpfs" ) { > + return; > + } > + > + print "Create $basedir/fstest with dd\n"; > + $result = system( > + "dd if=/dev/zero of=$basedir/fstest bs=1024 count=10240 2>/dev/null"); > + if ( $result != 0 ) { > + print "dd failed to create fstest\n"; > + exit -1; > + } > + > + attach_dev(); > + > + print "Make $mk_type filesystem on $dev\n"; > + $result = system("mkfs.$mk_type $dev >& /dev/null"); > + if ( $result != 0 ) { > + system("losetup -d $dev 2>/dev/null"); > + cleanup(); > + print "mkfs.$mk_type failed to create filesystem on $dev\n"; > + exit -1; > + } > +} > + > +sub mk_mntpoint_1 { > + system("rm -rf $private_path/mp1 2>/dev/null"); > + system("mkdir -p $private_path/mp1 2>/dev/null"); > +} > + > +sub mk_mntpoint_2 { > + system("rm -rf $private_path/mp2 2>/dev/null"); > + system("mkdir -p $private_path/mp2 2>/dev/null"); > +} > + > +sub cleanup { > + system("rm -rf $basedir/fstest 2>/dev/null"); > + system("rm -rf $basedir/mntpoint 2>/dev/null"); > +} > + > +sub cleanup1 { > + system("losetup -d $dev 2>/dev/null"); > + system("rm -rf $basedir/fstest 2>/dev/null"); > + system("rm -rf $basedir/mntpoint 2>/dev/null"); > +} > + > +############### Test setfscreatecon(3) ########################## > +print "Test setfscreatecon(3)\n"; > +$result = system > +"runcon -t test_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0"; > +ok( $result eq 0 ); > + > +$result = system > +"runcon -t test_no_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0 2>&1"; > +ok( $result >> 8 eq 13 ); > + > +############### Test Basic Mount/Unmount ########################## > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > +$mount_opts1 = > + "quota,usrquota,grpquota,defcontext=system_u:object_r:test_filesystem_t:s0"; > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$mount_opts1\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v" > +); > +ok( $result eq 0 ); > + > +print "Then remount\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/mount -r -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v" > +); > +ok( $result eq 0 ); > + > +print "Running quotacheck(8) to init user/group quota files\n"; > +$result = system("quotacheck -ugF vfsv0 $private_path/mp1"); On RHEL-6, there is a type transition to quota_t when running quotacheck as unconfined_t and it hits some denials... Would it be OK to run it as "runcon `id -Z` quotacheck ..." here to keep the test runnable on older systems? > +ok( $result eq 0 ); > + > +print "Toggle User & Group quotas on/off\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v" > +); > +ok( $result eq 0 ); > +$result = system( > +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.group $v" > +); > +ok( $result eq 0 ); > + > +print "Get statfs(2)\n"; > +$result = > + system( > + "runcon -t test_filesystem_t $basedir/statfs_test -t $basedir/mntpoint $v"); > +ok( $result eq 0 ); > + > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v" > + ); > +ok( $result eq 0 ); > + > +if ($test_watch) { > + print "fanotify(7) test\n"; > + $result = system( > +"runcon -t test_filesystem_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1" > + ); > + ok( $result eq 0 ); > +} > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp1 $v"); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Test Move Mount ########################## > +make_fs($fs_type); > +$mount_opts2 = > + "quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_t:s0"; > +system("mkdir -p $private_path 2>/dev/null"); > + > +print "Set mount MS_BIND on filesystem\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/mount -s $private_path -t $private_path -b $v" > +); > +ok( $result eq 0 ); > + > +print "Set mount MS_PRIVATE on filesystem\n"; > +$result = > + system("runcon -t test_filesystem_t $basedir/mount -t $private_path -p $v"); > +ok( $result eq 0 ); > + > +mk_mntpoint_1(); > +mk_mntpoint_2(); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$mount_opts2\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts2 $v" > +); > +ok( $result eq 0 ); > + > +print "Set mount MS_MOVE on filesystem\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/mount -s $private_path/mp1 -t $private_path/mp2 -m $v" > +); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp2\n"; > +$result = > + system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp2 $v"); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint\n"; > +$result = > + system("runcon -t test_filesystem_t $basedir/umount -t $private_path $v"); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { relabelfrom } ########################## > +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM > + > +$opts_no_relabelfrom = > +"defcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0,fscontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_relabelfrom\n"; > +$result = system( > +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { relabelto } ########################## > +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO > + > +$opts_no_relabelto = > + "fscontext=system_u:object_r:test_filesystem_no_relabelto_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_relabelto\n"; > +$result = system( > +"runcon -t test_filesystem_no_relabelto_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelto $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { relabelfrom } ########################## > +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM > + > +$opts_no_relabelfrom = > + "rootcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_relabelfrom\n"; > +$result = system( > +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { associate } ########################## > +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE > + > +$opts_no_associate = > +"defcontext=system_u:object_r:test_filesystem_no_associate_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_associate\n"; > +$result = system( > +"runcon -t test_filesystem_no_associate_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { associate } ########################## > +# hooks.c may_create() FILESYSTEM__ASSOCIATE > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > +$opts_no_associate_file = > + "fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0"; > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_associate_file\n"; > +$result = system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v" > +); > +ok( $result eq 0 ); > + > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1" > + ); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { quotamod } ########################## > +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD > + > +$opts_no_quotamod = > +"quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesystem_no_quotamod_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > +system("mkdir -p $private_path 2>/dev/null"); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_quotamod\n"; > +$result = system( > +"runcon -t test_filesystem_no_quotamod_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotamod $v 2>&1" > +); > +ok( $result eq 0 ); > + > +# No need to run quotacheck(8) as never gets far enough to read quota file > +print "Toggle User & Group quotas on/off\n"; # Must have full path > +$result = system( > +"runcon -t test_filesystem_no_quotamod_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_no_quotamod_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { quotaget } ########################## > +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET > + > +$opts_no_quotaget = > +"quota,usrquota,grpquota,context=system_u:object_r:test_filesystem_no_quotaget_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_quotaget\n"; > +$result = system( > +"runcon -t test_filesystem_no_quotaget_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotaget $v" > +); > +ok( $result eq 0 ); > + > +print "Running quotacheck(8) to init user/group quota files\n"; > +$result = system("quotacheck -ugF vfsv0 $private_path/mp1"); Same issue as above. > +ok( $result eq 0 ); > + > +print "Toggle User & Group quotas on/off\n"; # Must have full path > +$result = system( > +"runcon -t test_filesystem_no_quotaget_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_no_quotaget_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { mount } ########################## > +# hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT > + > +$opts_no_mount = "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_mount\n"; > +$result = system( > +"runcon -t test_filesystem_no_mount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_mount $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { getattr } ########################## > +# hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR > + > +$opts_no_getattr = > + "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_getattr\n"; > +$result = system( > +"runcon -t test_filesystem_no_getattr_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_getattr $v" > +); > +ok( $result eq 0 ); > + > +$result = system( > +"runcon -t test_filesystem_no_getattr_t $basedir/statfs_test -t $basedir/mntpoint $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_no_getattr_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { remount } ########################## > +# hooks.c selinux_mount() FILESYSTEM__REMOUNT > + > +$opts_no_remount = > + "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_remount\n"; > +$result = system( > +"runcon -t test_filesystem_no_remount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v" > +); > +ok( $result eq 0 ); > + > +print "Then remount\n"; > +$result = system( > +"runcon -t test_filesystem_no_remount_t $basedir/mount -r -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_no_remount_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { unmount } ########################## > +# hooks.c selinux_umount() FILESYSTEM__UNMOUNT > + > +$opts_no_unmount = > + "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_unmount\n"; > +$result = system( > +"runcon -t test_filesystem_no_unmount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_unmount $v" > +); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_no_unmount_t $basedir/umount -t $basedir/mntpoint/mp1 $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +# Make sure it does get unmounted > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > + "runcon -t test_filesystem_t $basedir/umount -t $basedir/mntpoint/mp1 $v"); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { associate } ########################## > +# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > +$opts_no_associate_file = > +"defcontext=system_u:object_r:test_filesystem_no_associate_file_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0"; > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_associate_file\n"; > +$result = system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v" > +); > +ok( $result eq 0 ); > + > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1" > + ); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { watch } ########################## > +# hooks.c selinux_path_notify() FILESYSTEM__WATCH > +if ($test_watch) { > + cleanup(); > + mk_mntpoint_1(); > + make_fs($fs_type); > + $opts_no_watch = "context=system_u:object_r:test_filesystem_no_watch_t:s0"; > + > + print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > + print "Using mount options:\n\t$opts_no_watch\n"; > + $result = system( > +"runcon -t test_filesystem_no_watch_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_watch $v" > + ); > + ok( $result eq 0 ); > + > + print "test_fanotify\n"; > + $result = system( > +"runcon -t test_filesystem_no_watch_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1 2>&1" > + ); > + ok( $result >> 8 eq 13 ); > + > + print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > + $result = system( > +"runcon -t test_filesystem_no_watch_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > + ok( $result eq 0 ); > + > + print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > + cleanup1(); > +} > + > +########################################################################## > +# context - Useful when mounting filesystems that do not support extended > +# attributes. > +# Tested by - Creating a filesystem that has xattrs set to a different value, > +# then mount with context= and confirm that the files have that > +# context as well as any newly created files (even if fscreate > +# was set to something else), and that setfilecon/setxattr() on > +# files within the mount fails with errno EOPNOTSUPP. > +########################################################################## > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +# Mount with xttrs to create a file with specific context. > +$context1_opts = "defcontext=system_u:object_r:test_filesystem_context_t:s0"; > + > +print "Testing 'context=' mount option\n"; > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$context1_opts\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context1_opts $v" > +); > +ok( $result eq 0 ); > + > +# Create file with 'test_filesystem_filecon_t' context > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v" > + ); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +# Need to free the loop device, then get new dev one and attach > +system("losetup -d $dev 2>/dev/null"); > +get_loop_dev(); > +attach_dev(); > + > +# Mount again with no xttr support > +$context2_opts = "context=system_u:object_r:test_filesystem_context_t:s0"; > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$context2_opts\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context2_opts $v" > +); > +ok( $result eq 0 ); > + > +# Now check the context on file is system_u:object_r:test_filesystem_context_t:s0 > +print "Check test file context $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/check_file_context -f $private_path/mp1/test_file -e system_u:object_r:test_filesystem_context_t:s0 $v" > + ); > +ok( $result eq 0 ); > + > +# Then create a file with 'test_filesystem_filecon_t' context, this should fail with EOPNOTSUPP > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v 2>/dev/null" > + ); > +ok( $result >> 8 eq 95 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +########################################################################## > +# rootcontext - Explicitly label the root inode of the filesystem being > +# mounted before that filesystem or inode becomes visible > +# to userspace. > +# Tested by - Set mountpoint to unlabeled_t and then check that the > +# context of the root directory matches rootcontext= after > +# the mount operation. > +########################################################################## > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > +$root_opts = "rootcontext=system_u:object_r:test_filesystem_context_t:s0"; > + > +print "Testing 'rootcontext=' mount option\n"; > + > +# Reset mountpoint to 'unlabeled_t' so it is different to any other possible test values. > +print "Resetting MP to unlabeled_t $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/check_mount_context -r -m $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$root_opts\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $root_opts $v" > +); > +ok( $result eq 0 ); > + > +# Now check the mountpoint is the 'rootcontext=' value > +print "Check MP context $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/check_mount_context -m $basedir/mntpoint/mp1 -e system_u:object_r:test_filesystem_context_t:s0 $v" > + ); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +########################################################################## > +# defcontext - Set default security context for unlabeled files. > +# This overrides the value set for unlabeled files in policy > +# and requires a filesystem that supports xattr labeling. > +# Tested by - Create filesystem that has files w/o xattrs and then confirm > +# that they are mapped to the specified defcontext upon mount, > +# where defcontext differs from the policy default. > +########################################################################## > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +$test_opts = "context=system_u:object_r:test_filesystem_context_t:s0"; > + > +print "Testing 'defcontext=' mount option\n"; > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$test_opts\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $test_opts $v" > +); > +ok( $result eq 0 ); > + > +# Create file, its context will be system_u:object_r:test_filesystem_context_t:s0 from $test_opts > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -u system_u -t test_filesystem_fscontext_t $basedir/create_file -f $basedir/mntpoint/mp1/test_file $v" > + ); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +# Need to free the loop device, then get new dev one and attach > +system("losetup -d $dev 2>/dev/null"); > +get_loop_dev(); > +attach_dev(); > + > +# Mount again with defcontext= > +$defcontext_opts = "defcontext=system_u:object_r:test_filesystem_filecon_t:s0"; > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$defcontext_opts\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $defcontext_opts $v" > +); > +ok( $result eq 0 ); > + > +# Now check the file context is now system_u:object_r:test_filesystem_filecon_t:s0 > +print "Check test file context $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/check_file_context -f $basedir/mntpoint/mp1/test_file -e system_u:object_r:test_filesystem_filecon_t:s0 $v" > + ); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +########################################################################## > +# fscontext - Sets the overarching filesystem label to a specific security > +# context. This filesystem label is separate from the individual > +# labels on the files. > +# Tested by - Mount a tmpfs (fs_use_trans) filesystem with fscontext= and > +# then create a file within it, checking its context. > +########################################################################## > +$fs_type = "tmpfs"; > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > +$fscontext_opts = > +"fscontext=system_u:object_r:test_filesystem_fscontext_t:s0,size=10M,mode=0770"; > + > +print "Testing 'fscontext=' mount option\n"; > +print "Mount tmpfs filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$fscontext_opts\n"; > +$result = system( > +"runcon -t test_filesystem_fscontext_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $fscontext_opts $v" > +); > +ok( $result eq 0 ); > + > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_fscontext_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v" > + ); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_fscontext_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +# Cleanup any attached /dev/loop entries > +foreach my $n (@device_list) { > + system("$basedir/grim_reaper $n 2>/dev/null"); > +} > + > +exit; [...] -- Ondrej Mosnacek <omosnace at redhat dot com> Software Engineer, Security Technologies Red Hat, Inc.
On Mon, 2020-01-06 at 17:11 +0100, Ondrej Mosnacek wrote: > On Fri, Dec 20, 2019 at 11:11 AM Richard Haines > <richard_c_haines@btinternet.com> wrote: > > Test filesystem permissions and setfscreatecon(3). > > > > From kernels 5.5 filesystem { watch } is also tested. > > > > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com> > > Please see a few inline comments below. Thanks for flagging these REL6/7 issues as I only have access to current Fedora plus Rawhide. I'll send update later today. Richard
On 12/20/19 5:11 AM, Richard Haines wrote: > Test filesystem permissions and setfscreatecon(3). > > From kernels 5.5 filesystem { watch } is also tested. > > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com> During the execution of these tests, I see the following kernel log spew: <6>[ 496.535286] loop: module loaded <6>[ 498.180983] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: quota,usrquota,grpquota <4>[ 498.181535] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 498.225114] EXT4-fs (loop0): re-mounted. Opts: quota,usrquota,grpquota <4>[ 498.225167] ext4 filesystem being remounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 498.284372] EXT4-fs (loop0): re-mounted. Opts: (null) <6>[ 498.349328] EXT4-fs (loop0): re-mounted. Opts: (null) <4>[ 498.349385] ext4 filesystem being remounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 500.582812] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: quota,usrquota,grpquota <4>[ 500.583071] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <3>[ 501.030500] blk_update_request: I/O error, dev loop0, sector 0 op 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 <3>[ 501.030856] blk_update_request: I/O error, dev loop0, sector 0 op 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 <6>[ 502.557867] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <6>[ 504.475061] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <6>[ 506.366675] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <3>[ 506.479705] blk_update_request: I/O error, dev loop0, sector 0 op 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 <3>[ 506.479925] blk_update_request: I/O error, dev loop0, sector 0 op 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 <6>[ 508.316818] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <3>[ 508.526137] blk_update_request: I/O error, dev loop0, sector 0 op 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 <3>[ 508.526466] blk_update_request: I/O error, dev loop0, sector 0 op 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 <6>[ 510.241013] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <4>[ 510.241323] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 511.867178] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: quota,usrquota,grpquota <4>[ 511.867442] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <3>[ 512.521949] blk_update_request: I/O error, dev loop0, sector 0 op 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 <3>[ 512.525497] blk_update_request: I/O error, dev loop0, sector 0 op 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 <6>[ 513.996580] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: quota,usrquota,grpquota <4>[ 513.996869] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 514.040984] EXT4-fs (loop0): re-mounted. Opts: (null) <6>[ 514.065928] EXT4-fs (loop0): re-mounted. Opts: (null) <4>[ 514.065950] ext4 filesystem being remounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 516.071775] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <6>[ 518.001912] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <4>[ 518.002294] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 519.450511] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <4>[ 519.450737] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 521.579819] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <4>[ 521.580225] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 523.874190] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <4>[ 523.874526] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 525.559041] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <4>[ 525.559423] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 526.541667] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <4>[ 526.542194] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 528.760343] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <4>[ 528.760704] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 530.463519] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <4>[ 530.463823] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) <6>[ 531.469358] EXT4-fs (loop0): mounted filesystem with ordered data mode. Opts: <4>[ 531.469779] ext4 filesystem being mounted at /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports timestamps until 2038 (0x7fffffff) Wondering if all of that is expected and necessary for testing or if we can get rid of some of the noise. > --- > defconfig | 6 + > policy/Makefile | 4 + > policy/test_filesystem.te | 324 +++++++ > tests/Makefile | 7 + > tests/filesystem/.gitignore | 11 + > tests/filesystem/Makefile | 16 + > tests/filesystem/check_file_context.c | 75 ++ > tests/filesystem/check_mount_context.c | 109 +++ > tests/filesystem/create_file.c | 79 ++ > tests/filesystem/create_file_change_context.c | 143 +++ > tests/filesystem/fanotify_fs.c | 79 ++ > tests/filesystem/fs_relabel.c | 72 ++ > tests/filesystem/grim_reaper.c | 63 ++ > tests/filesystem/mount.c | 130 +++ > tests/filesystem/quotas_test.c | 134 +++ > tests/filesystem/statfs_test.c | 65 ++ > tests/filesystem/test | 830 ++++++++++++++++++ > tests/filesystem/umount.c | 84 ++ > 18 files changed, 2231 insertions(+) > create mode 100644 policy/test_filesystem.te > create mode 100644 tests/filesystem/.gitignore > create mode 100644 tests/filesystem/Makefile > create mode 100644 tests/filesystem/check_file_context.c > create mode 100644 tests/filesystem/check_mount_context.c > create mode 100644 tests/filesystem/create_file.c > create mode 100644 tests/filesystem/create_file_change_context.c > create mode 100644 tests/filesystem/fanotify_fs.c > create mode 100644 tests/filesystem/fs_relabel.c > create mode 100644 tests/filesystem/grim_reaper.c > create mode 100644 tests/filesystem/mount.c > create mode 100644 tests/filesystem/quotas_test.c > create mode 100644 tests/filesystem/statfs_test.c > create mode 100755 tests/filesystem/test > create mode 100644 tests/filesystem/umount.c > > diff --git a/defconfig b/defconfig > index 3bea332..7cb6a2c 100644 > --- a/defconfig > +++ b/defconfig > @@ -88,3 +88,9 @@ CONFIG_TUN=m > CONFIG_HAVE_PERF_EVENTS=y > CONFIG_PERF_EVENTS=y > CONFIG_TRACEPOINTS=y > + > +# Test filesystem permissions. > +# This is not required for SELinux operation itself. > +CONFIG_BLK_DEV_LOOP=m > +CONFIG_BLK_DEV_LOOP_MIN_COUNT=0 > +CONFIG_QFMT_V2=y > diff --git a/policy/Makefile b/policy/Makefile > index 6f1db03..30896d8 100644 > --- a/policy/Makefile > +++ b/policy/Makefile > @@ -114,6 +114,10 @@ TARGETS += test_lockdown.te > export M4PARAM += -Dlockdown_defined > endif > > +ifeq ($(shell grep -q filesystem $(POLDEV)/include/support/all_perms.spt && echo true),true) > +TARGETS += test_filesystem.te > +endif > + > ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6)) > TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te test_ibpkey.te, $(TARGETS)) > endif > diff --git a/policy/test_filesystem.te b/policy/test_filesystem.te > new file mode 100644 > index 0000000..2eee1fc > --- /dev/null > +++ b/policy/test_filesystem.te > @@ -0,0 +1,324 @@ > +# > +######### Test filesystem permissions policy module ########## > +# > +attribute filesystemdomain; > + > +#################### Create a test file context ###################### > +type test_filesystem_filecon_t; > +unconfined_runs_test(test_filesystem_filecon_t) > + > +################# Test all functions ########################## > +type test_filesystem_t; > +domain_type(test_filesystem_t) > +unconfined_runs_test(test_filesystem_t) > +typeattribute test_filesystem_t testdomain; > +typeattribute test_filesystem_t filesystemdomain; > + > +allow test_filesystem_t self:capability { sys_admin }; > +allow test_filesystem_t self:filesystem { mount remount quotamod relabelfrom relabelto unmount quotaget }; > +allow test_filesystem_t self:dir { mounton add_name write }; > +allow test_filesystem_t test_file_t:dir { mounton write remove_name rmdir }; > +# Create test file > +allow test_filesystem_t self:dir { add_name write }; > +allow test_filesystem_t self:file { create relabelfrom relabelto }; > + > +fs_mount_all_fs(test_filesystem_t) > +fs_remount_all_fs(test_filesystem_t) > +fs_unmount_all_fs(test_filesystem_t) > +fs_relabelfrom_all_fs(test_filesystem_t) > +fs_get_xattr_fs_quotas(test_filesystem_t) > +files_search_all(test_filesystem_t) > +# Required for mount opts "rootcontext=system_u:object_r:test_filesystem_t:s0"; > +fs_associate(test_filesystem_t) > +fs_getattr_xattr_fs(test_filesystem_t) > + > +# For running quotacheck(8) > +files_type(test_filesystem_t) > +# Update quotas > +fs_set_all_quotas(test_filesystem_t) > +allow test_filesystem_t self:file { quotaon }; > +# Create test file and change context: > +fs_associate(test_filesystem_filecon_t) > +allow test_filesystem_t test_filesystem_filecon_t:file { open read getattr relabelto write }; > +dontaudit test_filesystem_t kernel_t:process { setsched }; > + > +#################### Deny filesystem { getattr } ###################### > +type test_filesystem_no_getattr_t; > +domain_type(test_filesystem_no_getattr_t) > +unconfined_runs_test(test_filesystem_no_getattr_t) > +typeattribute test_filesystem_no_getattr_t testdomain; > +typeattribute test_filesystem_no_getattr_t filesystemdomain; > + > +allow test_filesystem_no_getattr_t self:capability { sys_admin }; > +fs_mount_all_fs(test_filesystem_no_getattr_t) > +fs_unmount_all_fs(test_filesystem_no_getattr_t) > +fs_relabelfrom_all_fs(test_filesystem_no_getattr_t) > +fs_associate(test_filesystem_no_getattr_t) > +allow test_filesystem_no_getattr_t self:dir { mounton }; > +allow test_filesystem_no_getattr_t test_file_t:dir { mounton write remove_name rmdir }; > +dontaudit test_filesystem_no_getattr_t kernel_t:process { setsched }; > + > +#################### Deny filesystem { remount } ###################### > +type test_filesystem_no_remount_t; > +domain_type(test_filesystem_no_remount_t) > +unconfined_runs_test(test_filesystem_no_remount_t) > +typeattribute test_filesystem_no_remount_t testdomain; > +typeattribute test_filesystem_no_remount_t filesystemdomain; > + > +allow test_filesystem_no_remount_t self:capability { sys_admin }; > +fs_mount_all_fs(test_filesystem_no_remount_t) > +fs_unmount_all_fs(test_filesystem_no_remount_t) > +fs_relabelfrom_all_fs(test_filesystem_no_remount_t) > +fs_associate(test_filesystem_no_remount_t) > +allow test_filesystem_no_remount_t self:dir { mounton }; > +allow test_filesystem_no_remount_t test_file_t:dir { mounton write remove_name rmdir }; > +dontaudit test_filesystem_no_remount_t kernel_t:process { setsched }; > + > +#################### Deny filesystem { mount } ###################### > +type test_filesystem_no_mount_t; > +domain_type(test_filesystem_no_mount_t) > +unconfined_runs_test(test_filesystem_no_mount_t) > +typeattribute test_filesystem_no_mount_t testdomain; > +typeattribute test_filesystem_no_mount_t filesystemdomain; > + > +allow test_filesystem_no_mount_t self:capability { sys_admin }; > +fs_relabelfrom_all_fs(test_filesystem_no_mount_t) > +fs_associate(test_filesystem_no_mount_t) > +allow test_filesystem_no_mount_t self:dir { mounton }; > +allow test_filesystem_no_mount_t test_file_t:dir { mounton write remove_name rmdir }; > +dontaudit test_filesystem_no_mount_t kernel_t:process { setsched }; > + > +#################### Deny filesystem { unmount } ###################### > +type test_filesystem_no_unmount_t; > +domain_type(test_filesystem_no_unmount_t) > +unconfined_runs_test(test_filesystem_no_unmount_t) > +typeattribute test_filesystem_no_unmount_t testdomain; > +typeattribute test_filesystem_no_unmount_t filesystemdomain; > + > +allow test_filesystem_no_unmount_t self:capability { sys_admin }; > +fs_mount_all_fs(test_filesystem_no_unmount_t) > +fs_relabelfrom_all_fs(test_filesystem_no_unmount_t) > +fs_associate(test_filesystem_no_unmount_t) > +allow test_filesystem_no_unmount_t self:dir { mounton }; > +allow test_filesystem_no_unmount_t test_file_t:dir { mounton write remove_name rmdir }; > +dontaudit test_filesystem_no_unmount_t kernel_t:process { setsched }; > + > +#################### Deny filesystem { relabelfrom } ###################### > +type test_filesystem_no_relabelfrom_t; > +domain_type(test_filesystem_no_relabelfrom_t) > +unconfined_runs_test(test_filesystem_no_relabelfrom_t) > +typeattribute test_filesystem_no_relabelfrom_t testdomain; > +typeattribute test_filesystem_no_relabelfrom_t filesystemdomain; > + > +allow test_filesystem_no_relabelfrom_t self:capability { sys_admin }; > +fs_associate(test_filesystem_no_relabelfrom_t) > +allow test_filesystem_no_relabelfrom_t self:dir { mounton }; > +allow test_filesystem_no_relabelfrom_t test_file_t:dir { mounton write remove_name rmdir }; > +dontaudit test_filesystem_no_relabelfrom_t kernel_t:process { setsched }; > + > +#################### Deny filesystem { relabelto } ###################### > +type test_filesystem_no_relabelto_t; > +domain_type(test_filesystem_no_relabelto_t) > +unconfined_runs_test(test_filesystem_no_relabelto_t) > +typeattribute test_filesystem_no_relabelto_t testdomain; > +typeattribute test_filesystem_no_relabelto_t filesystemdomain; > + > +allow test_filesystem_no_relabelto_t self:capability { sys_admin }; > +fs_mount_all_fs(test_filesystem_no_relabelto_t) > +fs_relabelfrom_all_fs(test_filesystem_no_relabelto_t) > +fs_associate(test_filesystem_no_relabelto_t) > +allow test_filesystem_no_relabelto_t self:dir { mounton }; > +allow test_filesystem_no_relabelto_t test_file_t:dir { mounton write remove_name rmdir }; > +dontaudit test_filesystem_no_relabelto_t kernel_t:process { setsched }; > + > +#################### Deny filesystem { associate } ###################### > +type test_filesystem_no_associate_t; > +type test_filesystem_no_associate1_t; > +domain_type(test_filesystem_no_associate_t) > +unconfined_runs_test(test_filesystem_no_associate_t) > +typeattribute test_filesystem_no_associate_t testdomain; > +typeattribute test_filesystem_no_associate_t filesystemdomain; > + > +allow test_filesystem_no_associate_t self:capability { sys_admin }; > +allow test_filesystem_no_associate_t self:filesystem { relabelto mount relabelfrom }; > +fs_mount_all_fs(test_filesystem_no_associate_t) > +fs_relabelfrom_all_fs(test_filesystem_no_associate_t) > +allow test_filesystem_no_associate_t self:dir { mounton }; > +allow test_filesystem_no_associate_t test_file_t:dir { mounton write remove_name rmdir }; > +dontaudit test_filesystem_no_associate_t kernel_t:process { setsched }; > + > +########## Deny filesystem { associate } for create file ################ > +type test_filesystem_no_associate_file_t; > +domain_type(test_filesystem_no_associate_file_t) > +unconfined_runs_test(test_filesystem_no_associate_file_t) > +typeattribute test_filesystem_no_associate_file_t testdomain; > +typeattribute test_filesystem_no_associate_file_t filesystemdomain; > + > +allow test_filesystem_no_associate_file_t self:capability { sys_admin }; > +allow test_filesystem_no_associate_file_t self:filesystem { mount relabelfrom relabelto unmount associate }; > +allow test_filesystem_no_associate_file_t self:dir { mounton add_name write }; > +allow test_filesystem_no_associate_file_t test_file_t:dir { mounton write remove_name rmdir }; > + > +fs_mount_all_fs(test_filesystem_no_associate_file_t) > +fs_unmount_all_fs(test_filesystem_no_associate_file_t) > +fs_relabelfrom_all_fs(test_filesystem_no_associate_file_t) > +fs_associate(test_filesystem_no_associate_file_t) > +fs_getattr_xattr_fs(test_filesystem_no_associate_file_t) > +dontaudit test_filesystem_no_associate_file_t kernel_t:process { setsched }; > + > +# Create test file > +allow test_filesystem_no_associate_file_t self:file { create relabelfrom relabelto }; > +############ hooks.c may_create() FILESYSTEM__ASSOCIATE ############# > +# FOR: neverallow unlabeled_t test_filesystem_no_associate_file_t:filesystem { associate }; > +allow test_filesystem_no_associate_file_t unconfined_t:file { open read write }; > +allow test_filesystem_no_associate_file_t unlabeled_t:dir { add_name search write }; > +allow test_filesystem_no_associate_file_t unlabeled_t:file { create open relabelfrom write }; > +############ hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE ########## > +# FOR: neverallow unconfined_t test_filesystem_no_associate_file_t:filesystem { associate }; > +dontaudit unconfined_t test_filesystem_filecon_t:file { getattr read }; > +allow test_filesystem_no_associate_file_t unconfined_t:dir { add_name write }; > +allow test_filesystem_no_associate_file_t unconfined_t:file { create relabelfrom relabelto }; > + > +#################### Deny filesystem { quotamod } ###################### > +type test_filesystem_no_quotamod_t; > +domain_type(test_filesystem_no_quotamod_t) > +unconfined_runs_test(test_filesystem_no_quotamod_t) > +typeattribute test_filesystem_no_quotamod_t testdomain; > +typeattribute test_filesystem_no_quotamod_t filesystemdomain; > + > +allow test_filesystem_no_quotamod_t self:capability { sys_admin }; > +allow test_filesystem_no_quotamod_t self:filesystem { quotaget relabelto mount unmount}; > +fs_mount_all_fs(test_filesystem_no_quotamod_t) > +fs_relabelfrom_all_fs(test_filesystem_no_quotamod_t) > +fs_associate(test_filesystem_no_quotamod_t) > +# Required as $private_path to quota files > +files_search_all(test_filesystem_no_quotamod_t) > +allow test_filesystem_no_quotamod_t self:dir { mounton }; > +allow test_filesystem_no_quotamod_t test_file_t:dir { mounton write remove_name rmdir }; > +dontaudit test_filesystem_no_quotamod_t kernel_t:process { setsched }; > + > +#################### Deny filesystem { quotaget } ###################### > +type test_filesystem_no_quotaget_t; > +domain_type(test_filesystem_no_quotaget_t) > +unconfined_runs_test(test_filesystem_no_quotaget_t) > +typeattribute test_filesystem_no_quotaget_t testdomain; > +typeattribute test_filesystem_no_quotaget_t filesystemdomain; > + > +allow test_filesystem_no_quotaget_t self:capability { sys_admin }; > +allow test_filesystem_no_quotaget_t self:filesystem { quotamod relabelto mount unmount relabelfrom }; > +allow test_filesystem_no_quotaget_t self:dir { mounton }; > +allow test_filesystem_no_quotaget_t test_file_t:dir { mounton write remove_name rmdir }; > +allow test_filesystem_no_quotaget_t self:file { quotaon }; > +fs_mount_all_fs(test_filesystem_no_quotaget_t) > +fs_relabelfrom_all_fs(test_filesystem_no_quotaget_t) > +fs_associate(test_filesystem_no_quotaget_t) > +# Required as $private_path to quota files > +files_search_all(test_filesystem_no_quotaget_t) > +# For running quotacheck(8) > +files_type(test_filesystem_no_quotaget_t) > +dontaudit test_filesystem_no_quotaget_t kernel_t:process { setsched }; > + > +#################### Deny filesystem { watch } ###################### > +type test_filesystem_no_watch_t; > +domain_type(test_filesystem_no_watch_t) > +unconfined_runs_test(test_filesystem_no_watch_t) > +typeattribute test_filesystem_no_watch_t testdomain; > +typeattribute test_filesystem_no_watch_t filesystemdomain; > + > +allow test_filesystem_no_watch_t self:capability { sys_admin }; > +allow test_filesystem_no_watch_t self:filesystem { associate relabelto mount unmount relabelfrom }; > +allow test_filesystem_no_watch_t self:dir { mounton }; > +allow test_filesystem_no_watch_t test_file_t:dir { mounton write remove_name rmdir }; > +fs_mount_all_fs(test_filesystem_no_watch_t) > +fs_relabelfrom_all_fs(test_filesystem_no_watch_t) > +fs_associate(test_filesystem_no_watch_t) > +dontaudit test_filesystem_no_watch_t kernel_t:process { setsched }; > + > +################# Test process { setfscreate } ############# > +type test_setfscreatecon_t; > +domain_type(test_setfscreatecon_t) > +unconfined_runs_test(test_setfscreatecon_t) > +typeattribute test_setfscreatecon_t testdomain; > +typeattribute test_setfscreatecon_t filesystemdomain; > + > +allow test_setfscreatecon_t self:capability { sys_admin }; > +allow test_setfscreatecon_t self:process { setfscreate }; > + > +# Set new context on fs: > +type test_setfscreatecon_newcon_t; > +domain_type(test_setfscreatecon_newcon_t) > +typeattribute test_setfscreatecon_newcon_t testdomain; > + > +################# deny process { setfscreate } ############# > +type test_no_setfscreatecon_t; > +domain_type(test_no_setfscreatecon_t) > +unconfined_runs_test(test_no_setfscreatecon_t) > +typeattribute test_no_setfscreatecon_t testdomain; > +typeattribute test_no_setfscreatecon_t filesystemdomain; > + > +allow test_no_setfscreatecon_t self:capability { sys_admin }; > +# neverallow test_no_setfscreatecon_t self:process { setfscreate }; > + > +################# Test fscontext= ########################## > +type test_filesystem_fscontext_t; > +domain_type(test_filesystem_fscontext_t) > +unconfined_runs_test(test_filesystem_fscontext_t) > +typeattribute test_filesystem_fscontext_t testdomain; > +typeattribute test_filesystem_fscontext_t filesystemdomain; > + > +allow test_filesystem_fscontext_t self:capability { sys_admin }; > +allow test_filesystem_fscontext_t self:filesystem { associate mount relabelfrom relabelto unmount }; > +allow test_filesystem_fscontext_t self:dir { mounton add_name write }; > +allow test_filesystem_fscontext_t test_file_t:dir { mounton write remove_name rmdir }; > +# Create test file > +allow test_filesystem_fscontext_t self:dir { add_name write }; > +allow test_filesystem_fscontext_t self:file { create relabelfrom relabelto }; > +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { relabelto }; > +allow test_filesystem_filecon_t test_filesystem_fscontext_t:filesystem { associate }; > +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { open getattr read write }; > + > +fs_mount_all_fs(test_filesystem_fscontext_t) > +fs_unmount_all_fs(test_filesystem_fscontext_t) > +fs_relabelfrom_all_fs(test_filesystem_fscontext_t) > +files_search_all(test_filesystem_fscontext_t) > + > +########### Test context=, rootcontext= and defcontext ################# > +type test_filesystem_context_t; > +domain_type(test_filesystem_context_t) > +unconfined_runs_test(test_filesystem_context_t) > +typeattribute test_filesystem_context_t testdomain; > +typeattribute test_filesystem_context_t filesystemdomain; > + > +allow test_filesystem_context_t self:capability { sys_admin }; > +allow test_filesystem_context_t self:filesystem { associate mount relabelfrom relabelto unmount }; > +allow test_filesystem_context_t self:dir { mounton add_name write }; > +allow test_filesystem_context_t test_file_t:dir { mounton write remove_name rmdir }; > +# Create test file > +allow test_filesystem_context_t self:dir { add_name write }; > +allow test_filesystem_context_t self:file { create relabelfrom relabelto }; > +allow test_filesystem_context_t test_filesystem_filecon_t:file { open getattr read write relabelto }; > +allow test_filesystem_filecon_t test_filesystem_context_t:filesystem { associate }; > + > +fs_mount_all_fs(test_filesystem_context_t) > +fs_unmount_all_fs(test_filesystem_context_t) > +fs_relabelfrom_all_fs(test_filesystem_context_t) > +files_search_all(test_filesystem_context_t) > +fs_associate(test_filesystem_context_t) > +allow test_filesystem_context_t test_file_t:dir { add_name }; > +dontaudit test_filesystem_context_t kernel_t:process { setsched }; > + > +# For testing rootcontext= Set mountpoint to unlabeled first > +allow test_filesystem_context_t test_file_t:dir { relabelfrom }; > +allow test_filesystem_context_t unlabeled_t:dir { mounton relabelto }; > + > +# For testing defcontext= > +allow test_filesystem_context_t test_filesystem_filecon_t:dir { search }; > +allow test_filesystem_fscontext_t test_filesystem_context_t:dir { add_name search write }; > +allow test_filesystem_fscontext_t test_filesystem_context_t:file { create getattr open write }; > +dontaudit unconfined_t test_filesystem_filecon_t:dir { read search }; > + > +# > +########### Allow these domains to be entered from sysadm domain ############ > +# > +miscfiles_domain_entry_test_files(filesystemdomain) > +userdom_sysadm_entry_spec_domtrans_to(filesystemdomain) > diff --git a/tests/Makefile b/tests/Makefile > index e19ea2f..a1478f1 100644 > --- a/tests/Makefile > +++ b/tests/Makefile > @@ -91,6 +91,13 @@ ifeq ($(shell grep -q lockdown $(POLDEV)/include/support/all_perms.spt && echo t > SUBDIRS += lockdown > endif > > +ifeq ($(shell grep -q filesystem $(POLDEV)/include/support/all_perms.spt && echo true),true) > +SUBDIRS += filesystem > +ifeq ($(shell grep -q all_filesystem_perms.*watch $(POLDEV)/include/support/all_perms.spt && echo true),true) > +export CFLAGS += -DHAVE_FS_WATCH_PERM > +endif > +endif > + > ifeq ($(DISTRO),RHEL4) > SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp_nosuid overlay unix_socket, $(SUBDIRS)) > endif > diff --git a/tests/filesystem/.gitignore b/tests/filesystem/.gitignore > new file mode 100644 > index 0000000..5ac18d0 > --- /dev/null > +++ b/tests/filesystem/.gitignore > @@ -0,0 +1,11 @@ > +mount > +umount > +quotas_test > +statfs_test > +fanotify_fs > +create_file_change_context > +fs_relabel > +check_file_context > +check_mount_context > +create_file > +grim_reaper > diff --git a/tests/filesystem/Makefile b/tests/filesystem/Makefile > new file mode 100644 > index 0000000..d2fad63 > --- /dev/null > +++ b/tests/filesystem/Makefile > @@ -0,0 +1,16 @@ > +# Required for local building > +#export CFLAGS += -DHAVE_FS_WATCH_PERM > + > +TARGETS = mount umount quotas_test statfs_test create_file_change_context \ > +fs_relabel check_file_context grim_reaper check_mount_context create_file > + > +LDLIBS += -lselinux > + > +ifneq (,$(findstring -DHAVE_FS_WATCH_PERM,$(CFLAGS))) > + TARGETS += fanotify_fs > +endif > + > +all: $(TARGETS) > + > +clean: > + rm -f $(TARGETS) > diff --git a/tests/filesystem/check_file_context.c b/tests/filesystem/check_file_context.c > new file mode 100644 > index 0000000..1380f16 > --- /dev/null > +++ b/tests/filesystem/check_file_context.c > @@ -0,0 +1,75 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <stdbool.h> > +#include <linux/unistd.h> > +#include <selinux/selinux.h> > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s [-v] -f -e -n\n" > + "Where:\n\t" > + "-f File to check its context\n\t" > + "-e Expected context\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +int main(int argc, char **argv) > +{ > + int opt, result, fd; > + char *context = NULL, *expected = NULL, *file = NULL; > + bool verbose = false; > + > + while ((opt = getopt(argc, argv, "f:e:v")) != -1) { > + switch (opt) { > + case 'f': > + file = optarg; > + break; > + case 'e': > + expected = optarg; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!file || !expected) > + print_usage(argv[0]); > + > + fd = open(file, O_RDWR); > + if (fd < 0) { > + fprintf(stderr, "open(2) Failed: %s\n", strerror(errno)); > + return -1; > + } > + > + result = fgetfilecon(fd, &context); > + if (result < 0) { > + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", > + strerror(errno)); > + result = -1; > + goto err; > + } > + result = 0; > + > + if (strcmp(expected, context)) { > + fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n", > + expected, context); > + result = -1; > + } else { > + if (verbose) > + printf("Pass - File contexts match: %s\n", context); > + } > +err: > + free(context); > + close(fd); > + > + return result; > +} > diff --git a/tests/filesystem/check_mount_context.c b/tests/filesystem/check_mount_context.c > new file mode 100644 > index 0000000..dbe0fb8 > --- /dev/null > +++ b/tests/filesystem/check_mount_context.c > @@ -0,0 +1,109 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <stdbool.h> > +#include <linux/unistd.h> > +#include <selinux/selinux.h> > +#include <selinux/context.h> > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s [-v] -m [-e] -r\n" > + "Where:\n\t" > + "-m Mountpoint\n\t" > + "-e Expected MP context\n\t" > + "-r Reset MP context to 'unlabeled_t'\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +int main(int argc, char **argv) > +{ > + int opt, result, save_err; > + char *context = NULL, *expected = NULL, *mount = NULL, *newcon = NULL; > + bool verbose = false, reset = false; > + const char *type = "unlabeled_t"; > + context_t con_t; > + > + while ((opt = getopt(argc, argv, "m:e:rv")) != -1) { > + switch (opt) { > + case 'm': > + mount = optarg; > + break; > + case 'e': > + expected = optarg; > + break; > + case 'r': > + reset = true; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!mount) > + print_usage(argv[0]); > + > + result = getfilecon(mount, &context); > + if (result < 0) { > + fprintf(stderr, "getfilecon(3) Failed: %s\n", strerror(errno)); > + result = -1; > + goto err; > + } > + if (verbose) > + printf("Current MP context: %s\n", context); > + > + result = 0; > + > + if (reset) { > + /* Set context to unlabeled_t */ > + con_t = context_new(context); > + if (!con_t) { > + fprintf(stderr, "Unable to create context structure\n"); > + exit(-1); > + } > + > + if (context_type_set(con_t, type)) { > + fprintf(stderr, "Unable to set new type\n"); > + exit(-1); > + } > + > + newcon = context_str(con_t); > + if (!newcon) { > + fprintf(stderr, "Unable to obtain new context string\n"); > + exit(-1); > + } > + > + result = setfilecon(mount, newcon); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "setfilecon(3) Failed: %s\n", > + strerror(errno)); > + result = save_err; > + goto err; > + } > + if (verbose) > + printf("Set new MP context: %s\n", newcon); > + } else { > + if (strcmp(expected, context)) { > + fprintf(stderr, "Mount context error, expected:\n\t%s\ngot:\n\t%s\n", > + expected, context); > + result = -1; > + } else { > + if (verbose) > + printf("Pass - Mountpoint contexts match: %s\n", > + context); > + } > + } > + > +err: > + free(context); > + return result; > +} > diff --git a/tests/filesystem/create_file.c b/tests/filesystem/create_file.c > new file mode 100644 > index 0000000..3d73067 > --- /dev/null > +++ b/tests/filesystem/create_file.c > @@ -0,0 +1,79 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <stdbool.h> > +#include <sys/types.h> > +#include <linux/unistd.h> > +#include <selinux/selinux.h> > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s [-v] -f\n" > + "Where:\n\t" > + "-f File to create\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +int main(int argc, char **argv) > +{ > + int opt, result, fd, save_err; > + char *context, *file = NULL; > + bool verbose = false; > + > + while ((opt = getopt(argc, argv, "f:v")) != -1) { > + switch (opt) { > + case 'f': > + file = optarg; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!file) > + print_usage(argv[0]); > + > + if (verbose) { > + result = getcon(&context); > + if (result < 0) { > + fprintf(stderr, "Failed to obtain process context\n"); > + exit(-1); > + } > + printf("Process context:\n\t%s\n", context); > + free(context); > + } > + > + fd = creat(file, O_RDWR); > + save_err = errno; > + if (fd < 0) { > + fprintf(stderr, "creat(2) Failed: %s\n", strerror(errno)); > + return save_err; > + } > + > + context = NULL; > + result = fgetfilecon(fd, &context); > + if (result < 0) { > + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", > + strerror(errno)); > + result = -1; > + goto err; > + } > + result = 0; > + > + if (verbose) > + printf("File context is: %s\n", context); > + > +err: > + free(context); > + close(fd); > + > + return result; > +} > diff --git a/tests/filesystem/create_file_change_context.c b/tests/filesystem/create_file_change_context.c > new file mode 100644 > index 0000000..2a3b995 > --- /dev/null > +++ b/tests/filesystem/create_file_change_context.c > @@ -0,0 +1,143 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <stdbool.h> > +#include <linux/unistd.h> > +#include <selinux/selinux.h> > +#include <selinux/context.h> > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s [-v] -t -f\n" > + "Where:\n\t" > + "-t Type for context of created file\n\t" > + "-f File to create\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +int main(int argc, char **argv) > +{ > + int opt, result, fd, save_err; > + char *context, *newfcon, *orgfcon, *type = NULL, *file = NULL; > + bool verbose = false; > + context_t con_t; > + > + while ((opt = getopt(argc, argv, "t:f:v")) != -1) { > + switch (opt) { > + case 't': > + type = optarg; > + break; > + case 'f': > + file = optarg; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!type || !file) > + print_usage(argv[0]); > + > + result = getcon(&context); > + if (result < 0) { > + fprintf(stderr, "Failed to obtain process context\n"); > + exit(-1); > + } > + > + /* Build new file context */ > + con_t = context_new(context); > + if (!con_t) { > + fprintf(stderr, "Unable to create context structure\n"); > + exit(-1); > + } > + > + if (context_type_set(con_t, type)) { > + fprintf(stderr, "Unable to set new type\n"); > + exit(-1); > + } > + > + newfcon = context_str(con_t); > + if (!newfcon) { > + fprintf(stderr, "Unable to obtain new context string\n"); > + exit(-1); > + } > + > + if (verbose) { > + printf("Process context:\n\t%s\n", context); > + printf("is creating test file:\n\t%s\n", file); > + printf("and changing its context to:\n\t%s\n", newfcon); > + } > + > + free(context); > + context = NULL; > + > + /* hooks.c may_create() FILESYSTEM__ASSOCIATE */ > + fd = creat(file, O_RDWR); > + save_err = errno; > + if (fd < 0) { > + fprintf(stderr, "creat(2) Failed: %s\n", strerror(errno)); > + result = save_err; > + goto err; > + } > + > + result = fgetfilecon(fd, &orgfcon); > + if (result < 0) { > + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", > + strerror(errno)); > + result = -1; > + goto err; > + } > + > + if (verbose) > + printf("Current test file context is: %s\n", orgfcon); > + > + free(orgfcon); > + > + /* hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE */ > + result = fsetfilecon(fd, newfcon); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "fsetfilecon(3) Failed: %s\n", > + strerror(errno)); > + result = save_err; > + goto err; > + } > + > + fd = open(file, O_RDWR); > + if (fd < 0) { > + fprintf(stderr, "open(2) Failed: %s\n", strerror(errno)); > + result = -1; > + } > + > + result = fgetfilecon(fd, &context); > + if (result < 0) { > + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", > + strerror(errno)); > + result = -1; > + goto err; > + } > + > + if (verbose) > + printf("New test file context is: %s\n", context); > + > + result = 0; > + if (strcmp(newfcon, context)) { > + fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n", > + newfcon, context); > + result = -1; > + } > +err: > + free(context); > + free(newfcon); > + close(fd); > + > + return result; > +} > diff --git a/tests/filesystem/fanotify_fs.c b/tests/filesystem/fanotify_fs.c > new file mode 100644 > index 0000000..1f8f165 > --- /dev/null > +++ b/tests/filesystem/fanotify_fs.c > @@ -0,0 +1,79 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <fcntl.h> > +#include <errno.h> > +#include <stdbool.h> > +#include <sys/fanotify.h> > +#include <selinux/selinux.h> > + > +#ifndef FAN_MARK_FILESYSTEM > +#define FAN_MARK_FILESYSTEM 0x00000100 > +#endif > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s [-v] -t\n" > + "Where:\n\t" > + "-t Target path\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +int main(int argc, char *argv[]) > +{ > + int mask = FAN_OPEN, flags = FAN_MARK_ADD | FAN_MARK_FILESYSTEM; > + int fd, result, opt, save_err; > + char *context, *tgt = NULL; > + bool verbose = false; > + > + while ((opt = getopt(argc, argv, "t:v")) != -1) { > + switch (opt) { > + case 't': > + tgt = optarg; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!tgt) > + print_usage(argv[0]); > + > + if (verbose) { > + result = getcon(&context); > + if (result < 0) { > + fprintf(stderr, "Failed to obtain process context\n"); > + exit(-1); > + } > + printf("Process context:\n\t%s\n", context); > + free(context); > + } > + > + fd = fanotify_init(FAN_CLASS_CONTENT, O_RDWR); > + if (fd < 0) { > + fprintf(stderr, "fanotify_init(2) Failed: %s\n", > + strerror(errno)); > + exit(-1); > + } > + > + result = fanotify_mark(fd, flags, mask, AT_FDCWD, tgt); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "fanotify_mark(2) Failed: %s\n", > + strerror(errno)); > + close(fd); > + return save_err; > + } > + > + if (verbose) > + printf("Set fanotify_mark(2) on filesystem: %s\n", tgt); > + > + close(fd); > + return 0; > +} > diff --git a/tests/filesystem/fs_relabel.c b/tests/filesystem/fs_relabel.c > new file mode 100644 > index 0000000..25b1781 > --- /dev/null > +++ b/tests/filesystem/fs_relabel.c > @@ -0,0 +1,72 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <fcntl.h> > +#include <stdbool.h> > +#include <linux/unistd.h> > +#include <selinux/selinux.h> > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s [-v] -n\n" > + "Where:\n\t" > + "-n New fs context\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +int main(int argc, char **argv) > +{ > + int opt, result, save_err; > + char *context, *fscreate_con, *newcon = NULL; > + bool verbose = false; > + > + while ((opt = getopt(argc, argv, "n:v")) != -1) { > + switch (opt) { > + case 'n': > + newcon = optarg; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!newcon) > + print_usage(argv[0]); > + > + if (verbose) { > + result = getcon(&context); > + if (result < 0) { > + fprintf(stderr, "Failed to obtain process context\n"); > + exit(-1); > + } > + printf("Process context:\n\t%s\n", context); > + free(context); > + } > + > + result = setfscreatecon(newcon); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "Failed setfscreatecon(3): %s\n", > + strerror(errno)); > + return save_err; > + } > + > + result = getfscreatecon(&fscreate_con); > + if (result < 0) { > + fprintf(stderr, "Failed getfscreatecon(3): %s\n", > + strerror(errno)); > + exit(-1); > + } > + if (verbose) > + printf("New fscreate context: %s\n", fscreate_con); > + > + free(fscreate_con); > + return 0; > +} > diff --git a/tests/filesystem/grim_reaper.c b/tests/filesystem/grim_reaper.c > new file mode 100644 > index 0000000..0105ab6 > --- /dev/null > +++ b/tests/filesystem/grim_reaper.c > @@ -0,0 +1,63 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <stdbool.h> > +#include <sys/mount.h> > +#include <selinux/selinux.h> > + > +#define WAIT_COUNT 60 > +#define USLEEP_TIME 10000 > + > +/* Remove any mounts associated with the loop device in argv[1] */ > +int main(int argc, char *argv[]) > +{ > + FILE *fp; > + size_t len; > + ssize_t num; > + int index = 0, i, result = 0; > + char *mount_info[2]; > + char *buf = NULL, *item; > + > + if (!argv[1]) > + return -1; > + > + fp = fopen("/proc/mounts", "re"); > + if (!fp) { > + fprintf(stderr, "Failed to open /proc/mounts: %s\n", > + strerror(errno)); > + return -1; > + } > + > + while ((num = getline(&buf, &len, fp)) != -1) { > + index = 0; > + item = strtok(buf, " "); > + while (item != NULL) { > + mount_info[index] = item; > + index++; > + if (index == 2) > + break; > + item = strtok(NULL, " "); > + } > + > + if (strcmp(mount_info[0], argv[1]) == 0) { > + for (i = 0; i < WAIT_COUNT; i++) { > + result = umount(mount_info[1]); > + if (!result) > + break; > + > + if (errno != EBUSY) { > + fprintf(stderr, "Failed umount(2): %s\n", > + strerror(errno)); > + break; > + } > + usleep(USLEEP_TIME); > + } > + } > + } > + > + free(buf); > + fclose(fp); > + return result; > +} > diff --git a/tests/filesystem/mount.c b/tests/filesystem/mount.c > new file mode 100644 > index 0000000..034f0ec > --- /dev/null > +++ b/tests/filesystem/mount.c > @@ -0,0 +1,130 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <stdbool.h> > +#include <sys/mount.h> > +#include <selinux/selinux.h> > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s [-s src] -t tgt [-f fs_type] [-o options] [-bmprv]\n" > + "Where:\n\t" > + "-s Source path\n\t" > + "-t Target path\n\t" > + "-f Filesystem type\n\t" > + "-o Options list (comma separated list)\n\t" > + "Zero or one of the following flags:\n\t" > + "\t-b MS_BIND\n\t" > + "\t-m MS_MOVE\n\t" > + "\t-p MS_PRIVATE\n\t" > + "\t-r MS_REMOUNT\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +static int ck_mount(char *mntpoint) > +{ > + int result = 0; > + FILE *fp; > + size_t len; > + ssize_t num; > + char *buf = NULL; > + > + fp = fopen("/proc/mounts", "re"); > + if (fp == NULL) { > + fprintf(stderr, "Failed to open /proc/mounts: %s\n", > + strerror(errno)); > + return -1; > + } > + > + while ((num = getline(&buf, &len, fp)) != -1) { > + if (strstr(buf, mntpoint) != NULL) { > + result = 1; > + break; > + } > + } > + > + free(buf); > + fclose(fp); > + return result; > +} > + > +int main(int argc, char *argv[]) > +{ > + int opt, result, save_err, flags = 0; > + char *context, *src = NULL, *tgt = NULL, *fs_type = NULL, *opts = NULL; > + bool verbose = false; > + > + while ((opt = getopt(argc, argv, "s:t:f:o:pbmrv")) != -1) { > + switch (opt) { > + case 's': > + src = optarg; > + break; > + case 't': > + tgt = optarg; > + break; > + case 'f': > + fs_type = optarg; > + break; > + case 'o': > + opts = optarg; > + break; > + case 'b': > + flags = MS_BIND; > + break; > + case 'p': > + flags = MS_PRIVATE; > + break; > + case 'm': > + flags = MS_MOVE; > + break; > + case 'r': > + flags = MS_REMOUNT; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!tgt) > + print_usage(argv[0]); > + > + if (verbose) { > + result = getcon(&context); > + if (result < 0) { > + fprintf(stderr, "Failed to obtain process context\n"); > + return -1; > + } > + printf("Process context:\n\t%s\n", context); > + free(context); > + } > + > + if (verbose) > + printf("Mounting\n\tsrc: %s\n\ttgt: %s\n\tfs_type: %s flags: 0x%x\n\topts: %s\n", > + src, tgt, fs_type, flags, opts); > + > + result = mount(src, tgt, fs_type, flags, opts); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "Failed mount(2): %s\n", strerror(errno)); > + return save_err; > + } > + > + if (flags == MS_MOVE) { > + if (!ck_mount(src) && ck_mount(tgt)) { > + if (verbose) > + printf("MS_MOVE: Moved mountpoint\n"); > + } else { > + fprintf(stderr, "MS_MOVE: Move mountpoint failed\n"); > + return -1; > + } > + } > + > + return 0; > +} > diff --git a/tests/filesystem/quotas_test.c b/tests/filesystem/quotas_test.c > new file mode 100644 > index 0000000..34aaca9 > --- /dev/null > +++ b/tests/filesystem/quotas_test.c > @@ -0,0 +1,134 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <stdbool.h> > +#include <sys/quota.h> > +#include <selinux/selinux.h> > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s -s src -t tgt\n" > + "Where:\n\t" > + "-s Source path (e.g. /dev/loop0)\n\t" > + "-t Target quota file (Full path with either 'aquota.user'\n\t" > + " or 'aquota.group' appended)\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +int main(int argc, char *argv[]) > +{ > + int opt, result, qcmd, save_err, test_id = geteuid(); > + char *context, *src = NULL, *tgt = NULL; > + bool verbose = false; > + char fmt_buf[2]; > + > + while ((opt = getopt(argc, argv, "s:t:v")) != -1) { > + switch (opt) { > + case 's': > + src = optarg; > + break; > + case 't': > + tgt = optarg; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!src || !tgt) > + print_usage(argv[0]); > + > + if (verbose) { > + result = getcon(&context); > + if (result < 0) { > + fprintf(stderr, "Failed to obtain process context\n"); > + return -1; > + } > + printf("Process context:\n\t%s\n", context); > + free(context); > + } > + > + if (strstr(tgt, "aquota.user") != NULL) { > + qcmd = QCMD(Q_QUOTAON, USRQUOTA); > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_QUOTAON, USRQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("User Quota - ON\n"); > + > + qcmd = QCMD(Q_GETFMT, USRQUOTA); > + result = quotactl(qcmd, src, test_id, fmt_buf); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_GETFMT, USRQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("User Format: 0x%x\n", fmt_buf[0]); > + > + qcmd = QCMD(Q_QUOTAOFF, USRQUOTA); > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_QUOTAOFF, USRQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("User Quota - OFF\n"); > + > + return 0; > + > + } else if (strstr(tgt, "aquota.group") != NULL) { > + qcmd = QCMD(Q_QUOTAON, GRPQUOTA); > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_QUOTAON, GRPQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("Group Quota - ON\n"); > + > + qcmd = QCMD(Q_GETFMT, GRPQUOTA); > + result = quotactl(qcmd, src, test_id, fmt_buf); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_GETFMT, GRPQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("Group Format: 0x%x\n", fmt_buf[0]); > + > + qcmd = QCMD(Q_QUOTAOFF, GRPQUOTA); > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "quotactl(Q_QUOTAOFF, GRPQUOTA) Failed: %s\n", > + strerror(errno)); > + return save_err; > + } > + if (verbose) > + printf("Group Quota - OFF\n"); > + > + return 0; > + } > + > + fprintf(stderr, "Required %s to specify 'aquota.user' or 'aquota.group' file\n", > + tgt); > + return -1; > +} > diff --git a/tests/filesystem/statfs_test.c b/tests/filesystem/statfs_test.c > new file mode 100644 > index 0000000..5de49b1 > --- /dev/null > +++ b/tests/filesystem/statfs_test.c > @@ -0,0 +1,65 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <stdbool.h> > +#include <sys/statfs.h> > +#include <selinux/selinux.h> > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s [-v] -t\n" > + "Where:\n\t" > + "-t Target path\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +int main(int argc, char *argv[]) > +{ > + int opt, result, save_err; > + char *context, *tgt = NULL; > + bool verbose = false; > + struct statfs statfs_t; > + > + while ((opt = getopt(argc, argv, "t:v")) != -1) { > + switch (opt) { > + case 't': > + tgt = optarg; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!tgt) > + print_usage(argv[0]); > + > + if (verbose) { > + result = getcon(&context); > + if (result < 0) { > + fprintf(stderr, "Failed to obtain process context\n"); > + return -1; > + } > + printf("Process context:\n\t%s\n", context); > + free(context); > + } > + > + result = statfs(tgt, &statfs_t); > + save_err = errno; > + if (result < 0) { > + fprintf(stderr, "statfs(2) Failed: %s\n", strerror(errno)); > + return save_err; > + } > + > + if (verbose) > + printf("statfs(2) returned magic filesystem: 0x%lx\n", > + statfs_t.f_type); > + > + return 0; > +} > diff --git a/tests/filesystem/test b/tests/filesystem/test > new file mode 100755 > index 0000000..00c69e1 > --- /dev/null > +++ b/tests/filesystem/test > @@ -0,0 +1,830 @@ > +#!/usr/bin/perl > +use Test::More; > + > +BEGIN { > + $basedir = $0; > + $basedir =~ s|(.*)/[^/]*|$1|; > + > + $test_count = 63; > + > + # Allow info to be shown. > + $v = $ARGV[0]; > + if ($v) { > + if ( $v ne "-v" ) { > + plan skip_all => "Invalid option (use -v)"; > + } > + } > + else { > + $v = " "; > + } > + > + # From kernel 5.5 support for fanotify(7) with filesystem { watch } > + $kvercur = `uname -r`; > + chomp($kvercur); > + $kverminstream = "5.5"; > + > + $result = `$basedir/../kvercmp $kvercur $kverminstream`; > + if ( $result > 0 && -e "$basedir/fanotify_fs" ) { > + $test_watch = 1; > + $test_count += 4; > + } > + > + plan tests => $test_count; > +} > + > +# mount(2) MS_BIND | MS_PRIVATE requires an absolute path to a private mount > +# point before MS_MOVE > +$cwd = `pwd 2>/dev/null`; > +chomp($cwd); > +$private_path = "$cwd"; > +if ( $basedir eq "." ) { > + $private_path = "$cwd/mntpoint"; > +} > +else { > + $private_path = "$cwd/$basedir/mntpoint"; > +} > + > +# Set initial filesystem type > +$fs_type = "ext4"; > + > +# For list of devices used > +$device_count = 0; > + > +sub get_loop_dev { > + print "Finding free /dev/loop entry\n"; > + $dev = `losetup -f 2>/dev/null`; > + chomp($dev); > + if ( $dev eq "" ) { > + print "losetup failed to obtain /dev/loop entry\n"; > + cleanup(); > + exit -1; > + } > + > + # Keep list of devices for cleanup later > + if ( $device_count eq 0 ) { > + $device_list[$device_count] = $dev; > + $device_count += 1; > + } > + elsif ( $dev ne $device_list[ $device_count - 1 ] ) { > + $device_list[$device_count] = $dev; > + $device_count += 1; > + } > +} > + > +sub attach_dev { > + print "Attaching $basedir/fstest to $dev\n"; > + $result = system("losetup $dev $basedir/fstest 2>/dev/null"); > + if ( $result != 0 ) { > + print "Failed to attach $basedir/fstest to $dev\n"; > + cleanup(); > + exit -1; > + } > +} > + > +sub make_fs { > + my ($mk_type) = @_; > + > + get_loop_dev(); > + > + if ( $mk_type eq "tmpfs" ) { > + return; > + } > + > + print "Create $basedir/fstest with dd\n"; > + $result = system( > + "dd if=/dev/zero of=$basedir/fstest bs=1024 count=10240 2>/dev/null"); > + if ( $result != 0 ) { > + print "dd failed to create fstest\n"; > + exit -1; > + } > + > + attach_dev(); > + > + print "Make $mk_type filesystem on $dev\n"; > + $result = system("mkfs.$mk_type $dev >& /dev/null"); > + if ( $result != 0 ) { > + system("losetup -d $dev 2>/dev/null"); > + cleanup(); > + print "mkfs.$mk_type failed to create filesystem on $dev\n"; > + exit -1; > + } > +} > + > +sub mk_mntpoint_1 { > + system("rm -rf $private_path/mp1 2>/dev/null"); > + system("mkdir -p $private_path/mp1 2>/dev/null"); > +} > + > +sub mk_mntpoint_2 { > + system("rm -rf $private_path/mp2 2>/dev/null"); > + system("mkdir -p $private_path/mp2 2>/dev/null"); > +} > + > +sub cleanup { > + system("rm -rf $basedir/fstest 2>/dev/null"); > + system("rm -rf $basedir/mntpoint 2>/dev/null"); > +} > + > +sub cleanup1 { > + system("losetup -d $dev 2>/dev/null"); > + system("rm -rf $basedir/fstest 2>/dev/null"); > + system("rm -rf $basedir/mntpoint 2>/dev/null"); > +} > + > +############### Test setfscreatecon(3) ########################## > +print "Test setfscreatecon(3)\n"; > +$result = system > +"runcon -t test_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0"; > +ok( $result eq 0 ); > + > +$result = system > +"runcon -t test_no_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0 2>&1"; > +ok( $result >> 8 eq 13 ); > + > +############### Test Basic Mount/Unmount ########################## > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > +$mount_opts1 = > + "quota,usrquota,grpquota,defcontext=system_u:object_r:test_filesystem_t:s0"; > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$mount_opts1\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v" > +); > +ok( $result eq 0 ); > + > +print "Then remount\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/mount -r -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v" > +); > +ok( $result eq 0 ); > + > +print "Running quotacheck(8) to init user/group quota files\n"; > +$result = system("quotacheck -ugF vfsv0 $private_path/mp1"); > +ok( $result eq 0 ); > + > +print "Toggle User & Group quotas on/off\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v" > +); > +ok( $result eq 0 ); > +$result = system( > +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.group $v" > +); > +ok( $result eq 0 ); > + > +print "Get statfs(2)\n"; > +$result = > + system( > + "runcon -t test_filesystem_t $basedir/statfs_test -t $basedir/mntpoint $v"); > +ok( $result eq 0 ); > + > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v" > + ); > +ok( $result eq 0 ); > + > +if ($test_watch) { > + print "fanotify(7) test\n"; > + $result = system( > +"runcon -t test_filesystem_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1" > + ); > + ok( $result eq 0 ); > +} > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp1 $v"); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Test Move Mount ########################## > +make_fs($fs_type); > +$mount_opts2 = > + "quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_t:s0"; > +system("mkdir -p $private_path 2>/dev/null"); > + > +print "Set mount MS_BIND on filesystem\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/mount -s $private_path -t $private_path -b $v" > +); > +ok( $result eq 0 ); > + > +print "Set mount MS_PRIVATE on filesystem\n"; > +$result = > + system("runcon -t test_filesystem_t $basedir/mount -t $private_path -p $v"); > +ok( $result eq 0 ); > + > +mk_mntpoint_1(); > +mk_mntpoint_2(); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$mount_opts2\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts2 $v" > +); > +ok( $result eq 0 ); > + > +print "Set mount MS_MOVE on filesystem\n"; > +$result = system( > +"runcon -t test_filesystem_t $basedir/mount -s $private_path/mp1 -t $private_path/mp2 -m $v" > +); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp2\n"; > +$result = > + system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp2 $v"); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint\n"; > +$result = > + system("runcon -t test_filesystem_t $basedir/umount -t $private_path $v"); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { relabelfrom } ########################## > +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM > + > +$opts_no_relabelfrom = > +"defcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0,fscontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_relabelfrom\n"; > +$result = system( > +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { relabelto } ########################## > +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO > + > +$opts_no_relabelto = > + "fscontext=system_u:object_r:test_filesystem_no_relabelto_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_relabelto\n"; > +$result = system( > +"runcon -t test_filesystem_no_relabelto_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelto $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { relabelfrom } ########################## > +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM > + > +$opts_no_relabelfrom = > + "rootcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_relabelfrom\n"; > +$result = system( > +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { associate } ########################## > +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE > + > +$opts_no_associate = > +"defcontext=system_u:object_r:test_filesystem_no_associate_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_associate\n"; > +$result = system( > +"runcon -t test_filesystem_no_associate_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { associate } ########################## > +# hooks.c may_create() FILESYSTEM__ASSOCIATE > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > +$opts_no_associate_file = > + "fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0"; > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_associate_file\n"; > +$result = system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v" > +); > +ok( $result eq 0 ); > + > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1" > + ); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { quotamod } ########################## > +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD > + > +$opts_no_quotamod = > +"quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesystem_no_quotamod_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > +system("mkdir -p $private_path 2>/dev/null"); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_quotamod\n"; > +$result = system( > +"runcon -t test_filesystem_no_quotamod_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotamod $v 2>&1" > +); > +ok( $result eq 0 ); > + > +# No need to run quotacheck(8) as never gets far enough to read quota file > +print "Toggle User & Group quotas on/off\n"; # Must have full path > +$result = system( > +"runcon -t test_filesystem_no_quotamod_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_no_quotamod_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { quotaget } ########################## > +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET > + > +$opts_no_quotaget = > +"quota,usrquota,grpquota,context=system_u:object_r:test_filesystem_no_quotaget_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_quotaget\n"; > +$result = system( > +"runcon -t test_filesystem_no_quotaget_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotaget $v" > +); > +ok( $result eq 0 ); > + > +print "Running quotacheck(8) to init user/group quota files\n"; > +$result = system("quotacheck -ugF vfsv0 $private_path/mp1"); > +ok( $result eq 0 ); > + > +print "Toggle User & Group quotas on/off\n"; # Must have full path > +$result = system( > +"runcon -t test_filesystem_no_quotaget_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_no_quotaget_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { mount } ########################## > +# hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT > + > +$opts_no_mount = "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_mount\n"; > +$result = system( > +"runcon -t test_filesystem_no_mount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_mount $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { getattr } ########################## > +# hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR > + > +$opts_no_getattr = > + "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_getattr\n"; > +$result = system( > +"runcon -t test_filesystem_no_getattr_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_getattr $v" > +); > +ok( $result eq 0 ); > + > +$result = system( > +"runcon -t test_filesystem_no_getattr_t $basedir/statfs_test -t $basedir/mntpoint $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_no_getattr_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { remount } ########################## > +# hooks.c selinux_mount() FILESYSTEM__REMOUNT > + > +$opts_no_remount = > + "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_remount\n"; > +$result = system( > +"runcon -t test_filesystem_no_remount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v" > +); > +ok( $result eq 0 ); > + > +print "Then remount\n"; > +$result = system( > +"runcon -t test_filesystem_no_remount_t $basedir/mount -r -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_no_remount_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { unmount } ########################## > +# hooks.c selinux_umount() FILESYSTEM__UNMOUNT > + > +$opts_no_unmount = > + "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0"; > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_unmount\n"; > +$result = system( > +"runcon -t test_filesystem_no_unmount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_unmount $v" > +); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_no_unmount_t $basedir/umount -t $basedir/mntpoint/mp1 $v 2>&1" > +); > +ok( $result >> 8 eq 13 ); > + > +# Make sure it does get unmounted > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > + "runcon -t test_filesystem_t $basedir/umount -t $basedir/mntpoint/mp1 $v"); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { associate } ########################## > +# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > +$opts_no_associate_file = > +"defcontext=system_u:object_r:test_filesystem_no_associate_file_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0"; > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$opts_no_associate_file\n"; > +$result = system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v" > +); > +ok( $result eq 0 ); > + > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1" > + ); > +ok( $result >> 8 eq 13 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +############### Deny filesystem { watch } ########################## > +# hooks.c selinux_path_notify() FILESYSTEM__WATCH > +if ($test_watch) { > + cleanup(); > + mk_mntpoint_1(); > + make_fs($fs_type); > + $opts_no_watch = "context=system_u:object_r:test_filesystem_no_watch_t:s0"; > + > + print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > + print "Using mount options:\n\t$opts_no_watch\n"; > + $result = system( > +"runcon -t test_filesystem_no_watch_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_watch $v" > + ); > + ok( $result eq 0 ); > + > + print "test_fanotify\n"; > + $result = system( > +"runcon -t test_filesystem_no_watch_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1 2>&1" > + ); > + ok( $result >> 8 eq 13 ); > + > + print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > + $result = system( > +"runcon -t test_filesystem_no_watch_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > + ok( $result eq 0 ); > + > + print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > + cleanup1(); > +} > + > +########################################################################## > +# context - Useful when mounting filesystems that do not support extended > +# attributes. > +# Tested by - Creating a filesystem that has xattrs set to a different value, > +# then mount with context= and confirm that the files have that > +# context as well as any newly created files (even if fscreate > +# was set to something else), and that setfilecon/setxattr() on > +# files within the mount fails with errno EOPNOTSUPP. > +########################################################################## > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +# Mount with xttrs to create a file with specific context. > +$context1_opts = "defcontext=system_u:object_r:test_filesystem_context_t:s0"; > + > +print "Testing 'context=' mount option\n"; > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$context1_opts\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context1_opts $v" > +); > +ok( $result eq 0 ); > + > +# Create file with 'test_filesystem_filecon_t' context > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v" > + ); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +# Need to free the loop device, then get new dev one and attach > +system("losetup -d $dev 2>/dev/null"); > +get_loop_dev(); > +attach_dev(); > + > +# Mount again with no xttr support > +$context2_opts = "context=system_u:object_r:test_filesystem_context_t:s0"; > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$context2_opts\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context2_opts $v" > +); > +ok( $result eq 0 ); > + > +# Now check the context on file is system_u:object_r:test_filesystem_context_t:s0 > +print "Check test file context $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/check_file_context -f $private_path/mp1/test_file -e system_u:object_r:test_filesystem_context_t:s0 $v" > + ); > +ok( $result eq 0 ); > + > +# Then create a file with 'test_filesystem_filecon_t' context, this should fail with EOPNOTSUPP > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v 2>/dev/null" > + ); > +ok( $result >> 8 eq 95 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +########################################################################## > +# rootcontext - Explicitly label the root inode of the filesystem being > +# mounted before that filesystem or inode becomes visible > +# to userspace. > +# Tested by - Set mountpoint to unlabeled_t and then check that the > +# context of the root directory matches rootcontext= after > +# the mount operation. > +########################################################################## > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > +$root_opts = "rootcontext=system_u:object_r:test_filesystem_context_t:s0"; > + > +print "Testing 'rootcontext=' mount option\n"; > + > +# Reset mountpoint to 'unlabeled_t' so it is different to any other possible test values. > +print "Resetting MP to unlabeled_t $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/check_mount_context -r -m $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$root_opts\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $root_opts $v" > +); > +ok( $result eq 0 ); > + > +# Now check the mountpoint is the 'rootcontext=' value > +print "Check MP context $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/check_mount_context -m $basedir/mntpoint/mp1 -e system_u:object_r:test_filesystem_context_t:s0 $v" > + ); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +########################################################################## > +# defcontext - Set default security context for unlabeled files. > +# This overrides the value set for unlabeled files in policy > +# and requires a filesystem that supports xattr labeling. > +# Tested by - Create filesystem that has files w/o xattrs and then confirm > +# that they are mapped to the specified defcontext upon mount, > +# where defcontext differs from the policy default. > +########################################################################## > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > + > +$test_opts = "context=system_u:object_r:test_filesystem_context_t:s0"; > + > +print "Testing 'defcontext=' mount option\n"; > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$test_opts\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $test_opts $v" > +); > +ok( $result eq 0 ); > + > +# Create file, its context will be system_u:object_r:test_filesystem_context_t:s0 from $test_opts > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -u system_u -t test_filesystem_fscontext_t $basedir/create_file -f $basedir/mntpoint/mp1/test_file $v" > + ); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > +); > +ok( $result eq 0 ); > + > +# Need to free the loop device, then get new dev one and attach > +system("losetup -d $dev 2>/dev/null"); > +get_loop_dev(); > +attach_dev(); > + > +# Mount again with defcontext= > +$defcontext_opts = "defcontext=system_u:object_r:test_filesystem_filecon_t:s0"; > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$defcontext_opts\n"; > +$result = system( > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $defcontext_opts $v" > +); > +ok( $result eq 0 ); > + > +# Now check the file context is now system_u:object_r:test_filesystem_filecon_t:s0 > +print "Check test file context $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/check_file_context -f $basedir/mntpoint/mp1/test_file -e system_u:object_r:test_filesystem_filecon_t:s0 $v" > + ); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +########################################################################## > +# fscontext - Sets the overarching filesystem label to a specific security > +# context. This filesystem label is separate from the individual > +# labels on the files. > +# Tested by - Mount a tmpfs (fs_use_trans) filesystem with fscontext= and > +# then create a file within it, checking its context. > +########################################################################## > +$fs_type = "tmpfs"; > +cleanup(); > +mk_mntpoint_1(); > +make_fs($fs_type); > +$fscontext_opts = > +"fscontext=system_u:object_r:test_filesystem_fscontext_t:s0,size=10M,mode=0770"; > + > +print "Testing 'fscontext=' mount option\n"; > +print "Mount tmpfs filesystem on $basedir/mntpoint/mp1\n"; > +print "Using mount options:\n\t$fscontext_opts\n"; > +$result = system( > +"runcon -t test_filesystem_fscontext_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $fscontext_opts $v" > +); > +ok( $result eq 0 ); > + > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > +$result = > + system( > +"runcon -t test_filesystem_fscontext_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v" > + ); > +ok( $result eq 0 ); > + > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > +$result = > + system( > +"runcon -t test_filesystem_fscontext_t $basedir/umount -t $basedir/mntpoint/mp1 $v" > + ); > +ok( $result eq 0 ); > + > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > +cleanup1(); > + > +# Cleanup any attached /dev/loop entries > +foreach my $n (@device_list) { > + system("$basedir/grim_reaper $n 2>/dev/null"); > +} > + > +exit; > diff --git a/tests/filesystem/umount.c b/tests/filesystem/umount.c > new file mode 100644 > index 0000000..4a20448 > --- /dev/null > +++ b/tests/filesystem/umount.c > @@ -0,0 +1,84 @@ > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#include <errno.h> > +#include <stdbool.h> > +#include <sys/mount.h> > +#include <selinux/selinux.h> > + > +static void print_usage(char *progname) > +{ > + fprintf(stderr, > + "usage: %s [-v] [-t]\n" > + "Where:\n\t" > + "-t Target path\n\t" > + "-v Print information.\n", progname); > + exit(-1); > +} > + > +#define WAIT_COUNT 60 > +#define USLEEP_TIME 100000 > + > +int main(int argc, char *argv[]) > +{ > + char *context, *tgt = NULL; > + int opt, result, i, save_err; > + bool verbose = false; > + > + while ((opt = getopt(argc, argv, "t:v")) != -1) { > + switch (opt) { > + case 't': > + tgt = optarg; > + break; > + case 'v': > + verbose = true; > + break; > + default: > + print_usage(argv[0]); > + } > + } > + > + if (!tgt) > + print_usage(argv[0]); > + > + if (verbose) { > + result = getcon(&context); > + if (result < 0) { > + fprintf(stderr, "Failed to obtain process context\n"); > + exit(-1); > + } > + printf("Process context:\n\t%s\n", context); > + free(context); > + } > + > + /* > + * umount(2) will sometimes return EBUSY when other tasks are > + * checking mounts so wait around before bailing out. > + */ > + for (i = 0; i < WAIT_COUNT; i++) { > + result = umount(tgt); > + save_err = errno; > + if (!result) { > + if (verbose) > + printf("Unmounted: %s\n", tgt); > + > + return 0; > + } > + > + if (verbose && save_err == EBUSY) > + printf("umount(2) returned EBUSY %d times\n", i + 1); > + > + if (save_err != EBUSY) { > + fprintf(stderr, "Failed umount(2): %s\n", > + strerror(save_err)); > + return save_err; > + } > + usleep(USLEEP_TIME); > + } > + > + fprintf(stderr, "Failed to umount(2) after %d retries with: %s\n", > + WAIT_COUNT, strerror(save_err)); > + > + return save_err; > +} >
On Thu, 2020-01-09 at 09:18 -0500, Stephen Smalley wrote: > On 12/20/19 5:11 AM, Richard Haines wrote: > > Test filesystem permissions and setfscreatecon(3). > > > > From kernels 5.5 filesystem { watch } is also tested. > > > > Signed-off-by: Richard Haines <richard_c_haines@btinternet.com> > > During the execution of these tests, I see the following kernel log > spew: > > <6>[ 496.535286] loop: module loaded > <6>[ 498.180983] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: quota,usrquota,grpquota > <4>[ 498.181535] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 498.225114] EXT4-fs (loop0): re-mounted. Opts: > quota,usrquota,grpquota > <4>[ 498.225167] ext4 filesystem being remounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 498.284372] EXT4-fs (loop0): re-mounted. Opts: (null) > <6>[ 498.349328] EXT4-fs (loop0): re-mounted. Opts: (null) > <4>[ 498.349385] ext4 filesystem being remounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 500.582812] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: quota,usrquota,grpquota > <4>[ 500.583071] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <3>[ 501.030500] blk_update_request: I/O error, dev loop0, sector 0 > op > 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 > <3>[ 501.030856] blk_update_request: I/O error, dev loop0, sector 0 > op > 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 > <6>[ 502.557867] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <6>[ 504.475061] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <6>[ 506.366675] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <3>[ 506.479705] blk_update_request: I/O error, dev loop0, sector 0 > op > 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 > <3>[ 506.479925] blk_update_request: I/O error, dev loop0, sector 0 > op > 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 > <6>[ 508.316818] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <3>[ 508.526137] blk_update_request: I/O error, dev loop0, sector 0 > op > 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 > <3>[ 508.526466] blk_update_request: I/O error, dev loop0, sector 0 > op > 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 > <6>[ 510.241013] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <4>[ 510.241323] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 511.867178] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: quota,usrquota,grpquota > <4>[ 511.867442] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <3>[ 512.521949] blk_update_request: I/O error, dev loop0, sector 0 > op > 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 > <3>[ 512.525497] blk_update_request: I/O error, dev loop0, sector 0 > op > 0x1:(WRITE) flags 0x800 phys_seg 0 prio class 0 > <6>[ 513.996580] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: quota,usrquota,grpquota > <4>[ 513.996869] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 514.040984] EXT4-fs (loop0): re-mounted. Opts: (null) > <6>[ 514.065928] EXT4-fs (loop0): re-mounted. Opts: (null) > <4>[ 514.065950] ext4 filesystem being remounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 516.071775] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <6>[ 518.001912] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <4>[ 518.002294] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 519.450511] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <4>[ 519.450737] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 521.579819] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <4>[ 521.580225] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 523.874190] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <4>[ 523.874526] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 525.559041] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <4>[ 525.559423] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 526.541667] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <4>[ 526.542194] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 528.760343] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <4>[ 528.760704] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 530.463519] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <4>[ 530.463823] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > <6>[ 531.469358] EXT4-fs (loop0): mounted filesystem with ordered > data > mode. Opts: > <4>[ 531.469779] ext4 filesystem being mounted at > /home/sds/selinux-testsuite/tests/filesystem/mntpoint/mp1 supports > timestamps until 2038 (0x7fffffff) > > Wondering if all of that is expected and necessary for testing or if > we > can get rid of some of the noise. I'll see about stopping some of these in the next version. > > > --- > > defconfig | 6 + > > policy/Makefile | 4 + > > policy/test_filesystem.te | 324 +++++++ > > tests/Makefile | 7 + > > tests/filesystem/.gitignore | 11 + > > tests/filesystem/Makefile | 16 + > > tests/filesystem/check_file_context.c | 75 ++ > > tests/filesystem/check_mount_context.c | 109 +++ > > tests/filesystem/create_file.c | 79 ++ > > tests/filesystem/create_file_change_context.c | 143 +++ > > tests/filesystem/fanotify_fs.c | 79 ++ > > tests/filesystem/fs_relabel.c | 72 ++ > > tests/filesystem/grim_reaper.c | 63 ++ > > tests/filesystem/mount.c | 130 +++ > > tests/filesystem/quotas_test.c | 134 +++ > > tests/filesystem/statfs_test.c | 65 ++ > > tests/filesystem/test | 830 > > ++++++++++++++++++ > > tests/filesystem/umount.c | 84 ++ > > 18 files changed, 2231 insertions(+) > > create mode 100644 policy/test_filesystem.te > > create mode 100644 tests/filesystem/.gitignore > > create mode 100644 tests/filesystem/Makefile > > create mode 100644 tests/filesystem/check_file_context.c > > create mode 100644 tests/filesystem/check_mount_context.c > > create mode 100644 tests/filesystem/create_file.c > > create mode 100644 tests/filesystem/create_file_change_context.c > > create mode 100644 tests/filesystem/fanotify_fs.c > > create mode 100644 tests/filesystem/fs_relabel.c > > create mode 100644 tests/filesystem/grim_reaper.c > > create mode 100644 tests/filesystem/mount.c > > create mode 100644 tests/filesystem/quotas_test.c > > create mode 100644 tests/filesystem/statfs_test.c > > create mode 100755 tests/filesystem/test > > create mode 100644 tests/filesystem/umount.c > > > > diff --git a/defconfig b/defconfig > > index 3bea332..7cb6a2c 100644 > > --- a/defconfig > > +++ b/defconfig > > @@ -88,3 +88,9 @@ CONFIG_TUN=m > > CONFIG_HAVE_PERF_EVENTS=y > > CONFIG_PERF_EVENTS=y > > CONFIG_TRACEPOINTS=y > > + > > +# Test filesystem permissions. > > +# This is not required for SELinux operation itself. > > +CONFIG_BLK_DEV_LOOP=m > > +CONFIG_BLK_DEV_LOOP_MIN_COUNT=0 > > +CONFIG_QFMT_V2=y > > diff --git a/policy/Makefile b/policy/Makefile > > index 6f1db03..30896d8 100644 > > --- a/policy/Makefile > > +++ b/policy/Makefile > > @@ -114,6 +114,10 @@ TARGETS += test_lockdown.te > > export M4PARAM += -Dlockdown_defined > > endif > > > > +ifeq ($(shell grep -q filesystem > > $(POLDEV)/include/support/all_perms.spt && echo true),true) > > +TARGETS += test_filesystem.te > > +endif > > + > > ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6)) > > TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te > > test_ibpkey.te, $(TARGETS)) > > endif > > diff --git a/policy/test_filesystem.te b/policy/test_filesystem.te > > new file mode 100644 > > index 0000000..2eee1fc > > --- /dev/null > > +++ b/policy/test_filesystem.te > > @@ -0,0 +1,324 @@ > > +# > > +######### Test filesystem permissions policy module ########## > > +# > > +attribute filesystemdomain; > > + > > +#################### Create a test file context > > ###################### > > +type test_filesystem_filecon_t; > > +unconfined_runs_test(test_filesystem_filecon_t) > > + > > +################# Test all functions ########################## > > +type test_filesystem_t; > > +domain_type(test_filesystem_t) > > +unconfined_runs_test(test_filesystem_t) > > +typeattribute test_filesystem_t testdomain; > > +typeattribute test_filesystem_t filesystemdomain; > > + > > +allow test_filesystem_t self:capability { sys_admin }; > > +allow test_filesystem_t self:filesystem { mount remount quotamod > > relabelfrom relabelto unmount quotaget }; > > +allow test_filesystem_t self:dir { mounton add_name write }; > > +allow test_filesystem_t test_file_t:dir { mounton write > > remove_name rmdir }; > > +# Create test file > > +allow test_filesystem_t self:dir { add_name write }; > > +allow test_filesystem_t self:file { create relabelfrom relabelto > > }; > > + > > +fs_mount_all_fs(test_filesystem_t) > > +fs_remount_all_fs(test_filesystem_t) > > +fs_unmount_all_fs(test_filesystem_t) > > +fs_relabelfrom_all_fs(test_filesystem_t) > > +fs_get_xattr_fs_quotas(test_filesystem_t) > > +files_search_all(test_filesystem_t) > > +# Required for mount opts > > "rootcontext=system_u:object_r:test_filesystem_t:s0"; > > +fs_associate(test_filesystem_t) > > +fs_getattr_xattr_fs(test_filesystem_t) > > + > > +# For running quotacheck(8) > > +files_type(test_filesystem_t) > > +# Update quotas > > +fs_set_all_quotas(test_filesystem_t) > > +allow test_filesystem_t self:file { quotaon }; > > +# Create test file and change context: > > +fs_associate(test_filesystem_filecon_t) > > +allow test_filesystem_t test_filesystem_filecon_t:file { open read > > getattr relabelto write }; > > +dontaudit test_filesystem_t kernel_t:process { setsched }; > > + > > +#################### Deny filesystem { getattr } > > ###################### > > +type test_filesystem_no_getattr_t; > > +domain_type(test_filesystem_no_getattr_t) > > +unconfined_runs_test(test_filesystem_no_getattr_t) > > +typeattribute test_filesystem_no_getattr_t testdomain; > > +typeattribute test_filesystem_no_getattr_t filesystemdomain; > > + > > +allow test_filesystem_no_getattr_t self:capability { sys_admin }; > > +fs_mount_all_fs(test_filesystem_no_getattr_t) > > +fs_unmount_all_fs(test_filesystem_no_getattr_t) > > +fs_relabelfrom_all_fs(test_filesystem_no_getattr_t) > > +fs_associate(test_filesystem_no_getattr_t) > > +allow test_filesystem_no_getattr_t self:dir { mounton }; > > +allow test_filesystem_no_getattr_t test_file_t:dir { mounton write > > remove_name rmdir }; > > +dontaudit test_filesystem_no_getattr_t kernel_t:process { setsched > > }; > > + > > +#################### Deny filesystem { remount } > > ###################### > > +type test_filesystem_no_remount_t; > > +domain_type(test_filesystem_no_remount_t) > > +unconfined_runs_test(test_filesystem_no_remount_t) > > +typeattribute test_filesystem_no_remount_t testdomain; > > +typeattribute test_filesystem_no_remount_t filesystemdomain; > > + > > +allow test_filesystem_no_remount_t self:capability { sys_admin }; > > +fs_mount_all_fs(test_filesystem_no_remount_t) > > +fs_unmount_all_fs(test_filesystem_no_remount_t) > > +fs_relabelfrom_all_fs(test_filesystem_no_remount_t) > > +fs_associate(test_filesystem_no_remount_t) > > +allow test_filesystem_no_remount_t self:dir { mounton }; > > +allow test_filesystem_no_remount_t test_file_t:dir { mounton write > > remove_name rmdir }; > > +dontaudit test_filesystem_no_remount_t kernel_t:process { setsched > > }; > > + > > +#################### Deny filesystem { mount } > > ###################### > > +type test_filesystem_no_mount_t; > > +domain_type(test_filesystem_no_mount_t) > > +unconfined_runs_test(test_filesystem_no_mount_t) > > +typeattribute test_filesystem_no_mount_t testdomain; > > +typeattribute test_filesystem_no_mount_t filesystemdomain; > > + > > +allow test_filesystem_no_mount_t self:capability { sys_admin }; > > +fs_relabelfrom_all_fs(test_filesystem_no_mount_t) > > +fs_associate(test_filesystem_no_mount_t) > > +allow test_filesystem_no_mount_t self:dir { mounton }; > > +allow test_filesystem_no_mount_t test_file_t:dir { mounton write > > remove_name rmdir }; > > +dontaudit test_filesystem_no_mount_t kernel_t:process { setsched > > }; > > + > > +#################### Deny filesystem { unmount } > > ###################### > > +type test_filesystem_no_unmount_t; > > +domain_type(test_filesystem_no_unmount_t) > > +unconfined_runs_test(test_filesystem_no_unmount_t) > > +typeattribute test_filesystem_no_unmount_t testdomain; > > +typeattribute test_filesystem_no_unmount_t filesystemdomain; > > + > > +allow test_filesystem_no_unmount_t self:capability { sys_admin }; > > +fs_mount_all_fs(test_filesystem_no_unmount_t) > > +fs_relabelfrom_all_fs(test_filesystem_no_unmount_t) > > +fs_associate(test_filesystem_no_unmount_t) > > +allow test_filesystem_no_unmount_t self:dir { mounton }; > > +allow test_filesystem_no_unmount_t test_file_t:dir { mounton write > > remove_name rmdir }; > > +dontaudit test_filesystem_no_unmount_t kernel_t:process { setsched > > }; > > + > > +#################### Deny filesystem { relabelfrom } > > ###################### > > +type test_filesystem_no_relabelfrom_t; > > +domain_type(test_filesystem_no_relabelfrom_t) > > +unconfined_runs_test(test_filesystem_no_relabelfrom_t) > > +typeattribute test_filesystem_no_relabelfrom_t testdomain; > > +typeattribute test_filesystem_no_relabelfrom_t filesystemdomain; > > + > > +allow test_filesystem_no_relabelfrom_t self:capability { sys_admin > > }; > > +fs_associate(test_filesystem_no_relabelfrom_t) > > +allow test_filesystem_no_relabelfrom_t self:dir { mounton }; > > +allow test_filesystem_no_relabelfrom_t test_file_t:dir { mounton > > write remove_name rmdir }; > > +dontaudit test_filesystem_no_relabelfrom_t kernel_t:process { > > setsched }; > > + > > +#################### Deny filesystem { relabelto } > > ###################### > > +type test_filesystem_no_relabelto_t; > > +domain_type(test_filesystem_no_relabelto_t) > > +unconfined_runs_test(test_filesystem_no_relabelto_t) > > +typeattribute test_filesystem_no_relabelto_t testdomain; > > +typeattribute test_filesystem_no_relabelto_t filesystemdomain; > > + > > +allow test_filesystem_no_relabelto_t self:capability { sys_admin > > }; > > +fs_mount_all_fs(test_filesystem_no_relabelto_t) > > +fs_relabelfrom_all_fs(test_filesystem_no_relabelto_t) > > +fs_associate(test_filesystem_no_relabelto_t) > > +allow test_filesystem_no_relabelto_t self:dir { mounton }; > > +allow test_filesystem_no_relabelto_t test_file_t:dir { mounton > > write remove_name rmdir }; > > +dontaudit test_filesystem_no_relabelto_t kernel_t:process { > > setsched }; > > + > > +#################### Deny filesystem { associate } > > ###################### > > +type test_filesystem_no_associate_t; > > +type test_filesystem_no_associate1_t; > > +domain_type(test_filesystem_no_associate_t) > > +unconfined_runs_test(test_filesystem_no_associate_t) > > +typeattribute test_filesystem_no_associate_t testdomain; > > +typeattribute test_filesystem_no_associate_t filesystemdomain; > > + > > +allow test_filesystem_no_associate_t self:capability { sys_admin > > }; > > +allow test_filesystem_no_associate_t self:filesystem { relabelto > > mount relabelfrom }; > > +fs_mount_all_fs(test_filesystem_no_associate_t) > > +fs_relabelfrom_all_fs(test_filesystem_no_associate_t) > > +allow test_filesystem_no_associate_t self:dir { mounton }; > > +allow test_filesystem_no_associate_t test_file_t:dir { mounton > > write remove_name rmdir }; > > +dontaudit test_filesystem_no_associate_t kernel_t:process { > > setsched }; > > + > > +########## Deny filesystem { associate } for create file > > ################ > > +type test_filesystem_no_associate_file_t; > > +domain_type(test_filesystem_no_associate_file_t) > > +unconfined_runs_test(test_filesystem_no_associate_file_t) > > +typeattribute test_filesystem_no_associate_file_t testdomain; > > +typeattribute test_filesystem_no_associate_file_t > > filesystemdomain; > > + > > +allow test_filesystem_no_associate_file_t self:capability { > > sys_admin }; > > +allow test_filesystem_no_associate_file_t self:filesystem { mount > > relabelfrom relabelto unmount associate }; > > +allow test_filesystem_no_associate_file_t self:dir { mounton > > add_name write }; > > +allow test_filesystem_no_associate_file_t test_file_t:dir { > > mounton write remove_name rmdir }; > > + > > +fs_mount_all_fs(test_filesystem_no_associate_file_t) > > +fs_unmount_all_fs(test_filesystem_no_associate_file_t) > > +fs_relabelfrom_all_fs(test_filesystem_no_associate_file_t) > > +fs_associate(test_filesystem_no_associate_file_t) > > +fs_getattr_xattr_fs(test_filesystem_no_associate_file_t) > > +dontaudit test_filesystem_no_associate_file_t kernel_t:process { > > setsched }; > > + > > +# Create test file > > +allow test_filesystem_no_associate_file_t self:file { create > > relabelfrom relabelto }; > > +############ hooks.c may_create() FILESYSTEM__ASSOCIATE > > ############# > > +# FOR: neverallow unlabeled_t > > test_filesystem_no_associate_file_t:filesystem { associate }; > > +allow test_filesystem_no_associate_file_t unconfined_t:file { open > > read write }; > > +allow test_filesystem_no_associate_file_t unlabeled_t:dir { > > add_name search write }; > > +allow test_filesystem_no_associate_file_t unlabeled_t:file { > > create open relabelfrom write }; > > +############ hooks.c selinux_inode_setxattr() > > FILESYSTEM__ASSOCIATE ########## > > +# FOR: neverallow unconfined_t > > test_filesystem_no_associate_file_t:filesystem { associate }; > > +dontaudit unconfined_t test_filesystem_filecon_t:file { getattr > > read }; > > +allow test_filesystem_no_associate_file_t unconfined_t:dir { > > add_name write }; > > +allow test_filesystem_no_associate_file_t unconfined_t:file { > > create relabelfrom relabelto }; > > + > > +#################### Deny filesystem { quotamod } > > ###################### > > +type test_filesystem_no_quotamod_t; > > +domain_type(test_filesystem_no_quotamod_t) > > +unconfined_runs_test(test_filesystem_no_quotamod_t) > > +typeattribute test_filesystem_no_quotamod_t testdomain; > > +typeattribute test_filesystem_no_quotamod_t filesystemdomain; > > + > > +allow test_filesystem_no_quotamod_t self:capability { sys_admin }; > > +allow test_filesystem_no_quotamod_t self:filesystem { quotaget > > relabelto mount unmount}; > > +fs_mount_all_fs(test_filesystem_no_quotamod_t) > > +fs_relabelfrom_all_fs(test_filesystem_no_quotamod_t) > > +fs_associate(test_filesystem_no_quotamod_t) > > +# Required as $private_path to quota files > > +files_search_all(test_filesystem_no_quotamod_t) > > +allow test_filesystem_no_quotamod_t self:dir { mounton }; > > +allow test_filesystem_no_quotamod_t test_file_t:dir { mounton > > write remove_name rmdir }; > > +dontaudit test_filesystem_no_quotamod_t kernel_t:process { > > setsched }; > > + > > +#################### Deny filesystem { quotaget } > > ###################### > > +type test_filesystem_no_quotaget_t; > > +domain_type(test_filesystem_no_quotaget_t) > > +unconfined_runs_test(test_filesystem_no_quotaget_t) > > +typeattribute test_filesystem_no_quotaget_t testdomain; > > +typeattribute test_filesystem_no_quotaget_t filesystemdomain; > > + > > +allow test_filesystem_no_quotaget_t self:capability { sys_admin }; > > +allow test_filesystem_no_quotaget_t self:filesystem { quotamod > > relabelto mount unmount relabelfrom }; > > +allow test_filesystem_no_quotaget_t self:dir { mounton }; > > +allow test_filesystem_no_quotaget_t test_file_t:dir { mounton > > write remove_name rmdir }; > > +allow test_filesystem_no_quotaget_t self:file { quotaon }; > > +fs_mount_all_fs(test_filesystem_no_quotaget_t) > > +fs_relabelfrom_all_fs(test_filesystem_no_quotaget_t) > > +fs_associate(test_filesystem_no_quotaget_t) > > +# Required as $private_path to quota files > > +files_search_all(test_filesystem_no_quotaget_t) > > +# For running quotacheck(8) > > +files_type(test_filesystem_no_quotaget_t) > > +dontaudit test_filesystem_no_quotaget_t kernel_t:process { > > setsched }; > > + > > +#################### Deny filesystem { watch } > > ###################### > > +type test_filesystem_no_watch_t; > > +domain_type(test_filesystem_no_watch_t) > > +unconfined_runs_test(test_filesystem_no_watch_t) > > +typeattribute test_filesystem_no_watch_t testdomain; > > +typeattribute test_filesystem_no_watch_t filesystemdomain; > > + > > +allow test_filesystem_no_watch_t self:capability { sys_admin }; > > +allow test_filesystem_no_watch_t self:filesystem { associate > > relabelto mount unmount relabelfrom }; > > +allow test_filesystem_no_watch_t self:dir { mounton }; > > +allow test_filesystem_no_watch_t test_file_t:dir { mounton write > > remove_name rmdir }; > > +fs_mount_all_fs(test_filesystem_no_watch_t) > > +fs_relabelfrom_all_fs(test_filesystem_no_watch_t) > > +fs_associate(test_filesystem_no_watch_t) > > +dontaudit test_filesystem_no_watch_t kernel_t:process { setsched > > }; > > + > > +################# Test process { setfscreate } ############# > > +type test_setfscreatecon_t; > > +domain_type(test_setfscreatecon_t) > > +unconfined_runs_test(test_setfscreatecon_t) > > +typeattribute test_setfscreatecon_t testdomain; > > +typeattribute test_setfscreatecon_t filesystemdomain; > > + > > +allow test_setfscreatecon_t self:capability { sys_admin }; > > +allow test_setfscreatecon_t self:process { setfscreate }; > > + > > +# Set new context on fs: > > +type test_setfscreatecon_newcon_t; > > +domain_type(test_setfscreatecon_newcon_t) > > +typeattribute test_setfscreatecon_newcon_t testdomain; > > + > > +################# deny process { setfscreate } ############# > > +type test_no_setfscreatecon_t; > > +domain_type(test_no_setfscreatecon_t) > > +unconfined_runs_test(test_no_setfscreatecon_t) > > +typeattribute test_no_setfscreatecon_t testdomain; > > +typeattribute test_no_setfscreatecon_t filesystemdomain; > > + > > +allow test_no_setfscreatecon_t self:capability { sys_admin }; > > +# neverallow test_no_setfscreatecon_t self:process { setfscreate > > }; > > + > > +################# Test fscontext= ########################## > > +type test_filesystem_fscontext_t; > > +domain_type(test_filesystem_fscontext_t) > > +unconfined_runs_test(test_filesystem_fscontext_t) > > +typeattribute test_filesystem_fscontext_t testdomain; > > +typeattribute test_filesystem_fscontext_t filesystemdomain; > > + > > +allow test_filesystem_fscontext_t self:capability { sys_admin }; > > +allow test_filesystem_fscontext_t self:filesystem { associate > > mount relabelfrom relabelto unmount }; > > +allow test_filesystem_fscontext_t self:dir { mounton add_name > > write }; > > +allow test_filesystem_fscontext_t test_file_t:dir { mounton write > > remove_name rmdir }; > > +# Create test file > > +allow test_filesystem_fscontext_t self:dir { add_name write }; > > +allow test_filesystem_fscontext_t self:file { create relabelfrom > > relabelto }; > > +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { > > relabelto }; > > +allow test_filesystem_filecon_t > > test_filesystem_fscontext_t:filesystem { associate }; > > +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { > > open getattr read write }; > > + > > +fs_mount_all_fs(test_filesystem_fscontext_t) > > +fs_unmount_all_fs(test_filesystem_fscontext_t) > > +fs_relabelfrom_all_fs(test_filesystem_fscontext_t) > > +files_search_all(test_filesystem_fscontext_t) > > + > > +########### Test context=, rootcontext= and defcontext > > ################# > > +type test_filesystem_context_t; > > +domain_type(test_filesystem_context_t) > > +unconfined_runs_test(test_filesystem_context_t) > > +typeattribute test_filesystem_context_t testdomain; > > +typeattribute test_filesystem_context_t filesystemdomain; > > + > > +allow test_filesystem_context_t self:capability { sys_admin }; > > +allow test_filesystem_context_t self:filesystem { associate mount > > relabelfrom relabelto unmount }; > > +allow test_filesystem_context_t self:dir { mounton add_name write > > }; > > +allow test_filesystem_context_t test_file_t:dir { mounton write > > remove_name rmdir }; > > +# Create test file > > +allow test_filesystem_context_t self:dir { add_name write }; > > +allow test_filesystem_context_t self:file { create relabelfrom > > relabelto }; > > +allow test_filesystem_context_t test_filesystem_filecon_t:file { > > open getattr read write relabelto }; > > +allow test_filesystem_filecon_t > > test_filesystem_context_t:filesystem { associate }; > > + > > +fs_mount_all_fs(test_filesystem_context_t) > > +fs_unmount_all_fs(test_filesystem_context_t) > > +fs_relabelfrom_all_fs(test_filesystem_context_t) > > +files_search_all(test_filesystem_context_t) > > +fs_associate(test_filesystem_context_t) > > +allow test_filesystem_context_t test_file_t:dir { add_name }; > > +dontaudit test_filesystem_context_t kernel_t:process { setsched }; > > + > > +# For testing rootcontext= Set mountpoint to unlabeled first > > +allow test_filesystem_context_t test_file_t:dir { relabelfrom }; > > +allow test_filesystem_context_t unlabeled_t:dir { mounton > > relabelto }; > > + > > +# For testing defcontext= > > +allow test_filesystem_context_t test_filesystem_filecon_t:dir { > > search }; > > +allow test_filesystem_fscontext_t test_filesystem_context_t:dir { > > add_name search write }; > > +allow test_filesystem_fscontext_t test_filesystem_context_t:file { > > create getattr open write }; > > +dontaudit unconfined_t test_filesystem_filecon_t:dir { read search > > }; > > + > > +# > > +########### Allow these domains to be entered from sysadm domain > > ############ > > +# > > +miscfiles_domain_entry_test_files(filesystemdomain) > > +userdom_sysadm_entry_spec_domtrans_to(filesystemdomain) > > diff --git a/tests/Makefile b/tests/Makefile > > index e19ea2f..a1478f1 100644 > > --- a/tests/Makefile > > +++ b/tests/Makefile > > @@ -91,6 +91,13 @@ ifeq ($(shell grep -q lockdown > > $(POLDEV)/include/support/all_perms.spt && echo t > > SUBDIRS += lockdown > > endif > > > > +ifeq ($(shell grep -q filesystem > > $(POLDEV)/include/support/all_perms.spt && echo true),true) > > +SUBDIRS += filesystem > > +ifeq ($(shell grep -q all_filesystem_perms.*watch > > $(POLDEV)/include/support/all_perms.spt && echo true),true) > > +export CFLAGS += -DHAVE_FS_WATCH_PERM > > +endif > > +endif > > + > > ifeq ($(DISTRO),RHEL4) > > SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket > > mmap nnp_nosuid overlay unix_socket, $(SUBDIRS)) > > endif > > diff --git a/tests/filesystem/.gitignore > > b/tests/filesystem/.gitignore > > new file mode 100644 > > index 0000000..5ac18d0 > > --- /dev/null > > +++ b/tests/filesystem/.gitignore > > @@ -0,0 +1,11 @@ > > +mount > > +umount > > +quotas_test > > +statfs_test > > +fanotify_fs > > +create_file_change_context > > +fs_relabel > > +check_file_context > > +check_mount_context > > +create_file > > +grim_reaper > > diff --git a/tests/filesystem/Makefile b/tests/filesystem/Makefile > > new file mode 100644 > > index 0000000..d2fad63 > > --- /dev/null > > +++ b/tests/filesystem/Makefile > > @@ -0,0 +1,16 @@ > > +# Required for local building > > +#export CFLAGS += -DHAVE_FS_WATCH_PERM > > + > > +TARGETS = mount umount quotas_test statfs_test > > create_file_change_context \ > > +fs_relabel check_file_context grim_reaper check_mount_context > > create_file > > + > > +LDLIBS += -lselinux > > + > > +ifneq (,$(findstring -DHAVE_FS_WATCH_PERM,$(CFLAGS))) > > + TARGETS += fanotify_fs > > +endif > > + > > +all: $(TARGETS) > > + > > +clean: > > + rm -f $(TARGETS) > > diff --git a/tests/filesystem/check_file_context.c > > b/tests/filesystem/check_file_context.c > > new file mode 100644 > > index 0000000..1380f16 > > --- /dev/null > > +++ b/tests/filesystem/check_file_context.c > > @@ -0,0 +1,75 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <errno.h> > > +#include <fcntl.h> > > +#include <stdbool.h> > > +#include <linux/unistd.h> > > +#include <selinux/selinux.h> > > + > > +static void print_usage(char *progname) > > +{ > > + fprintf(stderr, > > + "usage: %s [-v] -f -e -n\n" > > + "Where:\n\t" > > + "-f File to check its context\n\t" > > + "-e Expected context\n\t" > > + "-v Print information.\n", progname); > > + exit(-1); > > +} > > + > > +int main(int argc, char **argv) > > +{ > > + int opt, result, fd; > > + char *context = NULL, *expected = NULL, *file = NULL; > > + bool verbose = false; > > + > > + while ((opt = getopt(argc, argv, "f:e:v")) != -1) { > > + switch (opt) { > > + case 'f': > > + file = optarg; > > + break; > > + case 'e': > > + expected = optarg; > > + break; > > + case 'v': > > + verbose = true; > > + break; > > + default: > > + print_usage(argv[0]); > > + } > > + } > > + > > + if (!file || !expected) > > + print_usage(argv[0]); > > + > > + fd = open(file, O_RDWR); > > + if (fd < 0) { > > + fprintf(stderr, "open(2) Failed: %s\n", > > strerror(errno)); > > + return -1; > > + } > > + > > + result = fgetfilecon(fd, &context); > > + if (result < 0) { > > + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", > > + strerror(errno)); > > + result = -1; > > + goto err; > > + } > > + result = 0; > > + > > + if (strcmp(expected, context)) { > > + fprintf(stderr, "File context error, > > expected:\n\t%s\ngot:\n\t%s\n", > > + expected, context); > > + result = -1; > > + } else { > > + if (verbose) > > + printf("Pass - File contexts match: %s\n", > > context); > > + } > > +err: > > + free(context); > > + close(fd); > > + > > + return result; > > +} > > diff --git a/tests/filesystem/check_mount_context.c > > b/tests/filesystem/check_mount_context.c > > new file mode 100644 > > index 0000000..dbe0fb8 > > --- /dev/null > > +++ b/tests/filesystem/check_mount_context.c > > @@ -0,0 +1,109 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <errno.h> > > +#include <fcntl.h> > > +#include <stdbool.h> > > +#include <linux/unistd.h> > > +#include <selinux/selinux.h> > > +#include <selinux/context.h> > > + > > +static void print_usage(char *progname) > > +{ > > + fprintf(stderr, > > + "usage: %s [-v] -m [-e] -r\n" > > + "Where:\n\t" > > + "-m Mountpoint\n\t" > > + "-e Expected MP context\n\t" > > + "-r Reset MP context to 'unlabeled_t'\n\t" > > + "-v Print information.\n", progname); > > + exit(-1); > > +} > > + > > +int main(int argc, char **argv) > > +{ > > + int opt, result, save_err; > > + char *context = NULL, *expected = NULL, *mount = NULL, *newcon > > = NULL; > > + bool verbose = false, reset = false; > > + const char *type = "unlabeled_t"; > > + context_t con_t; > > + > > + while ((opt = getopt(argc, argv, "m:e:rv")) != -1) { > > + switch (opt) { > > + case 'm': > > + mount = optarg; > > + break; > > + case 'e': > > + expected = optarg; > > + break; > > + case 'r': > > + reset = true; > > + break; > > + case 'v': > > + verbose = true; > > + break; > > + default: > > + print_usage(argv[0]); > > + } > > + } > > + > > + if (!mount) > > + print_usage(argv[0]); > > + > > + result = getfilecon(mount, &context); > > + if (result < 0) { > > + fprintf(stderr, "getfilecon(3) Failed: %s\n", > > strerror(errno)); > > + result = -1; > > + goto err; > > + } > > + if (verbose) > > + printf("Current MP context: %s\n", context); > > + > > + result = 0; > > + > > + if (reset) { > > + /* Set context to unlabeled_t */ > > + con_t = context_new(context); > > + if (!con_t) { > > + fprintf(stderr, "Unable to create context > > structure\n"); > > + exit(-1); > > + } > > + > > + if (context_type_set(con_t, type)) { > > + fprintf(stderr, "Unable to set new type\n"); > > + exit(-1); > > + } > > + > > + newcon = context_str(con_t); > > + if (!newcon) { > > + fprintf(stderr, "Unable to obtain new context > > string\n"); > > + exit(-1); > > + } > > + > > + result = setfilecon(mount, newcon); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "setfilecon(3) Failed: %s\n", > > + strerror(errno)); > > + result = save_err; > > + goto err; > > + } > > + if (verbose) > > + printf("Set new MP context: %s\n", newcon); > > + } else { > > + if (strcmp(expected, context)) { > > + fprintf(stderr, "Mount context error, > > expected:\n\t%s\ngot:\n\t%s\n", > > + expected, context); > > + result = -1; > > + } else { > > + if (verbose) > > + printf("Pass - Mountpoint contexts > > match: %s\n", > > + context); > > + } > > + } > > + > > +err: > > + free(context); > > + return result; > > +} > > diff --git a/tests/filesystem/create_file.c > > b/tests/filesystem/create_file.c > > new file mode 100644 > > index 0000000..3d73067 > > --- /dev/null > > +++ b/tests/filesystem/create_file.c > > @@ -0,0 +1,79 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <errno.h> > > +#include <fcntl.h> > > +#include <stdbool.h> > > +#include <sys/types.h> > > +#include <linux/unistd.h> > > +#include <selinux/selinux.h> > > + > > +static void print_usage(char *progname) > > +{ > > + fprintf(stderr, > > + "usage: %s [-v] -f\n" > > + "Where:\n\t" > > + "-f File to create\n\t" > > + "-v Print information.\n", progname); > > + exit(-1); > > +} > > + > > +int main(int argc, char **argv) > > +{ > > + int opt, result, fd, save_err; > > + char *context, *file = NULL; > > + bool verbose = false; > > + > > + while ((opt = getopt(argc, argv, "f:v")) != -1) { > > + switch (opt) { > > + case 'f': > > + file = optarg; > > + break; > > + case 'v': > > + verbose = true; > > + break; > > + default: > > + print_usage(argv[0]); > > + } > > + } > > + > > + if (!file) > > + print_usage(argv[0]); > > + > > + if (verbose) { > > + result = getcon(&context); > > + if (result < 0) { > > + fprintf(stderr, "Failed to obtain process > > context\n"); > > + exit(-1); > > + } > > + printf("Process context:\n\t%s\n", context); > > + free(context); > > + } > > + > > + fd = creat(file, O_RDWR); > > + save_err = errno; > > + if (fd < 0) { > > + fprintf(stderr, "creat(2) Failed: %s\n", > > strerror(errno)); > > + return save_err; > > + } > > + > > + context = NULL; > > + result = fgetfilecon(fd, &context); > > + if (result < 0) { > > + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", > > + strerror(errno)); > > + result = -1; > > + goto err; > > + } > > + result = 0; > > + > > + if (verbose) > > + printf("File context is: %s\n", context); > > + > > +err: > > + free(context); > > + close(fd); > > + > > + return result; > > +} > > diff --git a/tests/filesystem/create_file_change_context.c > > b/tests/filesystem/create_file_change_context.c > > new file mode 100644 > > index 0000000..2a3b995 > > --- /dev/null > > +++ b/tests/filesystem/create_file_change_context.c > > @@ -0,0 +1,143 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <errno.h> > > +#include <fcntl.h> > > +#include <stdbool.h> > > +#include <linux/unistd.h> > > +#include <selinux/selinux.h> > > +#include <selinux/context.h> > > + > > +static void print_usage(char *progname) > > +{ > > + fprintf(stderr, > > + "usage: %s [-v] -t -f\n" > > + "Where:\n\t" > > + "-t Type for context of created file\n\t" > > + "-f File to create\n\t" > > + "-v Print information.\n", progname); > > + exit(-1); > > +} > > + > > +int main(int argc, char **argv) > > +{ > > + int opt, result, fd, save_err; > > + char *context, *newfcon, *orgfcon, *type = NULL, *file = NULL; > > + bool verbose = false; > > + context_t con_t; > > + > > + while ((opt = getopt(argc, argv, "t:f:v")) != -1) { > > + switch (opt) { > > + case 't': > > + type = optarg; > > + break; > > + case 'f': > > + file = optarg; > > + break; > > + case 'v': > > + verbose = true; > > + break; > > + default: > > + print_usage(argv[0]); > > + } > > + } > > + > > + if (!type || !file) > > + print_usage(argv[0]); > > + > > + result = getcon(&context); > > + if (result < 0) { > > + fprintf(stderr, "Failed to obtain process context\n"); > > + exit(-1); > > + } > > + > > + /* Build new file context */ > > + con_t = context_new(context); > > + if (!con_t) { > > + fprintf(stderr, "Unable to create context > > structure\n"); > > + exit(-1); > > + } > > + > > + if (context_type_set(con_t, type)) { > > + fprintf(stderr, "Unable to set new type\n"); > > + exit(-1); > > + } > > + > > + newfcon = context_str(con_t); > > + if (!newfcon) { > > + fprintf(stderr, "Unable to obtain new context > > string\n"); > > + exit(-1); > > + } > > + > > + if (verbose) { > > + printf("Process context:\n\t%s\n", context); > > + printf("is creating test file:\n\t%s\n", file); > > + printf("and changing its context to:\n\t%s\n", > > newfcon); > > + } > > + > > + free(context); > > + context = NULL; > > + > > + /* hooks.c may_create() FILESYSTEM__ASSOCIATE */ > > + fd = creat(file, O_RDWR); > > + save_err = errno; > > + if (fd < 0) { > > + fprintf(stderr, "creat(2) Failed: %s\n", > > strerror(errno)); > > + result = save_err; > > + goto err; > > + } > > + > > + result = fgetfilecon(fd, &orgfcon); > > + if (result < 0) { > > + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", > > + strerror(errno)); > > + result = -1; > > + goto err; > > + } > > + > > + if (verbose) > > + printf("Current test file context is: %s\n", orgfcon); > > + > > + free(orgfcon); > > + > > + /* hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE */ > > + result = fsetfilecon(fd, newfcon); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "fsetfilecon(3) Failed: %s\n", > > + strerror(errno)); > > + result = save_err; > > + goto err; > > + } > > + > > + fd = open(file, O_RDWR); > > + if (fd < 0) { > > + fprintf(stderr, "open(2) Failed: %s\n", > > strerror(errno)); > > + result = -1; > > + } > > + > > + result = fgetfilecon(fd, &context); > > + if (result < 0) { > > + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", > > + strerror(errno)); > > + result = -1; > > + goto err; > > + } > > + > > + if (verbose) > > + printf("New test file context is: %s\n", context); > > + > > + result = 0; > > + if (strcmp(newfcon, context)) { > > + fprintf(stderr, "File context error, > > expected:\n\t%s\ngot:\n\t%s\n", > > + newfcon, context); > > + result = -1; > > + } > > +err: > > + free(context); > > + free(newfcon); > > + close(fd); > > + > > + return result; > > +} > > diff --git a/tests/filesystem/fanotify_fs.c > > b/tests/filesystem/fanotify_fs.c > > new file mode 100644 > > index 0000000..1f8f165 > > --- /dev/null > > +++ b/tests/filesystem/fanotify_fs.c > > @@ -0,0 +1,79 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <fcntl.h> > > +#include <errno.h> > > +#include <stdbool.h> > > +#include <sys/fanotify.h> > > +#include <selinux/selinux.h> > > + > > +#ifndef FAN_MARK_FILESYSTEM > > +#define FAN_MARK_FILESYSTEM 0x00000100 > > +#endif > > + > > +static void print_usage(char *progname) > > +{ > > + fprintf(stderr, > > + "usage: %s [-v] -t\n" > > + "Where:\n\t" > > + "-t Target path\n\t" > > + "-v Print information.\n", progname); > > + exit(-1); > > +} > > + > > +int main(int argc, char *argv[]) > > +{ > > + int mask = FAN_OPEN, flags = FAN_MARK_ADD | > > FAN_MARK_FILESYSTEM; > > + int fd, result, opt, save_err; > > + char *context, *tgt = NULL; > > + bool verbose = false; > > + > > + while ((opt = getopt(argc, argv, "t:v")) != -1) { > > + switch (opt) { > > + case 't': > > + tgt = optarg; > > + break; > > + case 'v': > > + verbose = true; > > + break; > > + default: > > + print_usage(argv[0]); > > + } > > + } > > + > > + if (!tgt) > > + print_usage(argv[0]); > > + > > + if (verbose) { > > + result = getcon(&context); > > + if (result < 0) { > > + fprintf(stderr, "Failed to obtain process > > context\n"); > > + exit(-1); > > + } > > + printf("Process context:\n\t%s\n", context); > > + free(context); > > + } > > + > > + fd = fanotify_init(FAN_CLASS_CONTENT, O_RDWR); > > + if (fd < 0) { > > + fprintf(stderr, "fanotify_init(2) Failed: %s\n", > > + strerror(errno)); > > + exit(-1); > > + } > > + > > + result = fanotify_mark(fd, flags, mask, AT_FDCWD, tgt); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "fanotify_mark(2) Failed: %s\n", > > + strerror(errno)); > > + close(fd); > > + return save_err; > > + } > > + > > + if (verbose) > > + printf("Set fanotify_mark(2) on filesystem: %s\n", > > tgt); > > + > > + close(fd); > > + return 0; > > +} > > diff --git a/tests/filesystem/fs_relabel.c > > b/tests/filesystem/fs_relabel.c > > new file mode 100644 > > index 0000000..25b1781 > > --- /dev/null > > +++ b/tests/filesystem/fs_relabel.c > > @@ -0,0 +1,72 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <errno.h> > > +#include <fcntl.h> > > +#include <stdbool.h> > > +#include <linux/unistd.h> > > +#include <selinux/selinux.h> > > + > > +static void print_usage(char *progname) > > +{ > > + fprintf(stderr, > > + "usage: %s [-v] -n\n" > > + "Where:\n\t" > > + "-n New fs context\n\t" > > + "-v Print information.\n", progname); > > + exit(-1); > > +} > > + > > +int main(int argc, char **argv) > > +{ > > + int opt, result, save_err; > > + char *context, *fscreate_con, *newcon = NULL; > > + bool verbose = false; > > + > > + while ((opt = getopt(argc, argv, "n:v")) != -1) { > > + switch (opt) { > > + case 'n': > > + newcon = optarg; > > + break; > > + case 'v': > > + verbose = true; > > + break; > > + default: > > + print_usage(argv[0]); > > + } > > + } > > + > > + if (!newcon) > > + print_usage(argv[0]); > > + > > + if (verbose) { > > + result = getcon(&context); > > + if (result < 0) { > > + fprintf(stderr, "Failed to obtain process > > context\n"); > > + exit(-1); > > + } > > + printf("Process context:\n\t%s\n", context); > > + free(context); > > + } > > + > > + result = setfscreatecon(newcon); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "Failed setfscreatecon(3): %s\n", > > + strerror(errno)); > > + return save_err; > > + } > > + > > + result = getfscreatecon(&fscreate_con); > > + if (result < 0) { > > + fprintf(stderr, "Failed getfscreatecon(3): %s\n", > > + strerror(errno)); > > + exit(-1); > > + } > > + if (verbose) > > + printf("New fscreate context: %s\n", fscreate_con); > > + > > + free(fscreate_con); > > + return 0; > > +} > > diff --git a/tests/filesystem/grim_reaper.c > > b/tests/filesystem/grim_reaper.c > > new file mode 100644 > > index 0000000..0105ab6 > > --- /dev/null > > +++ b/tests/filesystem/grim_reaper.c > > @@ -0,0 +1,63 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <errno.h> > > +#include <stdbool.h> > > +#include <sys/mount.h> > > +#include <selinux/selinux.h> > > + > > +#define WAIT_COUNT 60 > > +#define USLEEP_TIME 10000 > > + > > +/* Remove any mounts associated with the loop device in argv[1] */ > > +int main(int argc, char *argv[]) > > +{ > > + FILE *fp; > > + size_t len; > > + ssize_t num; > > + int index = 0, i, result = 0; > > + char *mount_info[2]; > > + char *buf = NULL, *item; > > + > > + if (!argv[1]) > > + return -1; > > + > > + fp = fopen("/proc/mounts", "re"); > > + if (!fp) { > > + fprintf(stderr, "Failed to open /proc/mounts: %s\n", > > + strerror(errno)); > > + return -1; > > + } > > + > > + while ((num = getline(&buf, &len, fp)) != -1) { > > + index = 0; > > + item = strtok(buf, " "); > > + while (item != NULL) { > > + mount_info[index] = item; > > + index++; > > + if (index == 2) > > + break; > > + item = strtok(NULL, " "); > > + } > > + > > + if (strcmp(mount_info[0], argv[1]) == 0) { > > + for (i = 0; i < WAIT_COUNT; i++) { > > + result = umount(mount_info[1]); > > + if (!result) > > + break; > > + > > + if (errno != EBUSY) { > > + fprintf(stderr, "Failed > > umount(2): %s\n", > > + strerror(errno)); > > + break; > > + } > > + usleep(USLEEP_TIME); > > + } > > + } > > + } > > + > > + free(buf); > > + fclose(fp); > > + return result; > > +} > > diff --git a/tests/filesystem/mount.c b/tests/filesystem/mount.c > > new file mode 100644 > > index 0000000..034f0ec > > --- /dev/null > > +++ b/tests/filesystem/mount.c > > @@ -0,0 +1,130 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <errno.h> > > +#include <stdbool.h> > > +#include <sys/mount.h> > > +#include <selinux/selinux.h> > > + > > +static void print_usage(char *progname) > > +{ > > + fprintf(stderr, > > + "usage: %s [-s src] -t tgt [-f fs_type] [-o options] > > [-bmprv]\n" > > + "Where:\n\t" > > + "-s Source path\n\t" > > + "-t Target path\n\t" > > + "-f Filesystem type\n\t" > > + "-o Options list (comma separated list)\n\t" > > + "Zero or one of the following flags:\n\t" > > + "\t-b MS_BIND\n\t" > > + "\t-m MS_MOVE\n\t" > > + "\t-p MS_PRIVATE\n\t" > > + "\t-r MS_REMOUNT\n\t" > > + "-v Print information.\n", progname); > > + exit(-1); > > +} > > + > > +static int ck_mount(char *mntpoint) > > +{ > > + int result = 0; > > + FILE *fp; > > + size_t len; > > + ssize_t num; > > + char *buf = NULL; > > + > > + fp = fopen("/proc/mounts", "re"); > > + if (fp == NULL) { > > + fprintf(stderr, "Failed to open /proc/mounts: %s\n", > > + strerror(errno)); > > + return -1; > > + } > > + > > + while ((num = getline(&buf, &len, fp)) != -1) { > > + if (strstr(buf, mntpoint) != NULL) { > > + result = 1; > > + break; > > + } > > + } > > + > > + free(buf); > > + fclose(fp); > > + return result; > > +} > > + > > +int main(int argc, char *argv[]) > > +{ > > + int opt, result, save_err, flags = 0; > > + char *context, *src = NULL, *tgt = NULL, *fs_type = NULL, *opts > > = NULL; > > + bool verbose = false; > > + > > + while ((opt = getopt(argc, argv, "s:t:f:o:pbmrv")) != -1) { > > + switch (opt) { > > + case 's': > > + src = optarg; > > + break; > > + case 't': > > + tgt = optarg; > > + break; > > + case 'f': > > + fs_type = optarg; > > + break; > > + case 'o': > > + opts = optarg; > > + break; > > + case 'b': > > + flags = MS_BIND; > > + break; > > + case 'p': > > + flags = MS_PRIVATE; > > + break; > > + case 'm': > > + flags = MS_MOVE; > > + break; > > + case 'r': > > + flags = MS_REMOUNT; > > + break; > > + case 'v': > > + verbose = true; > > + break; > > + default: > > + print_usage(argv[0]); > > + } > > + } > > + > > + if (!tgt) > > + print_usage(argv[0]); > > + > > + if (verbose) { > > + result = getcon(&context); > > + if (result < 0) { > > + fprintf(stderr, "Failed to obtain process > > context\n"); > > + return -1; > > + } > > + printf("Process context:\n\t%s\n", context); > > + free(context); > > + } > > + > > + if (verbose) > > + printf("Mounting\n\tsrc: %s\n\ttgt: %s\n\tfs_type: %s > > flags: 0x%x\n\topts: %s\n", > > + src, tgt, fs_type, flags, opts); > > + > > + result = mount(src, tgt, fs_type, flags, opts); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "Failed mount(2): %s\n", > > strerror(errno)); > > + return save_err; > > + } > > + > > + if (flags == MS_MOVE) { > > + if (!ck_mount(src) && ck_mount(tgt)) { > > + if (verbose) > > + printf("MS_MOVE: Moved mountpoint\n"); > > + } else { > > + fprintf(stderr, "MS_MOVE: Move mountpoint > > failed\n"); > > + return -1; > > + } > > + } > > + > > + return 0; > > +} > > diff --git a/tests/filesystem/quotas_test.c > > b/tests/filesystem/quotas_test.c > > new file mode 100644 > > index 0000000..34aaca9 > > --- /dev/null > > +++ b/tests/filesystem/quotas_test.c > > @@ -0,0 +1,134 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <errno.h> > > +#include <stdbool.h> > > +#include <sys/quota.h> > > +#include <selinux/selinux.h> > > + > > +static void print_usage(char *progname) > > +{ > > + fprintf(stderr, > > + "usage: %s -s src -t tgt\n" > > + "Where:\n\t" > > + "-s Source path (e.g. /dev/loop0)\n\t" > > + "-t Target quota file (Full path with either > > 'aquota.user'\n\t" > > + " or 'aquota.group' appended)\n\t" > > + "-v Print information.\n", progname); > > + exit(-1); > > +} > > + > > +int main(int argc, char *argv[]) > > +{ > > + int opt, result, qcmd, save_err, test_id = geteuid(); > > + char *context, *src = NULL, *tgt = NULL; > > + bool verbose = false; > > + char fmt_buf[2]; > > + > > + while ((opt = getopt(argc, argv, "s:t:v")) != -1) { > > + switch (opt) { > > + case 's': > > + src = optarg; > > + break; > > + case 't': > > + tgt = optarg; > > + break; > > + case 'v': > > + verbose = true; > > + break; > > + default: > > + print_usage(argv[0]); > > + } > > + } > > + > > + if (!src || !tgt) > > + print_usage(argv[0]); > > + > > + if (verbose) { > > + result = getcon(&context); > > + if (result < 0) { > > + fprintf(stderr, "Failed to obtain process > > context\n"); > > + return -1; > > + } > > + printf("Process context:\n\t%s\n", context); > > + free(context); > > + } > > + > > + if (strstr(tgt, "aquota.user") != NULL) { > > + qcmd = QCMD(Q_QUOTAON, USRQUOTA); > > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "quotactl(Q_QUOTAON, USRQUOTA) > > Failed: %s\n", > > + strerror(errno)); > > + return save_err; > > + } > > + if (verbose) > > + printf("User Quota - ON\n"); > > + > > + qcmd = QCMD(Q_GETFMT, USRQUOTA); > > + result = quotactl(qcmd, src, test_id, fmt_buf); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "quotactl(Q_GETFMT, USRQUOTA) > > Failed: %s\n", > > + strerror(errno)); > > + return save_err; > > + } > > + if (verbose) > > + printf("User Format: 0x%x\n", fmt_buf[0]); > > + > > + qcmd = QCMD(Q_QUOTAOFF, USRQUOTA); > > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "quotactl(Q_QUOTAOFF, USRQUOTA) > > Failed: %s\n", > > + strerror(errno)); > > + return save_err; > > + } > > + if (verbose) > > + printf("User Quota - OFF\n"); > > + > > + return 0; > > + > > + } else if (strstr(tgt, "aquota.group") != NULL) { > > + qcmd = QCMD(Q_QUOTAON, GRPQUOTA); > > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "quotactl(Q_QUOTAON, GRPQUOTA) > > Failed: %s\n", > > + strerror(errno)); > > + return save_err; > > + } > > + if (verbose) > > + printf("Group Quota - ON\n"); > > + > > + qcmd = QCMD(Q_GETFMT, GRPQUOTA); > > + result = quotactl(qcmd, src, test_id, fmt_buf); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "quotactl(Q_GETFMT, GRPQUOTA) > > Failed: %s\n", > > + strerror(errno)); > > + return save_err; > > + } > > + if (verbose) > > + printf("Group Format: 0x%x\n", fmt_buf[0]); > > + > > + qcmd = QCMD(Q_QUOTAOFF, GRPQUOTA); > > + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "quotactl(Q_QUOTAOFF, GRPQUOTA) > > Failed: %s\n", > > + strerror(errno)); > > + return save_err; > > + } > > + if (verbose) > > + printf("Group Quota - OFF\n"); > > + > > + return 0; > > + } > > + > > + fprintf(stderr, "Required %s to specify 'aquota.user' or > > 'aquota.group' file\n", > > + tgt); > > + return -1; > > +} > > diff --git a/tests/filesystem/statfs_test.c > > b/tests/filesystem/statfs_test.c > > new file mode 100644 > > index 0000000..5de49b1 > > --- /dev/null > > +++ b/tests/filesystem/statfs_test.c > > @@ -0,0 +1,65 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <errno.h> > > +#include <stdbool.h> > > +#include <sys/statfs.h> > > +#include <selinux/selinux.h> > > + > > +static void print_usage(char *progname) > > +{ > > + fprintf(stderr, > > + "usage: %s [-v] -t\n" > > + "Where:\n\t" > > + "-t Target path\n\t" > > + "-v Print information.\n", progname); > > + exit(-1); > > +} > > + > > +int main(int argc, char *argv[]) > > +{ > > + int opt, result, save_err; > > + char *context, *tgt = NULL; > > + bool verbose = false; > > + struct statfs statfs_t; > > + > > + while ((opt = getopt(argc, argv, "t:v")) != -1) { > > + switch (opt) { > > + case 't': > > + tgt = optarg; > > + break; > > + case 'v': > > + verbose = true; > > + break; > > + default: > > + print_usage(argv[0]); > > + } > > + } > > + > > + if (!tgt) > > + print_usage(argv[0]); > > + > > + if (verbose) { > > + result = getcon(&context); > > + if (result < 0) { > > + fprintf(stderr, "Failed to obtain process > > context\n"); > > + return -1; > > + } > > + printf("Process context:\n\t%s\n", context); > > + free(context); > > + } > > + > > + result = statfs(tgt, &statfs_t); > > + save_err = errno; > > + if (result < 0) { > > + fprintf(stderr, "statfs(2) Failed: %s\n", > > strerror(errno)); > > + return save_err; > > + } > > + > > + if (verbose) > > + printf("statfs(2) returned magic filesystem: 0x%lx\n", > > + statfs_t.f_type); > > + > > + return 0; > > +} > > diff --git a/tests/filesystem/test b/tests/filesystem/test > > new file mode 100755 > > index 0000000..00c69e1 > > --- /dev/null > > +++ b/tests/filesystem/test > > @@ -0,0 +1,830 @@ > > +#!/usr/bin/perl > > +use Test::More; > > + > > +BEGIN { > > + $basedir = $0; > > + $basedir =~ s|(.*)/[^/]*|$1|; > > + > > + $test_count = 63; > > + > > + # Allow info to be shown. > > + $v = $ARGV[0]; > > + if ($v) { > > + if ( $v ne "-v" ) { > > + plan skip_all => "Invalid option (use -v)"; > > + } > > + } > > + else { > > + $v = " "; > > + } > > + > > + # From kernel 5.5 support for fanotify(7) with filesystem { > > watch } > > + $kvercur = `uname -r`; > > + chomp($kvercur); > > + $kverminstream = "5.5"; > > + > > + $result = `$basedir/../kvercmp $kvercur $kverminstream`; > > + if ( $result > 0 && -e "$basedir/fanotify_fs" ) { > > + $test_watch = 1; > > + $test_count += 4; > > + } > > + > > + plan tests => $test_count; > > +} > > + > > +# mount(2) MS_BIND | MS_PRIVATE requires an absolute path to a > > private mount > > +# point before MS_MOVE > > +$cwd = `pwd 2>/dev/null`; > > +chomp($cwd); > > +$private_path = "$cwd"; > > +if ( $basedir eq "." ) { > > + $private_path = "$cwd/mntpoint"; > > +} > > +else { > > + $private_path = "$cwd/$basedir/mntpoint"; > > +} > > + > > +# Set initial filesystem type > > +$fs_type = "ext4"; > > + > > +# For list of devices used > > +$device_count = 0; > > + > > +sub get_loop_dev { > > + print "Finding free /dev/loop entry\n"; > > + $dev = `losetup -f 2>/dev/null`; > > + chomp($dev); > > + if ( $dev eq "" ) { > > + print "losetup failed to obtain /dev/loop entry\n"; > > + cleanup(); > > + exit -1; > > + } > > + > > + # Keep list of devices for cleanup later > > + if ( $device_count eq 0 ) { > > + $device_list[$device_count] = $dev; > > + $device_count += 1; > > + } > > + elsif ( $dev ne $device_list[ $device_count - 1 ] ) { > > + $device_list[$device_count] = $dev; > > + $device_count += 1; > > + } > > +} > > + > > +sub attach_dev { > > + print "Attaching $basedir/fstest to $dev\n"; > > + $result = system("losetup $dev $basedir/fstest 2>/dev/null"); > > + if ( $result != 0 ) { > > + print "Failed to attach $basedir/fstest to $dev\n"; > > + cleanup(); > > + exit -1; > > + } > > +} > > + > > +sub make_fs { > > + my ($mk_type) = @_; > > + > > + get_loop_dev(); > > + > > + if ( $mk_type eq "tmpfs" ) { > > + return; > > + } > > + > > + print "Create $basedir/fstest with dd\n"; > > + $result = system( > > + "dd if=/dev/zero of=$basedir/fstest bs=1024 count=10240 > > 2>/dev/null"); > > + if ( $result != 0 ) { > > + print "dd failed to create fstest\n"; > > + exit -1; > > + } > > + > > + attach_dev(); > > + > > + print "Make $mk_type filesystem on $dev\n"; > > + $result = system("mkfs.$mk_type $dev >& /dev/null"); > > + if ( $result != 0 ) { > > + system("losetup -d $dev 2>/dev/null"); > > + cleanup(); > > + print "mkfs.$mk_type failed to create filesystem on > > $dev\n"; > > + exit -1; > > + } > > +} > > + > > +sub mk_mntpoint_1 { > > + system("rm -rf $private_path/mp1 2>/dev/null"); > > + system("mkdir -p $private_path/mp1 2>/dev/null"); > > +} > > + > > +sub mk_mntpoint_2 { > > + system("rm -rf $private_path/mp2 2>/dev/null"); > > + system("mkdir -p $private_path/mp2 2>/dev/null"); > > +} > > + > > +sub cleanup { > > + system("rm -rf $basedir/fstest 2>/dev/null"); > > + system("rm -rf $basedir/mntpoint 2>/dev/null"); > > +} > > + > > +sub cleanup1 { > > + system("losetup -d $dev 2>/dev/null"); > > + system("rm -rf $basedir/fstest 2>/dev/null"); > > + system("rm -rf $basedir/mntpoint 2>/dev/null"); > > +} > > + > > +############### Test setfscreatecon(3) ########################## > > +print "Test setfscreatecon(3)\n"; > > +$result = system > > +"runcon -t test_setfscreatecon_t $basedir/fs_relabel $v -n > > system_u:system_r:test_setfscreatecon_newcon_t:s0"; > > +ok( $result eq 0 ); > > + > > +$result = system > > +"runcon -t test_no_setfscreatecon_t $basedir/fs_relabel $v -n > > system_u:system_r:test_setfscreatecon_newcon_t:s0 2>&1"; > > +ok( $result >> 8 eq 13 ); > > + > > +############### Test Basic Mount/Unmount > > ########################## > > +cleanup(); > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > +$mount_opts1 = > > + "quota,usrquota,grpquota,defcontext=system_u:object_r:test_files > > ystem_t:s0"; > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$mount_opts1\n"; > > +$result = system( > > +"runcon -t test_filesystem_t $basedir/mount -s $dev -t > > $private_path/mp1 -f $fs_type -o $mount_opts1 $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Then remount\n"; > > +$result = system( > > +"runcon -t test_filesystem_t $basedir/mount -r -s $dev -t > > $private_path/mp1 -f $fs_type -o $mount_opts1 $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Running quotacheck(8) to init user/group quota files\n"; > > +$result = system("quotacheck -ugF vfsv0 $private_path/mp1"); > > +ok( $result eq 0 ); > > + > > +print "Toggle User & Group quotas on/off\n"; > > +$result = system( > > +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t > > $private_path/mp1/aquota.user $v" > > +); > > +ok( $result eq 0 ); > > +$result = system( > > +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t > > $private_path/mp1/aquota.group $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Get statfs(2)\n"; > > +$result = > > + system( > > + "runcon -t test_filesystem_t $basedir/statfs_test -t > > $basedir/mntpoint $v"); > > +ok( $result eq 0 ); > > + > > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_t $basedir/create_file_change_context > > -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v" > > + ); > > +ok( $result eq 0 ); > > + > > +if ($test_watch) { > > + print "fanotify(7) test\n"; > > + $result = system( > > +"runcon -t test_filesystem_t $basedir/fanotify_fs $v -t > > $basedir/mntpoint/mp1" > > + ); > > + ok( $result eq 0 ); > > +} > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = > > + system("runcon -t test_filesystem_t $basedir/umount -t > > $private_path/mp1 $v"); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Test Move Mount ########################## > > +make_fs($fs_type); > > +$mount_opts2 = > > + "quota,usrquota,grpquota,rootcontext=system_u:object_r:test_file > > system_t:s0"; > > +system("mkdir -p $private_path 2>/dev/null"); > > + > > +print "Set mount MS_BIND on filesystem\n"; > > +$result = system( > > +"runcon -t test_filesystem_t $basedir/mount -s $private_path -t > > $private_path -b $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Set mount MS_PRIVATE on filesystem\n"; > > +$result = > > + system("runcon -t test_filesystem_t $basedir/mount -t > > $private_path -p $v"); > > +ok( $result eq 0 ); > > + > > +mk_mntpoint_1(); > > +mk_mntpoint_2(); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$mount_opts2\n"; > > +$result = system( > > +"runcon -t test_filesystem_t $basedir/mount -s $dev -t > > $private_path/mp1 -f $fs_type -o $mount_opts2 $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Set mount MS_MOVE on filesystem\n"; > > +$result = system( > > +"runcon -t test_filesystem_t $basedir/mount -s $private_path/mp1 > > -t $private_path/mp2 -m $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp2\n"; > > +$result = > > + system("runcon -t test_filesystem_t $basedir/umount -t > > $private_path/mp2 $v"); > > +ok( $result eq 0 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint\n"; > > +$result = > > + system("runcon -t test_filesystem_t $basedir/umount -t > > $private_path $v"); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { relabelfrom } > > ########################## > > +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM > > + > > +$opts_no_relabelfrom = > > +"defcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0, > > fscontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0"; > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_relabelfrom\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev > > -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v > > 2>&1" > > +); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { relabelto } > > ########################## > > +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO > > + > > +$opts_no_relabelto = > > + "fscontext=system_u:object_r:test_filesystem_no_relabelto_t:s0"; > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_relabelto\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_relabelto_t $basedir/mount -s $dev > > -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelto $v 2>&1" > > +); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { relabelfrom } > > ########################## > > +# hooks.c may_context_mount_inode_relabel() > > FILESYSTEM__RELABELFROM > > + > > +$opts_no_relabelfrom = > > + "rootcontext=system_u:object_r:test_filesystem_no_relabelfrom_t: > > s0"; > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_relabelfrom\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev > > -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v > > 2>&1" > > +); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { associate } > > ########################## > > +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE > > + > > +$opts_no_associate = > > +"defcontext=system_u:object_r:test_filesystem_no_associate_t:s0,fs > > context=system_u:object_r:test_filesystem_no_associate_t:s0"; > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_associate\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_associate_t $basedir/mount -s $dev > > -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate $v 2>&1" > > +); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { associate } > > ########################## > > +# hooks.c may_create() FILESYSTEM__ASSOCIATE > > +cleanup(); > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > +$opts_no_associate_file = > > + "fscontext=system_u:object_r:test_filesystem_no_associate_file_t > > :s0"; > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_associate_file\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s > > $dev -t $basedir/mntpoint/mp1 -f $fs_type -o > > $opts_no_associate_file $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_no_associate_file_t > > $basedir/create_file_change_context -t unconfined_t -f > > $basedir/mntpoint/mp1/test_file $v 2>&1" > > + ); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { quotamod } > > ########################## > > +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD > > + > > +$opts_no_quotamod = > > +"quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesyst > > em_no_quotamod_t:s0"; > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > +system("mkdir -p $private_path 2>/dev/null"); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_quotamod\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_quotamod_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotamod $v 2>&1" > > +); > > +ok( $result eq 0 ); > > + > > +# No need to run quotacheck(8) as never gets far enough to read > > quota file > > +print "Toggle User & Group quotas on/off\n"; # Must have full > > path > > +$result = system( > > +"runcon -t test_filesystem_no_quotamod_t $basedir/quotas_test -s > > $dev -t $private_path/mp1/aquota.user $v 2>&1" > > +); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_quotamod_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { quotaget } > > ########################## > > +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET > > + > > +$opts_no_quotaget = > > +"quota,usrquota,grpquota,context=system_u:object_r:test_filesystem > > _no_quotaget_t:s0"; > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_quotaget\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_quotaget_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotaget $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Running quotacheck(8) to init user/group quota files\n"; > > +$result = system("quotacheck -ugF vfsv0 $private_path/mp1"); > > +ok( $result eq 0 ); > > + > > +print "Toggle User & Group quotas on/off\n"; # Must have full > > path > > +$result = system( > > +"runcon -t test_filesystem_no_quotaget_t $basedir/quotas_test -s > > $dev -t $private_path/mp1/aquota.user $v 2>&1" > > +); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_quotaget_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { mount } > > ########################## > > +# hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT > > + > > +$opts_no_mount = > > "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0"; > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_mount\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_mount_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_mount $v 2>&1" > > +); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { getattr } > > ########################## > > +# hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR > > + > > +$opts_no_getattr = > > + "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0"; > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_getattr\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_getattr_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_getattr $v" > > +); > > +ok( $result eq 0 ); > > + > > +$result = system( > > +"runcon -t test_filesystem_no_getattr_t $basedir/statfs_test -t > > $basedir/mntpoint $v 2>&1" > > +); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_getattr_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { remount } > > ########################## > > +# hooks.c selinux_mount() FILESYSTEM__REMOUNT > > + > > +$opts_no_remount = > > + "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0"; > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_remount\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_remount_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Then remount\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_remount_t $basedir/mount -r -s $dev > > -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v 2>&1" > > +); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_remount_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { unmount } > > ########################## > > +# hooks.c selinux_umount() FILESYSTEM__UNMOUNT > > + > > +$opts_no_unmount = > > + "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0"; > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_unmount\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_unmount_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_unmount $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_unmount_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v 2>&1" > > +); > > +ok( $result >> 8 eq 13 ); > > + > > +# Make sure it does get unmounted > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = > > + system( > > + "runcon -t test_filesystem_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v"); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { associate > > } ########################## > > +# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE > > +cleanup(); > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > +$opts_no_associate_file = > > +"defcontext=system_u:object_r:test_filesystem_no_associate_file_t: > > s0,fscontext=system_u:object_r:test_filesystem_no_associate_file_t: > > s0"; > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$opts_no_associate_file\n"; > > +$result = system( > > +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s > > $dev -t $basedir/mntpoint/mp1 -f $fs_type -o > > $opts_no_associate_file $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_no_associate_file_t > > $basedir/create_file_change_context -t unconfined_t -f > > $basedir/mntpoint/mp1/test_file $v 2>&1" > > + ); > > +ok( $result >> 8 eq 13 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +############### Deny filesystem { watch > > } ########################## > > +# hooks.c selinux_path_notify() FILESYSTEM__WATCH > > +if ($test_watch) { > > + cleanup(); > > + mk_mntpoint_1(); > > + make_fs($fs_type); > > + $opts_no_watch = > > "context=system_u:object_r:test_filesystem_no_watch_t:s0"; > > + > > + print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > + print "Using mount options:\n\t$opts_no_watch\n"; > > + $result = system( > > +"runcon -t test_filesystem_no_watch_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_watch $v" > > + ); > > + ok( $result eq 0 ); > > + > > + print "test_fanotify\n"; > > + $result = system( > > +"runcon -t test_filesystem_no_watch_t $basedir/fanotify_fs $v -t > > $basedir/mntpoint/mp1 2>&1" > > + ); > > + ok( $result >> 8 eq 13 ); > > + > > + print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > + $result = system( > > +"runcon -t test_filesystem_no_watch_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > + ); > > + ok( $result eq 0 ); > > + > > + print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > + cleanup1(); > > +} > > + > > +################################################################## > > ######## > > +# context - Useful when mounting filesystems that do not > > support extended > > +# attributes. > > +# Tested by - Creating a filesystem that has xattrs set to a > > different value, > > +# then mount with context= and confirm that the > > files have that > > +# context as well as any newly created files (even > > if fscreate > > +# was set to something else), and that > > setfilecon/setxattr() on > > +# files within the mount fails with errno > > EOPNOTSUPP. > > +################################################################## > > ######## > > +cleanup(); > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +# Mount with xttrs to create a file with specific context. > > +$context1_opts = > > "defcontext=system_u:object_r:test_filesystem_context_t:s0"; > > + > > +print "Testing 'context=' mount option\n"; > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$context1_opts\n"; > > +$result = system( > > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $context1_opts $v" > > +); > > +ok( $result eq 0 ); > > + > > +# Create file with 'test_filesystem_filecon_t' context > > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_context_t > > $basedir/create_file_change_context -t test_filesystem_filecon_t -f > > $private_path/mp1/test_file $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = system( > > +"runcon -t test_filesystem_context_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > +); > > +ok( $result eq 0 ); > > + > > +# Need to free the loop device, then get new dev one and attach > > +system("losetup -d $dev 2>/dev/null"); > > +get_loop_dev(); > > +attach_dev(); > > + > > +# Mount again with no xttr support > > +$context2_opts = > > "context=system_u:object_r:test_filesystem_context_t:s0"; > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$context2_opts\n"; > > +$result = system( > > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $context2_opts $v" > > +); > > +ok( $result eq 0 ); > > + > > +# Now check the context on file is > > system_u:object_r:test_filesystem_context_t:s0 > > +print "Check test file context $basedir/mntpoint/mp1/test_file\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_context_t $basedir/check_file_context > > -f $private_path/mp1/test_file -e > > system_u:object_r:test_filesystem_context_t:s0 $v" > > + ); > > +ok( $result eq 0 ); > > + > > +# Then create a file with 'test_filesystem_filecon_t' context, > > this should fail with EOPNOTSUPP > > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_context_t > > $basedir/create_file_change_context -t test_filesystem_filecon_t -f > > $private_path/mp1/test_file $v 2>/dev/null" > > + ); > > +ok( $result >> 8 eq 95 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_context_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +################################################################## > > ######## > > +# rootcontext - Explicitly label the root inode of the filesystem > > being > > +# mounted before that filesystem or inode becomes > > visible > > +# to userspace. > > +# Tested by - Set mountpoint to unlabeled_t and then check that > > the > > +# context of the root directory matches rootcontext= > > after > > +# the mount operation. > > +################################################################## > > ######## > > +cleanup(); > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > +$root_opts = > > "rootcontext=system_u:object_r:test_filesystem_context_t:s0"; > > + > > +print "Testing 'rootcontext=' mount option\n"; > > + > > +# Reset mountpoint to 'unlabeled_t' so it is different to any > > other possible test values. > > +print "Resetting MP to unlabeled_t $basedir/mntpoint/mp1\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_context_t $basedir/check_mount_context > > -r -m $basedir/mntpoint/mp1 $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$root_opts\n"; > > +$result = system( > > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $root_opts $v" > > +); > > +ok( $result eq 0 ); > > + > > +# Now check the mountpoint is the 'rootcontext=' value > > +print "Check MP context $basedir/mntpoint/mp1\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_context_t $basedir/check_mount_context > > -m $basedir/mntpoint/mp1 -e > > system_u:object_r:test_filesystem_context_t:s0 $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = system( > > +"runcon -t test_filesystem_context_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +################################################################## > > ######## > > +# defcontext - Set default security context for unlabeled files. > > +# This overrides the value set for unlabeled files > > in policy > > +# and requires a filesystem that supports xattr > > labeling. > > +# Tested by - Create filesystem that has files w/o xattrs and > > then confirm > > +# that they are mapped to the specified defcontext > > upon mount, > > +# where defcontext differs from the policy default. > > +################################################################## > > ######## > > +cleanup(); > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > + > > +$test_opts = > > "context=system_u:object_r:test_filesystem_context_t:s0"; > > + > > +print "Testing 'defcontext=' mount option\n"; > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$test_opts\n"; > > +$result = system( > > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $test_opts $v" > > +); > > +ok( $result eq 0 ); > > + > > +# Create file, its context will be > > system_u:object_r:test_filesystem_context_t:s0 from $test_opts > > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > > +$result = > > + system( > > +"runcon -u system_u -t test_filesystem_fscontext_t > > $basedir/create_file -f $basedir/mntpoint/mp1/test_file $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = system( > > +"runcon -t test_filesystem_context_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > +); > > +ok( $result eq 0 ); > > + > > +# Need to free the loop device, then get new dev one and attach > > +system("losetup -d $dev 2>/dev/null"); > > +get_loop_dev(); > > +attach_dev(); > > + > > +# Mount again with defcontext= > > +$defcontext_opts = > > "defcontext=system_u:object_r:test_filesystem_filecon_t:s0"; > > +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$defcontext_opts\n"; > > +$result = system( > > +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $defcontext_opts $v" > > +); > > +ok( $result eq 0 ); > > + > > +# Now check the file context is now > > system_u:object_r:test_filesystem_filecon_t:s0 > > +print "Check test file context $basedir/mntpoint/mp1/test_file\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_context_t $basedir/check_file_context > > -f $basedir/mntpoint/mp1/test_file -e > > system_u:object_r:test_filesystem_filecon_t:s0 $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_context_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +################################################################## > > ######## > > +# fscontext - Sets the overarching filesystem label to a > > specific security > > +# context. This filesystem label is separate from > > the individual > > +# labels on the files. > > +# Tested by - Mount a tmpfs (fs_use_trans) filesystem with > > fscontext= and > > +# then create a file within it, checking its > > context. > > +################################################################## > > ######## > > +$fs_type = "tmpfs"; > > +cleanup(); > > +mk_mntpoint_1(); > > +make_fs($fs_type); > > +$fscontext_opts = > > +"fscontext=system_u:object_r:test_filesystem_fscontext_t:s0,size=1 > > 0M,mode=0770"; > > + > > +print "Testing 'fscontext=' mount option\n"; > > +print "Mount tmpfs filesystem on $basedir/mntpoint/mp1\n"; > > +print "Using mount options:\n\t$fscontext_opts\n"; > > +$result = system( > > +"runcon -t test_filesystem_fscontext_t $basedir/mount -s $dev -t > > $basedir/mntpoint/mp1 -f $fs_type -o $fscontext_opts $v" > > +); > > +ok( $result eq 0 ); > > + > > +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_fscontext_t > > $basedir/create_file_change_context -t test_filesystem_filecon_t -f > > $private_path/mp1/test_file $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; > > +$result = > > + system( > > +"runcon -t test_filesystem_fscontext_t $basedir/umount -t > > $basedir/mntpoint/mp1 $v" > > + ); > > +ok( $result eq 0 ); > > + > > +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; > > +cleanup1(); > > + > > +# Cleanup any attached /dev/loop entries > > +foreach my $n (@device_list) { > > + system("$basedir/grim_reaper $n 2>/dev/null"); > > +} > > + > > +exit; > > diff --git a/tests/filesystem/umount.c b/tests/filesystem/umount.c > > new file mode 100644 > > index 0000000..4a20448 > > --- /dev/null > > +++ b/tests/filesystem/umount.c > > @@ -0,0 +1,84 @@ > > +#include <stdio.h> > > +#include <stdlib.h> > > +#include <string.h> > > +#include <unistd.h> > > +#include <errno.h> > > +#include <stdbool.h> > > +#include <sys/mount.h> > > +#include <selinux/selinux.h> > > + > > +static void print_usage(char *progname) > > +{ > > + fprintf(stderr, > > + "usage: %s [-v] [-t]\n" > > + "Where:\n\t" > > + "-t Target path\n\t" > > + "-v Print information.\n", progname); > > + exit(-1); > > +} > > + > > +#define WAIT_COUNT 60 > > +#define USLEEP_TIME 100000 > > + > > +int main(int argc, char *argv[]) > > +{ > > + char *context, *tgt = NULL; > > + int opt, result, i, save_err; > > + bool verbose = false; > > + > > + while ((opt = getopt(argc, argv, "t:v")) != -1) { > > + switch (opt) { > > + case 't': > > + tgt = optarg; > > + break; > > + case 'v': > > + verbose = true; > > + break; > > + default: > > + print_usage(argv[0]); > > + } > > + } > > + > > + if (!tgt) > > + print_usage(argv[0]); > > + > > + if (verbose) { > > + result = getcon(&context); > > + if (result < 0) { > > + fprintf(stderr, "Failed to obtain process > > context\n"); > > + exit(-1); > > + } > > + printf("Process context:\n\t%s\n", context); > > + free(context); > > + } > > + > > + /* > > + * umount(2) will sometimes return EBUSY when other tasks are > > + * checking mounts so wait around before bailing out. > > + */ > > + for (i = 0; i < WAIT_COUNT; i++) { > > + result = umount(tgt); > > + save_err = errno; > > + if (!result) { > > + if (verbose) > > + printf("Unmounted: %s\n", tgt); > > + > > + return 0; > > + } > > + > > + if (verbose && save_err == EBUSY) > > + printf("umount(2) returned EBUSY %d times\n", i > > + 1); > > + > > + if (save_err != EBUSY) { > > + fprintf(stderr, "Failed umount(2): %s\n", > > + strerror(save_err)); > > + return save_err; > > + } > > + usleep(USLEEP_TIME); > > + } > > + > > + fprintf(stderr, "Failed to umount(2) after %d retries with: > > %s\n", > > + WAIT_COUNT, strerror(save_err)); > > + > > + return save_err; > > +} > >
diff --git a/defconfig b/defconfig index 3bea332..7cb6a2c 100644 --- a/defconfig +++ b/defconfig @@ -88,3 +88,9 @@ CONFIG_TUN=m CONFIG_HAVE_PERF_EVENTS=y CONFIG_PERF_EVENTS=y CONFIG_TRACEPOINTS=y + +# Test filesystem permissions. +# This is not required for SELinux operation itself. +CONFIG_BLK_DEV_LOOP=m +CONFIG_BLK_DEV_LOOP_MIN_COUNT=0 +CONFIG_QFMT_V2=y diff --git a/policy/Makefile b/policy/Makefile index 6f1db03..30896d8 100644 --- a/policy/Makefile +++ b/policy/Makefile @@ -114,6 +114,10 @@ TARGETS += test_lockdown.te export M4PARAM += -Dlockdown_defined endif +ifeq ($(shell grep -q filesystem $(POLDEV)/include/support/all_perms.spt && echo true),true) +TARGETS += test_filesystem.te +endif + ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6)) TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te test_ibpkey.te, $(TARGETS)) endif diff --git a/policy/test_filesystem.te b/policy/test_filesystem.te new file mode 100644 index 0000000..2eee1fc --- /dev/null +++ b/policy/test_filesystem.te @@ -0,0 +1,324 @@ +# +######### Test filesystem permissions policy module ########## +# +attribute filesystemdomain; + +#################### Create a test file context ###################### +type test_filesystem_filecon_t; +unconfined_runs_test(test_filesystem_filecon_t) + +################# Test all functions ########################## +type test_filesystem_t; +domain_type(test_filesystem_t) +unconfined_runs_test(test_filesystem_t) +typeattribute test_filesystem_t testdomain; +typeattribute test_filesystem_t filesystemdomain; + +allow test_filesystem_t self:capability { sys_admin }; +allow test_filesystem_t self:filesystem { mount remount quotamod relabelfrom relabelto unmount quotaget }; +allow test_filesystem_t self:dir { mounton add_name write }; +allow test_filesystem_t test_file_t:dir { mounton write remove_name rmdir }; +# Create test file +allow test_filesystem_t self:dir { add_name write }; +allow test_filesystem_t self:file { create relabelfrom relabelto }; + +fs_mount_all_fs(test_filesystem_t) +fs_remount_all_fs(test_filesystem_t) +fs_unmount_all_fs(test_filesystem_t) +fs_relabelfrom_all_fs(test_filesystem_t) +fs_get_xattr_fs_quotas(test_filesystem_t) +files_search_all(test_filesystem_t) +# Required for mount opts "rootcontext=system_u:object_r:test_filesystem_t:s0"; +fs_associate(test_filesystem_t) +fs_getattr_xattr_fs(test_filesystem_t) + +# For running quotacheck(8) +files_type(test_filesystem_t) +# Update quotas +fs_set_all_quotas(test_filesystem_t) +allow test_filesystem_t self:file { quotaon }; +# Create test file and change context: +fs_associate(test_filesystem_filecon_t) +allow test_filesystem_t test_filesystem_filecon_t:file { open read getattr relabelto write }; +dontaudit test_filesystem_t kernel_t:process { setsched }; + +#################### Deny filesystem { getattr } ###################### +type test_filesystem_no_getattr_t; +domain_type(test_filesystem_no_getattr_t) +unconfined_runs_test(test_filesystem_no_getattr_t) +typeattribute test_filesystem_no_getattr_t testdomain; +typeattribute test_filesystem_no_getattr_t filesystemdomain; + +allow test_filesystem_no_getattr_t self:capability { sys_admin }; +fs_mount_all_fs(test_filesystem_no_getattr_t) +fs_unmount_all_fs(test_filesystem_no_getattr_t) +fs_relabelfrom_all_fs(test_filesystem_no_getattr_t) +fs_associate(test_filesystem_no_getattr_t) +allow test_filesystem_no_getattr_t self:dir { mounton }; +allow test_filesystem_no_getattr_t test_file_t:dir { mounton write remove_name rmdir }; +dontaudit test_filesystem_no_getattr_t kernel_t:process { setsched }; + +#################### Deny filesystem { remount } ###################### +type test_filesystem_no_remount_t; +domain_type(test_filesystem_no_remount_t) +unconfined_runs_test(test_filesystem_no_remount_t) +typeattribute test_filesystem_no_remount_t testdomain; +typeattribute test_filesystem_no_remount_t filesystemdomain; + +allow test_filesystem_no_remount_t self:capability { sys_admin }; +fs_mount_all_fs(test_filesystem_no_remount_t) +fs_unmount_all_fs(test_filesystem_no_remount_t) +fs_relabelfrom_all_fs(test_filesystem_no_remount_t) +fs_associate(test_filesystem_no_remount_t) +allow test_filesystem_no_remount_t self:dir { mounton }; +allow test_filesystem_no_remount_t test_file_t:dir { mounton write remove_name rmdir }; +dontaudit test_filesystem_no_remount_t kernel_t:process { setsched }; + +#################### Deny filesystem { mount } ###################### +type test_filesystem_no_mount_t; +domain_type(test_filesystem_no_mount_t) +unconfined_runs_test(test_filesystem_no_mount_t) +typeattribute test_filesystem_no_mount_t testdomain; +typeattribute test_filesystem_no_mount_t filesystemdomain; + +allow test_filesystem_no_mount_t self:capability { sys_admin }; +fs_relabelfrom_all_fs(test_filesystem_no_mount_t) +fs_associate(test_filesystem_no_mount_t) +allow test_filesystem_no_mount_t self:dir { mounton }; +allow test_filesystem_no_mount_t test_file_t:dir { mounton write remove_name rmdir }; +dontaudit test_filesystem_no_mount_t kernel_t:process { setsched }; + +#################### Deny filesystem { unmount } ###################### +type test_filesystem_no_unmount_t; +domain_type(test_filesystem_no_unmount_t) +unconfined_runs_test(test_filesystem_no_unmount_t) +typeattribute test_filesystem_no_unmount_t testdomain; +typeattribute test_filesystem_no_unmount_t filesystemdomain; + +allow test_filesystem_no_unmount_t self:capability { sys_admin }; +fs_mount_all_fs(test_filesystem_no_unmount_t) +fs_relabelfrom_all_fs(test_filesystem_no_unmount_t) +fs_associate(test_filesystem_no_unmount_t) +allow test_filesystem_no_unmount_t self:dir { mounton }; +allow test_filesystem_no_unmount_t test_file_t:dir { mounton write remove_name rmdir }; +dontaudit test_filesystem_no_unmount_t kernel_t:process { setsched }; + +#################### Deny filesystem { relabelfrom } ###################### +type test_filesystem_no_relabelfrom_t; +domain_type(test_filesystem_no_relabelfrom_t) +unconfined_runs_test(test_filesystem_no_relabelfrom_t) +typeattribute test_filesystem_no_relabelfrom_t testdomain; +typeattribute test_filesystem_no_relabelfrom_t filesystemdomain; + +allow test_filesystem_no_relabelfrom_t self:capability { sys_admin }; +fs_associate(test_filesystem_no_relabelfrom_t) +allow test_filesystem_no_relabelfrom_t self:dir { mounton }; +allow test_filesystem_no_relabelfrom_t test_file_t:dir { mounton write remove_name rmdir }; +dontaudit test_filesystem_no_relabelfrom_t kernel_t:process { setsched }; + +#################### Deny filesystem { relabelto } ###################### +type test_filesystem_no_relabelto_t; +domain_type(test_filesystem_no_relabelto_t) +unconfined_runs_test(test_filesystem_no_relabelto_t) +typeattribute test_filesystem_no_relabelto_t testdomain; +typeattribute test_filesystem_no_relabelto_t filesystemdomain; + +allow test_filesystem_no_relabelto_t self:capability { sys_admin }; +fs_mount_all_fs(test_filesystem_no_relabelto_t) +fs_relabelfrom_all_fs(test_filesystem_no_relabelto_t) +fs_associate(test_filesystem_no_relabelto_t) +allow test_filesystem_no_relabelto_t self:dir { mounton }; +allow test_filesystem_no_relabelto_t test_file_t:dir { mounton write remove_name rmdir }; +dontaudit test_filesystem_no_relabelto_t kernel_t:process { setsched }; + +#################### Deny filesystem { associate } ###################### +type test_filesystem_no_associate_t; +type test_filesystem_no_associate1_t; +domain_type(test_filesystem_no_associate_t) +unconfined_runs_test(test_filesystem_no_associate_t) +typeattribute test_filesystem_no_associate_t testdomain; +typeattribute test_filesystem_no_associate_t filesystemdomain; + +allow test_filesystem_no_associate_t self:capability { sys_admin }; +allow test_filesystem_no_associate_t self:filesystem { relabelto mount relabelfrom }; +fs_mount_all_fs(test_filesystem_no_associate_t) +fs_relabelfrom_all_fs(test_filesystem_no_associate_t) +allow test_filesystem_no_associate_t self:dir { mounton }; +allow test_filesystem_no_associate_t test_file_t:dir { mounton write remove_name rmdir }; +dontaudit test_filesystem_no_associate_t kernel_t:process { setsched }; + +########## Deny filesystem { associate } for create file ################ +type test_filesystem_no_associate_file_t; +domain_type(test_filesystem_no_associate_file_t) +unconfined_runs_test(test_filesystem_no_associate_file_t) +typeattribute test_filesystem_no_associate_file_t testdomain; +typeattribute test_filesystem_no_associate_file_t filesystemdomain; + +allow test_filesystem_no_associate_file_t self:capability { sys_admin }; +allow test_filesystem_no_associate_file_t self:filesystem { mount relabelfrom relabelto unmount associate }; +allow test_filesystem_no_associate_file_t self:dir { mounton add_name write }; +allow test_filesystem_no_associate_file_t test_file_t:dir { mounton write remove_name rmdir }; + +fs_mount_all_fs(test_filesystem_no_associate_file_t) +fs_unmount_all_fs(test_filesystem_no_associate_file_t) +fs_relabelfrom_all_fs(test_filesystem_no_associate_file_t) +fs_associate(test_filesystem_no_associate_file_t) +fs_getattr_xattr_fs(test_filesystem_no_associate_file_t) +dontaudit test_filesystem_no_associate_file_t kernel_t:process { setsched }; + +# Create test file +allow test_filesystem_no_associate_file_t self:file { create relabelfrom relabelto }; +############ hooks.c may_create() FILESYSTEM__ASSOCIATE ############# +# FOR: neverallow unlabeled_t test_filesystem_no_associate_file_t:filesystem { associate }; +allow test_filesystem_no_associate_file_t unconfined_t:file { open read write }; +allow test_filesystem_no_associate_file_t unlabeled_t:dir { add_name search write }; +allow test_filesystem_no_associate_file_t unlabeled_t:file { create open relabelfrom write }; +############ hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE ########## +# FOR: neverallow unconfined_t test_filesystem_no_associate_file_t:filesystem { associate }; +dontaudit unconfined_t test_filesystem_filecon_t:file { getattr read }; +allow test_filesystem_no_associate_file_t unconfined_t:dir { add_name write }; +allow test_filesystem_no_associate_file_t unconfined_t:file { create relabelfrom relabelto }; + +#################### Deny filesystem { quotamod } ###################### +type test_filesystem_no_quotamod_t; +domain_type(test_filesystem_no_quotamod_t) +unconfined_runs_test(test_filesystem_no_quotamod_t) +typeattribute test_filesystem_no_quotamod_t testdomain; +typeattribute test_filesystem_no_quotamod_t filesystemdomain; + +allow test_filesystem_no_quotamod_t self:capability { sys_admin }; +allow test_filesystem_no_quotamod_t self:filesystem { quotaget relabelto mount unmount}; +fs_mount_all_fs(test_filesystem_no_quotamod_t) +fs_relabelfrom_all_fs(test_filesystem_no_quotamod_t) +fs_associate(test_filesystem_no_quotamod_t) +# Required as $private_path to quota files +files_search_all(test_filesystem_no_quotamod_t) +allow test_filesystem_no_quotamod_t self:dir { mounton }; +allow test_filesystem_no_quotamod_t test_file_t:dir { mounton write remove_name rmdir }; +dontaudit test_filesystem_no_quotamod_t kernel_t:process { setsched }; + +#################### Deny filesystem { quotaget } ###################### +type test_filesystem_no_quotaget_t; +domain_type(test_filesystem_no_quotaget_t) +unconfined_runs_test(test_filesystem_no_quotaget_t) +typeattribute test_filesystem_no_quotaget_t testdomain; +typeattribute test_filesystem_no_quotaget_t filesystemdomain; + +allow test_filesystem_no_quotaget_t self:capability { sys_admin }; +allow test_filesystem_no_quotaget_t self:filesystem { quotamod relabelto mount unmount relabelfrom }; +allow test_filesystem_no_quotaget_t self:dir { mounton }; +allow test_filesystem_no_quotaget_t test_file_t:dir { mounton write remove_name rmdir }; +allow test_filesystem_no_quotaget_t self:file { quotaon }; +fs_mount_all_fs(test_filesystem_no_quotaget_t) +fs_relabelfrom_all_fs(test_filesystem_no_quotaget_t) +fs_associate(test_filesystem_no_quotaget_t) +# Required as $private_path to quota files +files_search_all(test_filesystem_no_quotaget_t) +# For running quotacheck(8) +files_type(test_filesystem_no_quotaget_t) +dontaudit test_filesystem_no_quotaget_t kernel_t:process { setsched }; + +#################### Deny filesystem { watch } ###################### +type test_filesystem_no_watch_t; +domain_type(test_filesystem_no_watch_t) +unconfined_runs_test(test_filesystem_no_watch_t) +typeattribute test_filesystem_no_watch_t testdomain; +typeattribute test_filesystem_no_watch_t filesystemdomain; + +allow test_filesystem_no_watch_t self:capability { sys_admin }; +allow test_filesystem_no_watch_t self:filesystem { associate relabelto mount unmount relabelfrom }; +allow test_filesystem_no_watch_t self:dir { mounton }; +allow test_filesystem_no_watch_t test_file_t:dir { mounton write remove_name rmdir }; +fs_mount_all_fs(test_filesystem_no_watch_t) +fs_relabelfrom_all_fs(test_filesystem_no_watch_t) +fs_associate(test_filesystem_no_watch_t) +dontaudit test_filesystem_no_watch_t kernel_t:process { setsched }; + +################# Test process { setfscreate } ############# +type test_setfscreatecon_t; +domain_type(test_setfscreatecon_t) +unconfined_runs_test(test_setfscreatecon_t) +typeattribute test_setfscreatecon_t testdomain; +typeattribute test_setfscreatecon_t filesystemdomain; + +allow test_setfscreatecon_t self:capability { sys_admin }; +allow test_setfscreatecon_t self:process { setfscreate }; + +# Set new context on fs: +type test_setfscreatecon_newcon_t; +domain_type(test_setfscreatecon_newcon_t) +typeattribute test_setfscreatecon_newcon_t testdomain; + +################# deny process { setfscreate } ############# +type test_no_setfscreatecon_t; +domain_type(test_no_setfscreatecon_t) +unconfined_runs_test(test_no_setfscreatecon_t) +typeattribute test_no_setfscreatecon_t testdomain; +typeattribute test_no_setfscreatecon_t filesystemdomain; + +allow test_no_setfscreatecon_t self:capability { sys_admin }; +# neverallow test_no_setfscreatecon_t self:process { setfscreate }; + +################# Test fscontext= ########################## +type test_filesystem_fscontext_t; +domain_type(test_filesystem_fscontext_t) +unconfined_runs_test(test_filesystem_fscontext_t) +typeattribute test_filesystem_fscontext_t testdomain; +typeattribute test_filesystem_fscontext_t filesystemdomain; + +allow test_filesystem_fscontext_t self:capability { sys_admin }; +allow test_filesystem_fscontext_t self:filesystem { associate mount relabelfrom relabelto unmount }; +allow test_filesystem_fscontext_t self:dir { mounton add_name write }; +allow test_filesystem_fscontext_t test_file_t:dir { mounton write remove_name rmdir }; +# Create test file +allow test_filesystem_fscontext_t self:dir { add_name write }; +allow test_filesystem_fscontext_t self:file { create relabelfrom relabelto }; +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { relabelto }; +allow test_filesystem_filecon_t test_filesystem_fscontext_t:filesystem { associate }; +allow test_filesystem_fscontext_t test_filesystem_filecon_t:file { open getattr read write }; + +fs_mount_all_fs(test_filesystem_fscontext_t) +fs_unmount_all_fs(test_filesystem_fscontext_t) +fs_relabelfrom_all_fs(test_filesystem_fscontext_t) +files_search_all(test_filesystem_fscontext_t) + +########### Test context=, rootcontext= and defcontext ################# +type test_filesystem_context_t; +domain_type(test_filesystem_context_t) +unconfined_runs_test(test_filesystem_context_t) +typeattribute test_filesystem_context_t testdomain; +typeattribute test_filesystem_context_t filesystemdomain; + +allow test_filesystem_context_t self:capability { sys_admin }; +allow test_filesystem_context_t self:filesystem { associate mount relabelfrom relabelto unmount }; +allow test_filesystem_context_t self:dir { mounton add_name write }; +allow test_filesystem_context_t test_file_t:dir { mounton write remove_name rmdir }; +# Create test file +allow test_filesystem_context_t self:dir { add_name write }; +allow test_filesystem_context_t self:file { create relabelfrom relabelto }; +allow test_filesystem_context_t test_filesystem_filecon_t:file { open getattr read write relabelto }; +allow test_filesystem_filecon_t test_filesystem_context_t:filesystem { associate }; + +fs_mount_all_fs(test_filesystem_context_t) +fs_unmount_all_fs(test_filesystem_context_t) +fs_relabelfrom_all_fs(test_filesystem_context_t) +files_search_all(test_filesystem_context_t) +fs_associate(test_filesystem_context_t) +allow test_filesystem_context_t test_file_t:dir { add_name }; +dontaudit test_filesystem_context_t kernel_t:process { setsched }; + +# For testing rootcontext= Set mountpoint to unlabeled first +allow test_filesystem_context_t test_file_t:dir { relabelfrom }; +allow test_filesystem_context_t unlabeled_t:dir { mounton relabelto }; + +# For testing defcontext= +allow test_filesystem_context_t test_filesystem_filecon_t:dir { search }; +allow test_filesystem_fscontext_t test_filesystem_context_t:dir { add_name search write }; +allow test_filesystem_fscontext_t test_filesystem_context_t:file { create getattr open write }; +dontaudit unconfined_t test_filesystem_filecon_t:dir { read search }; + +# +########### Allow these domains to be entered from sysadm domain ############ +# +miscfiles_domain_entry_test_files(filesystemdomain) +userdom_sysadm_entry_spec_domtrans_to(filesystemdomain) diff --git a/tests/Makefile b/tests/Makefile index e19ea2f..a1478f1 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -91,6 +91,13 @@ ifeq ($(shell grep -q lockdown $(POLDEV)/include/support/all_perms.spt && echo t SUBDIRS += lockdown endif +ifeq ($(shell grep -q filesystem $(POLDEV)/include/support/all_perms.spt && echo true),true) +SUBDIRS += filesystem +ifeq ($(shell grep -q all_filesystem_perms.*watch $(POLDEV)/include/support/all_perms.spt && echo true),true) +export CFLAGS += -DHAVE_FS_WATCH_PERM +endif +endif + ifeq ($(DISTRO),RHEL4) SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp_nosuid overlay unix_socket, $(SUBDIRS)) endif diff --git a/tests/filesystem/.gitignore b/tests/filesystem/.gitignore new file mode 100644 index 0000000..5ac18d0 --- /dev/null +++ b/tests/filesystem/.gitignore @@ -0,0 +1,11 @@ +mount +umount +quotas_test +statfs_test +fanotify_fs +create_file_change_context +fs_relabel +check_file_context +check_mount_context +create_file +grim_reaper diff --git a/tests/filesystem/Makefile b/tests/filesystem/Makefile new file mode 100644 index 0000000..d2fad63 --- /dev/null +++ b/tests/filesystem/Makefile @@ -0,0 +1,16 @@ +# Required for local building +#export CFLAGS += -DHAVE_FS_WATCH_PERM + +TARGETS = mount umount quotas_test statfs_test create_file_change_context \ +fs_relabel check_file_context grim_reaper check_mount_context create_file + +LDLIBS += -lselinux + +ifneq (,$(findstring -DHAVE_FS_WATCH_PERM,$(CFLAGS))) + TARGETS += fanotify_fs +endif + +all: $(TARGETS) + +clean: + rm -f $(TARGETS) diff --git a/tests/filesystem/check_file_context.c b/tests/filesystem/check_file_context.c new file mode 100644 index 0000000..1380f16 --- /dev/null +++ b/tests/filesystem/check_file_context.c @@ -0,0 +1,75 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <linux/unistd.h> +#include <selinux/selinux.h> + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] -f -e -n\n" + "Where:\n\t" + "-f File to check its context\n\t" + "-e Expected context\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char **argv) +{ + int opt, result, fd; + char *context = NULL, *expected = NULL, *file = NULL; + bool verbose = false; + + while ((opt = getopt(argc, argv, "f:e:v")) != -1) { + switch (opt) { + case 'f': + file = optarg; + break; + case 'e': + expected = optarg; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!file || !expected) + print_usage(argv[0]); + + fd = open(file, O_RDWR); + if (fd < 0) { + fprintf(stderr, "open(2) Failed: %s\n", strerror(errno)); + return -1; + } + + result = fgetfilecon(fd, &context); + if (result < 0) { + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", + strerror(errno)); + result = -1; + goto err; + } + result = 0; + + if (strcmp(expected, context)) { + fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n", + expected, context); + result = -1; + } else { + if (verbose) + printf("Pass - File contexts match: %s\n", context); + } +err: + free(context); + close(fd); + + return result; +} diff --git a/tests/filesystem/check_mount_context.c b/tests/filesystem/check_mount_context.c new file mode 100644 index 0000000..dbe0fb8 --- /dev/null +++ b/tests/filesystem/check_mount_context.c @@ -0,0 +1,109 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <linux/unistd.h> +#include <selinux/selinux.h> +#include <selinux/context.h> + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] -m [-e] -r\n" + "Where:\n\t" + "-m Mountpoint\n\t" + "-e Expected MP context\n\t" + "-r Reset MP context to 'unlabeled_t'\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char **argv) +{ + int opt, result, save_err; + char *context = NULL, *expected = NULL, *mount = NULL, *newcon = NULL; + bool verbose = false, reset = false; + const char *type = "unlabeled_t"; + context_t con_t; + + while ((opt = getopt(argc, argv, "m:e:rv")) != -1) { + switch (opt) { + case 'm': + mount = optarg; + break; + case 'e': + expected = optarg; + break; + case 'r': + reset = true; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!mount) + print_usage(argv[0]); + + result = getfilecon(mount, &context); + if (result < 0) { + fprintf(stderr, "getfilecon(3) Failed: %s\n", strerror(errno)); + result = -1; + goto err; + } + if (verbose) + printf("Current MP context: %s\n", context); + + result = 0; + + if (reset) { + /* Set context to unlabeled_t */ + con_t = context_new(context); + if (!con_t) { + fprintf(stderr, "Unable to create context structure\n"); + exit(-1); + } + + if (context_type_set(con_t, type)) { + fprintf(stderr, "Unable to set new type\n"); + exit(-1); + } + + newcon = context_str(con_t); + if (!newcon) { + fprintf(stderr, "Unable to obtain new context string\n"); + exit(-1); + } + + result = setfilecon(mount, newcon); + save_err = errno; + if (result < 0) { + fprintf(stderr, "setfilecon(3) Failed: %s\n", + strerror(errno)); + result = save_err; + goto err; + } + if (verbose) + printf("Set new MP context: %s\n", newcon); + } else { + if (strcmp(expected, context)) { + fprintf(stderr, "Mount context error, expected:\n\t%s\ngot:\n\t%s\n", + expected, context); + result = -1; + } else { + if (verbose) + printf("Pass - Mountpoint contexts match: %s\n", + context); + } + } + +err: + free(context); + return result; +} diff --git a/tests/filesystem/create_file.c b/tests/filesystem/create_file.c new file mode 100644 index 0000000..3d73067 --- /dev/null +++ b/tests/filesystem/create_file.c @@ -0,0 +1,79 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <sys/types.h> +#include <linux/unistd.h> +#include <selinux/selinux.h> + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] -f\n" + "Where:\n\t" + "-f File to create\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char **argv) +{ + int opt, result, fd, save_err; + char *context, *file = NULL; + bool verbose = false; + + while ((opt = getopt(argc, argv, "f:v")) != -1) { + switch (opt) { + case 'f': + file = optarg; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!file) + print_usage(argv[0]); + + if (verbose) { + result = getcon(&context); + if (result < 0) { + fprintf(stderr, "Failed to obtain process context\n"); + exit(-1); + } + printf("Process context:\n\t%s\n", context); + free(context); + } + + fd = creat(file, O_RDWR); + save_err = errno; + if (fd < 0) { + fprintf(stderr, "creat(2) Failed: %s\n", strerror(errno)); + return save_err; + } + + context = NULL; + result = fgetfilecon(fd, &context); + if (result < 0) { + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", + strerror(errno)); + result = -1; + goto err; + } + result = 0; + + if (verbose) + printf("File context is: %s\n", context); + +err: + free(context); + close(fd); + + return result; +} diff --git a/tests/filesystem/create_file_change_context.c b/tests/filesystem/create_file_change_context.c new file mode 100644 index 0000000..2a3b995 --- /dev/null +++ b/tests/filesystem/create_file_change_context.c @@ -0,0 +1,143 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <linux/unistd.h> +#include <selinux/selinux.h> +#include <selinux/context.h> + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] -t -f\n" + "Where:\n\t" + "-t Type for context of created file\n\t" + "-f File to create\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char **argv) +{ + int opt, result, fd, save_err; + char *context, *newfcon, *orgfcon, *type = NULL, *file = NULL; + bool verbose = false; + context_t con_t; + + while ((opt = getopt(argc, argv, "t:f:v")) != -1) { + switch (opt) { + case 't': + type = optarg; + break; + case 'f': + file = optarg; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!type || !file) + print_usage(argv[0]); + + result = getcon(&context); + if (result < 0) { + fprintf(stderr, "Failed to obtain process context\n"); + exit(-1); + } + + /* Build new file context */ + con_t = context_new(context); + if (!con_t) { + fprintf(stderr, "Unable to create context structure\n"); + exit(-1); + } + + if (context_type_set(con_t, type)) { + fprintf(stderr, "Unable to set new type\n"); + exit(-1); + } + + newfcon = context_str(con_t); + if (!newfcon) { + fprintf(stderr, "Unable to obtain new context string\n"); + exit(-1); + } + + if (verbose) { + printf("Process context:\n\t%s\n", context); + printf("is creating test file:\n\t%s\n", file); + printf("and changing its context to:\n\t%s\n", newfcon); + } + + free(context); + context = NULL; + + /* hooks.c may_create() FILESYSTEM__ASSOCIATE */ + fd = creat(file, O_RDWR); + save_err = errno; + if (fd < 0) { + fprintf(stderr, "creat(2) Failed: %s\n", strerror(errno)); + result = save_err; + goto err; + } + + result = fgetfilecon(fd, &orgfcon); + if (result < 0) { + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", + strerror(errno)); + result = -1; + goto err; + } + + if (verbose) + printf("Current test file context is: %s\n", orgfcon); + + free(orgfcon); + + /* hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE */ + result = fsetfilecon(fd, newfcon); + save_err = errno; + if (result < 0) { + fprintf(stderr, "fsetfilecon(3) Failed: %s\n", + strerror(errno)); + result = save_err; + goto err; + } + + fd = open(file, O_RDWR); + if (fd < 0) { + fprintf(stderr, "open(2) Failed: %s\n", strerror(errno)); + result = -1; + } + + result = fgetfilecon(fd, &context); + if (result < 0) { + fprintf(stderr, "fgetfilecon(3) Failed: %s\n", + strerror(errno)); + result = -1; + goto err; + } + + if (verbose) + printf("New test file context is: %s\n", context); + + result = 0; + if (strcmp(newfcon, context)) { + fprintf(stderr, "File context error, expected:\n\t%s\ngot:\n\t%s\n", + newfcon, context); + result = -1; + } +err: + free(context); + free(newfcon); + close(fd); + + return result; +} diff --git a/tests/filesystem/fanotify_fs.c b/tests/filesystem/fanotify_fs.c new file mode 100644 index 0000000..1f8f165 --- /dev/null +++ b/tests/filesystem/fanotify_fs.c @@ -0,0 +1,79 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <stdbool.h> +#include <sys/fanotify.h> +#include <selinux/selinux.h> + +#ifndef FAN_MARK_FILESYSTEM +#define FAN_MARK_FILESYSTEM 0x00000100 +#endif + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] -t\n" + "Where:\n\t" + "-t Target path\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char *argv[]) +{ + int mask = FAN_OPEN, flags = FAN_MARK_ADD | FAN_MARK_FILESYSTEM; + int fd, result, opt, save_err; + char *context, *tgt = NULL; + bool verbose = false; + + while ((opt = getopt(argc, argv, "t:v")) != -1) { + switch (opt) { + case 't': + tgt = optarg; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!tgt) + print_usage(argv[0]); + + if (verbose) { + result = getcon(&context); + if (result < 0) { + fprintf(stderr, "Failed to obtain process context\n"); + exit(-1); + } + printf("Process context:\n\t%s\n", context); + free(context); + } + + fd = fanotify_init(FAN_CLASS_CONTENT, O_RDWR); + if (fd < 0) { + fprintf(stderr, "fanotify_init(2) Failed: %s\n", + strerror(errno)); + exit(-1); + } + + result = fanotify_mark(fd, flags, mask, AT_FDCWD, tgt); + save_err = errno; + if (result < 0) { + fprintf(stderr, "fanotify_mark(2) Failed: %s\n", + strerror(errno)); + close(fd); + return save_err; + } + + if (verbose) + printf("Set fanotify_mark(2) on filesystem: %s\n", tgt); + + close(fd); + return 0; +} diff --git a/tests/filesystem/fs_relabel.c b/tests/filesystem/fs_relabel.c new file mode 100644 index 0000000..25b1781 --- /dev/null +++ b/tests/filesystem/fs_relabel.c @@ -0,0 +1,72 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <linux/unistd.h> +#include <selinux/selinux.h> + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] -n\n" + "Where:\n\t" + "-n New fs context\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char **argv) +{ + int opt, result, save_err; + char *context, *fscreate_con, *newcon = NULL; + bool verbose = false; + + while ((opt = getopt(argc, argv, "n:v")) != -1) { + switch (opt) { + case 'n': + newcon = optarg; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!newcon) + print_usage(argv[0]); + + if (verbose) { + result = getcon(&context); + if (result < 0) { + fprintf(stderr, "Failed to obtain process context\n"); + exit(-1); + } + printf("Process context:\n\t%s\n", context); + free(context); + } + + result = setfscreatecon(newcon); + save_err = errno; + if (result < 0) { + fprintf(stderr, "Failed setfscreatecon(3): %s\n", + strerror(errno)); + return save_err; + } + + result = getfscreatecon(&fscreate_con); + if (result < 0) { + fprintf(stderr, "Failed getfscreatecon(3): %s\n", + strerror(errno)); + exit(-1); + } + if (verbose) + printf("New fscreate context: %s\n", fscreate_con); + + free(fscreate_con); + return 0; +} diff --git a/tests/filesystem/grim_reaper.c b/tests/filesystem/grim_reaper.c new file mode 100644 index 0000000..0105ab6 --- /dev/null +++ b/tests/filesystem/grim_reaper.c @@ -0,0 +1,63 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <stdbool.h> +#include <sys/mount.h> +#include <selinux/selinux.h> + +#define WAIT_COUNT 60 +#define USLEEP_TIME 10000 + +/* Remove any mounts associated with the loop device in argv[1] */ +int main(int argc, char *argv[]) +{ + FILE *fp; + size_t len; + ssize_t num; + int index = 0, i, result = 0; + char *mount_info[2]; + char *buf = NULL, *item; + + if (!argv[1]) + return -1; + + fp = fopen("/proc/mounts", "re"); + if (!fp) { + fprintf(stderr, "Failed to open /proc/mounts: %s\n", + strerror(errno)); + return -1; + } + + while ((num = getline(&buf, &len, fp)) != -1) { + index = 0; + item = strtok(buf, " "); + while (item != NULL) { + mount_info[index] = item; + index++; + if (index == 2) + break; + item = strtok(NULL, " "); + } + + if (strcmp(mount_info[0], argv[1]) == 0) { + for (i = 0; i < WAIT_COUNT; i++) { + result = umount(mount_info[1]); + if (!result) + break; + + if (errno != EBUSY) { + fprintf(stderr, "Failed umount(2): %s\n", + strerror(errno)); + break; + } + usleep(USLEEP_TIME); + } + } + } + + free(buf); + fclose(fp); + return result; +} diff --git a/tests/filesystem/mount.c b/tests/filesystem/mount.c new file mode 100644 index 0000000..034f0ec --- /dev/null +++ b/tests/filesystem/mount.c @@ -0,0 +1,130 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <stdbool.h> +#include <sys/mount.h> +#include <selinux/selinux.h> + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-s src] -t tgt [-f fs_type] [-o options] [-bmprv]\n" + "Where:\n\t" + "-s Source path\n\t" + "-t Target path\n\t" + "-f Filesystem type\n\t" + "-o Options list (comma separated list)\n\t" + "Zero or one of the following flags:\n\t" + "\t-b MS_BIND\n\t" + "\t-m MS_MOVE\n\t" + "\t-p MS_PRIVATE\n\t" + "\t-r MS_REMOUNT\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +static int ck_mount(char *mntpoint) +{ + int result = 0; + FILE *fp; + size_t len; + ssize_t num; + char *buf = NULL; + + fp = fopen("/proc/mounts", "re"); + if (fp == NULL) { + fprintf(stderr, "Failed to open /proc/mounts: %s\n", + strerror(errno)); + return -1; + } + + while ((num = getline(&buf, &len, fp)) != -1) { + if (strstr(buf, mntpoint) != NULL) { + result = 1; + break; + } + } + + free(buf); + fclose(fp); + return result; +} + +int main(int argc, char *argv[]) +{ + int opt, result, save_err, flags = 0; + char *context, *src = NULL, *tgt = NULL, *fs_type = NULL, *opts = NULL; + bool verbose = false; + + while ((opt = getopt(argc, argv, "s:t:f:o:pbmrv")) != -1) { + switch (opt) { + case 's': + src = optarg; + break; + case 't': + tgt = optarg; + break; + case 'f': + fs_type = optarg; + break; + case 'o': + opts = optarg; + break; + case 'b': + flags = MS_BIND; + break; + case 'p': + flags = MS_PRIVATE; + break; + case 'm': + flags = MS_MOVE; + break; + case 'r': + flags = MS_REMOUNT; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!tgt) + print_usage(argv[0]); + + if (verbose) { + result = getcon(&context); + if (result < 0) { + fprintf(stderr, "Failed to obtain process context\n"); + return -1; + } + printf("Process context:\n\t%s\n", context); + free(context); + } + + if (verbose) + printf("Mounting\n\tsrc: %s\n\ttgt: %s\n\tfs_type: %s flags: 0x%x\n\topts: %s\n", + src, tgt, fs_type, flags, opts); + + result = mount(src, tgt, fs_type, flags, opts); + save_err = errno; + if (result < 0) { + fprintf(stderr, "Failed mount(2): %s\n", strerror(errno)); + return save_err; + } + + if (flags == MS_MOVE) { + if (!ck_mount(src) && ck_mount(tgt)) { + if (verbose) + printf("MS_MOVE: Moved mountpoint\n"); + } else { + fprintf(stderr, "MS_MOVE: Move mountpoint failed\n"); + return -1; + } + } + + return 0; +} diff --git a/tests/filesystem/quotas_test.c b/tests/filesystem/quotas_test.c new file mode 100644 index 0000000..34aaca9 --- /dev/null +++ b/tests/filesystem/quotas_test.c @@ -0,0 +1,134 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <stdbool.h> +#include <sys/quota.h> +#include <selinux/selinux.h> + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s -s src -t tgt\n" + "Where:\n\t" + "-s Source path (e.g. /dev/loop0)\n\t" + "-t Target quota file (Full path with either 'aquota.user'\n\t" + " or 'aquota.group' appended)\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char *argv[]) +{ + int opt, result, qcmd, save_err, test_id = geteuid(); + char *context, *src = NULL, *tgt = NULL; + bool verbose = false; + char fmt_buf[2]; + + while ((opt = getopt(argc, argv, "s:t:v")) != -1) { + switch (opt) { + case 's': + src = optarg; + break; + case 't': + tgt = optarg; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!src || !tgt) + print_usage(argv[0]); + + if (verbose) { + result = getcon(&context); + if (result < 0) { + fprintf(stderr, "Failed to obtain process context\n"); + return -1; + } + printf("Process context:\n\t%s\n", context); + free(context); + } + + if (strstr(tgt, "aquota.user") != NULL) { + qcmd = QCMD(Q_QUOTAON, USRQUOTA); + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); + save_err = errno; + if (result < 0) { + fprintf(stderr, "quotactl(Q_QUOTAON, USRQUOTA) Failed: %s\n", + strerror(errno)); + return save_err; + } + if (verbose) + printf("User Quota - ON\n"); + + qcmd = QCMD(Q_GETFMT, USRQUOTA); + result = quotactl(qcmd, src, test_id, fmt_buf); + save_err = errno; + if (result < 0) { + fprintf(stderr, "quotactl(Q_GETFMT, USRQUOTA) Failed: %s\n", + strerror(errno)); + return save_err; + } + if (verbose) + printf("User Format: 0x%x\n", fmt_buf[0]); + + qcmd = QCMD(Q_QUOTAOFF, USRQUOTA); + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); + save_err = errno; + if (result < 0) { + fprintf(stderr, "quotactl(Q_QUOTAOFF, USRQUOTA) Failed: %s\n", + strerror(errno)); + return save_err; + } + if (verbose) + printf("User Quota - OFF\n"); + + return 0; + + } else if (strstr(tgt, "aquota.group") != NULL) { + qcmd = QCMD(Q_QUOTAON, GRPQUOTA); + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); + save_err = errno; + if (result < 0) { + fprintf(stderr, "quotactl(Q_QUOTAON, GRPQUOTA) Failed: %s\n", + strerror(errno)); + return save_err; + } + if (verbose) + printf("Group Quota - ON\n"); + + qcmd = QCMD(Q_GETFMT, GRPQUOTA); + result = quotactl(qcmd, src, test_id, fmt_buf); + save_err = errno; + if (result < 0) { + fprintf(stderr, "quotactl(Q_GETFMT, GRPQUOTA) Failed: %s\n", + strerror(errno)); + return save_err; + } + if (verbose) + printf("Group Format: 0x%x\n", fmt_buf[0]); + + qcmd = QCMD(Q_QUOTAOFF, GRPQUOTA); + result = quotactl(qcmd, src, QFMT_VFS_V0, tgt); + save_err = errno; + if (result < 0) { + fprintf(stderr, "quotactl(Q_QUOTAOFF, GRPQUOTA) Failed: %s\n", + strerror(errno)); + return save_err; + } + if (verbose) + printf("Group Quota - OFF\n"); + + return 0; + } + + fprintf(stderr, "Required %s to specify 'aquota.user' or 'aquota.group' file\n", + tgt); + return -1; +} diff --git a/tests/filesystem/statfs_test.c b/tests/filesystem/statfs_test.c new file mode 100644 index 0000000..5de49b1 --- /dev/null +++ b/tests/filesystem/statfs_test.c @@ -0,0 +1,65 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <stdbool.h> +#include <sys/statfs.h> +#include <selinux/selinux.h> + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] -t\n" + "Where:\n\t" + "-t Target path\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +int main(int argc, char *argv[]) +{ + int opt, result, save_err; + char *context, *tgt = NULL; + bool verbose = false; + struct statfs statfs_t; + + while ((opt = getopt(argc, argv, "t:v")) != -1) { + switch (opt) { + case 't': + tgt = optarg; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!tgt) + print_usage(argv[0]); + + if (verbose) { + result = getcon(&context); + if (result < 0) { + fprintf(stderr, "Failed to obtain process context\n"); + return -1; + } + printf("Process context:\n\t%s\n", context); + free(context); + } + + result = statfs(tgt, &statfs_t); + save_err = errno; + if (result < 0) { + fprintf(stderr, "statfs(2) Failed: %s\n", strerror(errno)); + return save_err; + } + + if (verbose) + printf("statfs(2) returned magic filesystem: 0x%lx\n", + statfs_t.f_type); + + return 0; +} diff --git a/tests/filesystem/test b/tests/filesystem/test new file mode 100755 index 0000000..00c69e1 --- /dev/null +++ b/tests/filesystem/test @@ -0,0 +1,830 @@ +#!/usr/bin/perl +use Test::More; + +BEGIN { + $basedir = $0; + $basedir =~ s|(.*)/[^/]*|$1|; + + $test_count = 63; + + # Allow info to be shown. + $v = $ARGV[0]; + if ($v) { + if ( $v ne "-v" ) { + plan skip_all => "Invalid option (use -v)"; + } + } + else { + $v = " "; + } + + # From kernel 5.5 support for fanotify(7) with filesystem { watch } + $kvercur = `uname -r`; + chomp($kvercur); + $kverminstream = "5.5"; + + $result = `$basedir/../kvercmp $kvercur $kverminstream`; + if ( $result > 0 && -e "$basedir/fanotify_fs" ) { + $test_watch = 1; + $test_count += 4; + } + + plan tests => $test_count; +} + +# mount(2) MS_BIND | MS_PRIVATE requires an absolute path to a private mount +# point before MS_MOVE +$cwd = `pwd 2>/dev/null`; +chomp($cwd); +$private_path = "$cwd"; +if ( $basedir eq "." ) { + $private_path = "$cwd/mntpoint"; +} +else { + $private_path = "$cwd/$basedir/mntpoint"; +} + +# Set initial filesystem type +$fs_type = "ext4"; + +# For list of devices used +$device_count = 0; + +sub get_loop_dev { + print "Finding free /dev/loop entry\n"; + $dev = `losetup -f 2>/dev/null`; + chomp($dev); + if ( $dev eq "" ) { + print "losetup failed to obtain /dev/loop entry\n"; + cleanup(); + exit -1; + } + + # Keep list of devices for cleanup later + if ( $device_count eq 0 ) { + $device_list[$device_count] = $dev; + $device_count += 1; + } + elsif ( $dev ne $device_list[ $device_count - 1 ] ) { + $device_list[$device_count] = $dev; + $device_count += 1; + } +} + +sub attach_dev { + print "Attaching $basedir/fstest to $dev\n"; + $result = system("losetup $dev $basedir/fstest 2>/dev/null"); + if ( $result != 0 ) { + print "Failed to attach $basedir/fstest to $dev\n"; + cleanup(); + exit -1; + } +} + +sub make_fs { + my ($mk_type) = @_; + + get_loop_dev(); + + if ( $mk_type eq "tmpfs" ) { + return; + } + + print "Create $basedir/fstest with dd\n"; + $result = system( + "dd if=/dev/zero of=$basedir/fstest bs=1024 count=10240 2>/dev/null"); + if ( $result != 0 ) { + print "dd failed to create fstest\n"; + exit -1; + } + + attach_dev(); + + print "Make $mk_type filesystem on $dev\n"; + $result = system("mkfs.$mk_type $dev >& /dev/null"); + if ( $result != 0 ) { + system("losetup -d $dev 2>/dev/null"); + cleanup(); + print "mkfs.$mk_type failed to create filesystem on $dev\n"; + exit -1; + } +} + +sub mk_mntpoint_1 { + system("rm -rf $private_path/mp1 2>/dev/null"); + system("mkdir -p $private_path/mp1 2>/dev/null"); +} + +sub mk_mntpoint_2 { + system("rm -rf $private_path/mp2 2>/dev/null"); + system("mkdir -p $private_path/mp2 2>/dev/null"); +} + +sub cleanup { + system("rm -rf $basedir/fstest 2>/dev/null"); + system("rm -rf $basedir/mntpoint 2>/dev/null"); +} + +sub cleanup1 { + system("losetup -d $dev 2>/dev/null"); + system("rm -rf $basedir/fstest 2>/dev/null"); + system("rm -rf $basedir/mntpoint 2>/dev/null"); +} + +############### Test setfscreatecon(3) ########################## +print "Test setfscreatecon(3)\n"; +$result = system +"runcon -t test_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0"; +ok( $result eq 0 ); + +$result = system +"runcon -t test_no_setfscreatecon_t $basedir/fs_relabel $v -n system_u:system_r:test_setfscreatecon_newcon_t:s0 2>&1"; +ok( $result >> 8 eq 13 ); + +############### Test Basic Mount/Unmount ########################## +cleanup(); +mk_mntpoint_1(); +make_fs($fs_type); +$mount_opts1 = + "quota,usrquota,grpquota,defcontext=system_u:object_r:test_filesystem_t:s0"; + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$mount_opts1\n"; +$result = system( +"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v" +); +ok( $result eq 0 ); + +print "Then remount\n"; +$result = system( +"runcon -t test_filesystem_t $basedir/mount -r -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts1 $v" +); +ok( $result eq 0 ); + +print "Running quotacheck(8) to init user/group quota files\n"; +$result = system("quotacheck -ugF vfsv0 $private_path/mp1"); +ok( $result eq 0 ); + +print "Toggle User & Group quotas on/off\n"; +$result = system( +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v" +); +ok( $result eq 0 ); +$result = system( +"runcon -t test_filesystem_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.group $v" +); +ok( $result eq 0 ); + +print "Get statfs(2)\n"; +$result = + system( + "runcon -t test_filesystem_t $basedir/statfs_test -t $basedir/mntpoint $v"); +ok( $result eq 0 ); + +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; +$result = + system( +"runcon -t test_filesystem_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v" + ); +ok( $result eq 0 ); + +if ($test_watch) { + print "fanotify(7) test\n"; + $result = system( +"runcon -t test_filesystem_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1" + ); + ok( $result eq 0 ); +} + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = + system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp1 $v"); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Test Move Mount ########################## +make_fs($fs_type); +$mount_opts2 = + "quota,usrquota,grpquota,rootcontext=system_u:object_r:test_filesystem_t:s0"; +system("mkdir -p $private_path 2>/dev/null"); + +print "Set mount MS_BIND on filesystem\n"; +$result = system( +"runcon -t test_filesystem_t $basedir/mount -s $private_path -t $private_path -b $v" +); +ok( $result eq 0 ); + +print "Set mount MS_PRIVATE on filesystem\n"; +$result = + system("runcon -t test_filesystem_t $basedir/mount -t $private_path -p $v"); +ok( $result eq 0 ); + +mk_mntpoint_1(); +mk_mntpoint_2(); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$mount_opts2\n"; +$result = system( +"runcon -t test_filesystem_t $basedir/mount -s $dev -t $private_path/mp1 -f $fs_type -o $mount_opts2 $v" +); +ok( $result eq 0 ); + +print "Set mount MS_MOVE on filesystem\n"; +$result = system( +"runcon -t test_filesystem_t $basedir/mount -s $private_path/mp1 -t $private_path/mp2 -m $v" +); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp2\n"; +$result = + system("runcon -t test_filesystem_t $basedir/umount -t $private_path/mp2 $v"); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint\n"; +$result = + system("runcon -t test_filesystem_t $basedir/umount -t $private_path $v"); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { relabelfrom } ########################## +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELFROM + +$opts_no_relabelfrom = +"defcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0,fscontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0"; +mk_mntpoint_1(); +make_fs($fs_type); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_relabelfrom\n"; +$result = system( +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1" +); +ok( $result >> 8 eq 13 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { relabelto } ########################## +# hooks.c may_context_mount_sb_relabel() FILESYSTEM__RELABELTO + +$opts_no_relabelto = + "fscontext=system_u:object_r:test_filesystem_no_relabelto_t:s0"; +mk_mntpoint_1(); +make_fs($fs_type); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_relabelto\n"; +$result = system( +"runcon -t test_filesystem_no_relabelto_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelto $v 2>&1" +); +ok( $result >> 8 eq 13 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { relabelfrom } ########################## +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__RELABELFROM + +$opts_no_relabelfrom = + "rootcontext=system_u:object_r:test_filesystem_no_relabelfrom_t:s0"; +mk_mntpoint_1(); +make_fs($fs_type); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_relabelfrom\n"; +$result = system( +"runcon -t test_filesystem_no_relabelfrom_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_relabelfrom $v 2>&1" +); +ok( $result >> 8 eq 13 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { associate } ########################## +# hooks.c may_context_mount_inode_relabel() FILESYSTEM__ASSOCIATE + +$opts_no_associate = +"defcontext=system_u:object_r:test_filesystem_no_associate_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_t:s0"; +mk_mntpoint_1(); +make_fs($fs_type); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_associate\n"; +$result = system( +"runcon -t test_filesystem_no_associate_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate $v 2>&1" +); +ok( $result >> 8 eq 13 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { associate } ########################## +# hooks.c may_create() FILESYSTEM__ASSOCIATE +cleanup(); +mk_mntpoint_1(); +make_fs($fs_type); +$opts_no_associate_file = + "fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0"; + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_associate_file\n"; +$result = system( +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v" +); +ok( $result eq 0 ); + +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; +$result = + system( +"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1" + ); +ok( $result >> 8 eq 13 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = + system( +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v" + ); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { quotamod } ########################## +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAMOD + +$opts_no_quotamod = +"quota,usrquota,grpquota,fscontext=system_u:object_r:test_filesystem_no_quotamod_t:s0"; +mk_mntpoint_1(); +make_fs($fs_type); +system("mkdir -p $private_path 2>/dev/null"); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_quotamod\n"; +$result = system( +"runcon -t test_filesystem_no_quotamod_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotamod $v 2>&1" +); +ok( $result eq 0 ); + +# No need to run quotacheck(8) as never gets far enough to read quota file +print "Toggle User & Group quotas on/off\n"; # Must have full path +$result = system( +"runcon -t test_filesystem_no_quotamod_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1" +); +ok( $result >> 8 eq 13 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_no_quotamod_t $basedir/umount -t $basedir/mntpoint/mp1 $v" +); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { quotaget } ########################## +# hooks.c selinux_quotactl() FILESYSTEM__QUOTAGET + +$opts_no_quotaget = +"quota,usrquota,grpquota,context=system_u:object_r:test_filesystem_no_quotaget_t:s0"; +mk_mntpoint_1(); +make_fs($fs_type); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_quotaget\n"; +$result = system( +"runcon -t test_filesystem_no_quotaget_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_quotaget $v" +); +ok( $result eq 0 ); + +print "Running quotacheck(8) to init user/group quota files\n"; +$result = system("quotacheck -ugF vfsv0 $private_path/mp1"); +ok( $result eq 0 ); + +print "Toggle User & Group quotas on/off\n"; # Must have full path +$result = system( +"runcon -t test_filesystem_no_quotaget_t $basedir/quotas_test -s $dev -t $private_path/mp1/aquota.user $v 2>&1" +); +ok( $result >> 8 eq 13 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_no_quotaget_t $basedir/umount -t $basedir/mntpoint/mp1 $v" +); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { mount } ########################## +# hooks.c selinux_sb_kern_mount() FILESYSTEM__MOUNT + +$opts_no_mount = "rootcontext=system_u:object_r:test_filesystem_no_mount_t:s0"; +mk_mntpoint_1(); +make_fs($fs_type); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_mount\n"; +$result = system( +"runcon -t test_filesystem_no_mount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_mount $v 2>&1" +); +ok( $result >> 8 eq 13 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { getattr } ########################## +# hooks.c selinux_sb_statfs() FILESYSTEM__GETATTR + +$opts_no_getattr = + "rootcontext=system_u:object_r:test_filesystem_no_getattr_t:s0"; +mk_mntpoint_1(); +make_fs($fs_type); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_getattr\n"; +$result = system( +"runcon -t test_filesystem_no_getattr_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_getattr $v" +); +ok( $result eq 0 ); + +$result = system( +"runcon -t test_filesystem_no_getattr_t $basedir/statfs_test -t $basedir/mntpoint $v 2>&1" +); +ok( $result >> 8 eq 13 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_no_getattr_t $basedir/umount -t $basedir/mntpoint/mp1 $v" +); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { remount } ########################## +# hooks.c selinux_mount() FILESYSTEM__REMOUNT + +$opts_no_remount = + "rootcontext=system_u:object_r:test_filesystem_no_remount_t:s0"; +mk_mntpoint_1(); +make_fs($fs_type); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_remount\n"; +$result = system( +"runcon -t test_filesystem_no_remount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v" +); +ok( $result eq 0 ); + +print "Then remount\n"; +$result = system( +"runcon -t test_filesystem_no_remount_t $basedir/mount -r -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_remount $v 2>&1" +); +ok( $result >> 8 eq 13 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_no_remount_t $basedir/umount -t $basedir/mntpoint/mp1 $v" +); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { unmount } ########################## +# hooks.c selinux_umount() FILESYSTEM__UNMOUNT + +$opts_no_unmount = + "rootcontext=system_u:object_r:test_filesystem_no_unmount_t:s0"; +mk_mntpoint_1(); +make_fs($fs_type); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_unmount\n"; +$result = system( +"runcon -t test_filesystem_no_unmount_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_unmount $v" +); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_no_unmount_t $basedir/umount -t $basedir/mntpoint/mp1 $v 2>&1" +); +ok( $result >> 8 eq 13 ); + +# Make sure it does get unmounted +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = + system( + "runcon -t test_filesystem_t $basedir/umount -t $basedir/mntpoint/mp1 $v"); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { associate } ########################## +# hooks.c selinux_inode_setxattr() FILESYSTEM__ASSOCIATE +cleanup(); +mk_mntpoint_1(); +make_fs($fs_type); +$opts_no_associate_file = +"defcontext=system_u:object_r:test_filesystem_no_associate_file_t:s0,fscontext=system_u:object_r:test_filesystem_no_associate_file_t:s0"; + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$opts_no_associate_file\n"; +$result = system( +"runcon -t test_filesystem_no_associate_file_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_associate_file $v" +); +ok( $result eq 0 ); + +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; +$result = + system( +"runcon -t test_filesystem_no_associate_file_t $basedir/create_file_change_context -t unconfined_t -f $basedir/mntpoint/mp1/test_file $v 2>&1" + ); +ok( $result >> 8 eq 13 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = + system( +"runcon -t test_filesystem_no_associate_file_t $basedir/umount -t $basedir/mntpoint/mp1 $v" + ); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +############### Deny filesystem { watch } ########################## +# hooks.c selinux_path_notify() FILESYSTEM__WATCH +if ($test_watch) { + cleanup(); + mk_mntpoint_1(); + make_fs($fs_type); + $opts_no_watch = "context=system_u:object_r:test_filesystem_no_watch_t:s0"; + + print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; + print "Using mount options:\n\t$opts_no_watch\n"; + $result = system( +"runcon -t test_filesystem_no_watch_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $opts_no_watch $v" + ); + ok( $result eq 0 ); + + print "test_fanotify\n"; + $result = system( +"runcon -t test_filesystem_no_watch_t $basedir/fanotify_fs $v -t $basedir/mntpoint/mp1 2>&1" + ); + ok( $result >> 8 eq 13 ); + + print "Unmount filesystem from $basedir/mntpoint/mp1\n"; + $result = system( +"runcon -t test_filesystem_no_watch_t $basedir/umount -t $basedir/mntpoint/mp1 $v" + ); + ok( $result eq 0 ); + + print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; + cleanup1(); +} + +########################################################################## +# context - Useful when mounting filesystems that do not support extended +# attributes. +# Tested by - Creating a filesystem that has xattrs set to a different value, +# then mount with context= and confirm that the files have that +# context as well as any newly created files (even if fscreate +# was set to something else), and that setfilecon/setxattr() on +# files within the mount fails with errno EOPNOTSUPP. +########################################################################## +cleanup(); +mk_mntpoint_1(); +make_fs($fs_type); + +# Mount with xttrs to create a file with specific context. +$context1_opts = "defcontext=system_u:object_r:test_filesystem_context_t:s0"; + +print "Testing 'context=' mount option\n"; +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$context1_opts\n"; +$result = system( +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context1_opts $v" +); +ok( $result eq 0 ); + +# Create file with 'test_filesystem_filecon_t' context +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; +$result = + system( +"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v" + ); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" +); +ok( $result eq 0 ); + +# Need to free the loop device, then get new dev one and attach +system("losetup -d $dev 2>/dev/null"); +get_loop_dev(); +attach_dev(); + +# Mount again with no xttr support +$context2_opts = "context=system_u:object_r:test_filesystem_context_t:s0"; +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$context2_opts\n"; +$result = system( +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $context2_opts $v" +); +ok( $result eq 0 ); + +# Now check the context on file is system_u:object_r:test_filesystem_context_t:s0 +print "Check test file context $basedir/mntpoint/mp1/test_file\n"; +$result = + system( +"runcon -t test_filesystem_context_t $basedir/check_file_context -f $private_path/mp1/test_file -e system_u:object_r:test_filesystem_context_t:s0 $v" + ); +ok( $result eq 0 ); + +# Then create a file with 'test_filesystem_filecon_t' context, this should fail with EOPNOTSUPP +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; +$result = + system( +"runcon -t test_filesystem_context_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v 2>/dev/null" + ); +ok( $result >> 8 eq 95 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = + system( +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" + ); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +########################################################################## +# rootcontext - Explicitly label the root inode of the filesystem being +# mounted before that filesystem or inode becomes visible +# to userspace. +# Tested by - Set mountpoint to unlabeled_t and then check that the +# context of the root directory matches rootcontext= after +# the mount operation. +########################################################################## +cleanup(); +mk_mntpoint_1(); +make_fs($fs_type); +$root_opts = "rootcontext=system_u:object_r:test_filesystem_context_t:s0"; + +print "Testing 'rootcontext=' mount option\n"; + +# Reset mountpoint to 'unlabeled_t' so it is different to any other possible test values. +print "Resetting MP to unlabeled_t $basedir/mntpoint/mp1\n"; +$result = + system( +"runcon -t test_filesystem_context_t $basedir/check_mount_context -r -m $basedir/mntpoint/mp1 $v" + ); +ok( $result eq 0 ); + +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$root_opts\n"; +$result = system( +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $root_opts $v" +); +ok( $result eq 0 ); + +# Now check the mountpoint is the 'rootcontext=' value +print "Check MP context $basedir/mntpoint/mp1\n"; +$result = + system( +"runcon -t test_filesystem_context_t $basedir/check_mount_context -m $basedir/mntpoint/mp1 -e system_u:object_r:test_filesystem_context_t:s0 $v" + ); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" +); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +########################################################################## +# defcontext - Set default security context for unlabeled files. +# This overrides the value set for unlabeled files in policy +# and requires a filesystem that supports xattr labeling. +# Tested by - Create filesystem that has files w/o xattrs and then confirm +# that they are mapped to the specified defcontext upon mount, +# where defcontext differs from the policy default. +########################################################################## +cleanup(); +mk_mntpoint_1(); +make_fs($fs_type); + +$test_opts = "context=system_u:object_r:test_filesystem_context_t:s0"; + +print "Testing 'defcontext=' mount option\n"; +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$test_opts\n"; +$result = system( +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $test_opts $v" +); +ok( $result eq 0 ); + +# Create file, its context will be system_u:object_r:test_filesystem_context_t:s0 from $test_opts +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; +$result = + system( +"runcon -u system_u -t test_filesystem_fscontext_t $basedir/create_file -f $basedir/mntpoint/mp1/test_file $v" + ); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = system( +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" +); +ok( $result eq 0 ); + +# Need to free the loop device, then get new dev one and attach +system("losetup -d $dev 2>/dev/null"); +get_loop_dev(); +attach_dev(); + +# Mount again with defcontext= +$defcontext_opts = "defcontext=system_u:object_r:test_filesystem_filecon_t:s0"; +print "Mount $fs_type filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$defcontext_opts\n"; +$result = system( +"runcon -t test_filesystem_context_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $defcontext_opts $v" +); +ok( $result eq 0 ); + +# Now check the file context is now system_u:object_r:test_filesystem_filecon_t:s0 +print "Check test file context $basedir/mntpoint/mp1/test_file\n"; +$result = + system( +"runcon -t test_filesystem_context_t $basedir/check_file_context -f $basedir/mntpoint/mp1/test_file -e system_u:object_r:test_filesystem_filecon_t:s0 $v" + ); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = + system( +"runcon -t test_filesystem_context_t $basedir/umount -t $basedir/mntpoint/mp1 $v" + ); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +########################################################################## +# fscontext - Sets the overarching filesystem label to a specific security +# context. This filesystem label is separate from the individual +# labels on the files. +# Tested by - Mount a tmpfs (fs_use_trans) filesystem with fscontext= and +# then create a file within it, checking its context. +########################################################################## +$fs_type = "tmpfs"; +cleanup(); +mk_mntpoint_1(); +make_fs($fs_type); +$fscontext_opts = +"fscontext=system_u:object_r:test_filesystem_fscontext_t:s0,size=10M,mode=0770"; + +print "Testing 'fscontext=' mount option\n"; +print "Mount tmpfs filesystem on $basedir/mntpoint/mp1\n"; +print "Using mount options:\n\t$fscontext_opts\n"; +$result = system( +"runcon -t test_filesystem_fscontext_t $basedir/mount -s $dev -t $basedir/mntpoint/mp1 -f $fs_type -o $fscontext_opts $v" +); +ok( $result eq 0 ); + +print "Creating test file $basedir/mntpoint/mp1/test_file\n"; +$result = + system( +"runcon -t test_filesystem_fscontext_t $basedir/create_file_change_context -t test_filesystem_filecon_t -f $private_path/mp1/test_file $v" + ); +ok( $result eq 0 ); + +print "Unmount filesystem from $basedir/mntpoint/mp1\n"; +$result = + system( +"runcon -t test_filesystem_fscontext_t $basedir/umount -t $basedir/mntpoint/mp1 $v" + ); +ok( $result eq 0 ); + +print "Removing: $dev $basedir/mntpoint $basedir/fstest\n"; +cleanup1(); + +# Cleanup any attached /dev/loop entries +foreach my $n (@device_list) { + system("$basedir/grim_reaper $n 2>/dev/null"); +} + +exit; diff --git a/tests/filesystem/umount.c b/tests/filesystem/umount.c new file mode 100644 index 0000000..4a20448 --- /dev/null +++ b/tests/filesystem/umount.c @@ -0,0 +1,84 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <stdbool.h> +#include <sys/mount.h> +#include <selinux/selinux.h> + +static void print_usage(char *progname) +{ + fprintf(stderr, + "usage: %s [-v] [-t]\n" + "Where:\n\t" + "-t Target path\n\t" + "-v Print information.\n", progname); + exit(-1); +} + +#define WAIT_COUNT 60 +#define USLEEP_TIME 100000 + +int main(int argc, char *argv[]) +{ + char *context, *tgt = NULL; + int opt, result, i, save_err; + bool verbose = false; + + while ((opt = getopt(argc, argv, "t:v")) != -1) { + switch (opt) { + case 't': + tgt = optarg; + break; + case 'v': + verbose = true; + break; + default: + print_usage(argv[0]); + } + } + + if (!tgt) + print_usage(argv[0]); + + if (verbose) { + result = getcon(&context); + if (result < 0) { + fprintf(stderr, "Failed to obtain process context\n"); + exit(-1); + } + printf("Process context:\n\t%s\n", context); + free(context); + } + + /* + * umount(2) will sometimes return EBUSY when other tasks are + * checking mounts so wait around before bailing out. + */ + for (i = 0; i < WAIT_COUNT; i++) { + result = umount(tgt); + save_err = errno; + if (!result) { + if (verbose) + printf("Unmounted: %s\n", tgt); + + return 0; + } + + if (verbose && save_err == EBUSY) + printf("umount(2) returned EBUSY %d times\n", i + 1); + + if (save_err != EBUSY) { + fprintf(stderr, "Failed umount(2): %s\n", + strerror(save_err)); + return save_err; + } + usleep(USLEEP_TIME); + } + + fprintf(stderr, "Failed to umount(2) after %d retries with: %s\n", + WAIT_COUNT, strerror(save_err)); + + return save_err; +}
Test filesystem permissions and setfscreatecon(3). From kernels 5.5 filesystem { watch } is also tested. Signed-off-by: Richard Haines <richard_c_haines@btinternet.com> --- defconfig | 6 + policy/Makefile | 4 + policy/test_filesystem.te | 324 +++++++ tests/Makefile | 7 + tests/filesystem/.gitignore | 11 + tests/filesystem/Makefile | 16 + tests/filesystem/check_file_context.c | 75 ++ tests/filesystem/check_mount_context.c | 109 +++ tests/filesystem/create_file.c | 79 ++ tests/filesystem/create_file_change_context.c | 143 +++ tests/filesystem/fanotify_fs.c | 79 ++ tests/filesystem/fs_relabel.c | 72 ++ tests/filesystem/grim_reaper.c | 63 ++ tests/filesystem/mount.c | 130 +++ tests/filesystem/quotas_test.c | 134 +++ tests/filesystem/statfs_test.c | 65 ++ tests/filesystem/test | 830 ++++++++++++++++++ tests/filesystem/umount.c | 84 ++ 18 files changed, 2231 insertions(+) create mode 100644 policy/test_filesystem.te create mode 100644 tests/filesystem/.gitignore create mode 100644 tests/filesystem/Makefile create mode 100644 tests/filesystem/check_file_context.c create mode 100644 tests/filesystem/check_mount_context.c create mode 100644 tests/filesystem/create_file.c create mode 100644 tests/filesystem/create_file_change_context.c create mode 100644 tests/filesystem/fanotify_fs.c create mode 100644 tests/filesystem/fs_relabel.c create mode 100644 tests/filesystem/grim_reaper.c create mode 100644 tests/filesystem/mount.c create mode 100644 tests/filesystem/quotas_test.c create mode 100644 tests/filesystem/statfs_test.c create mode 100755 tests/filesystem/test create mode 100644 tests/filesystem/umount.c