@@ -71,6 +71,10 @@ ifeq ($(shell grep -q corenet_sctp_bind_all_nodes $(POLDEV)/include/kernel/coren
TARGETS += test_sctp.te
endif
+ifeq ($(shell grep -q all_file_perms.*watch $(POLDEV)/include/support/all_perms.spt && echo true),true)
+TARGETS+=test_notify.te
+endif
+
ifeq (x$(DISTRO),$(filter x$(DISTRO),xRHEL4 xRHEL5 xRHEL6))
TARGETS:=$(filter-out test_overlayfs.te test_mqueue.te, $(TARGETS))
endif
new file mode 100644
@@ -0,0 +1,94 @@
+####################################################
+# Policy for testing inoftify and fanotify watches #
+####################################################
+
+attribute test_notify_domain;
+
+# Type for the file on which we want to set a watch
+type test_notify_file_t;
+files_type(test_notify_file_t);
+
+# Domain for the process which CAN set a non-permission watch
+type test_watch_t;
+domain_type(test_watch_t);
+unconfined_runs_test(test_watch_t);
+
+typeattribute test_watch_t test_notify_domain;
+typeattribute test_watch_t testdomain;
+
+allow test_notify_domain self:capability sys_admin;
+
+allow test_watch_t test_notify_file_t:file { read write open watch };
+
+# Domain for the process which CAN set a NON-access watch on a file
+type test_perm_watch_t;
+domain_type(test_perm_watch_t);
+unconfined_runs_test(test_perm_watch_t);
+
+typeattribute test_perm_watch_t test_notify_domain;
+typeattribute test_perm_watch_t testdomain;
+
+allow test_perm_watch_t test_notify_file_t:file { read write open watch watch_with_perm };
+
+# Domain which CAN set a NON-perm watch which MAY read accesses
+type test_read_watch_t;
+domain_type(test_read_watch_t);
+unconfined_runs_test(test_read_watch_t);
+
+typeattribute test_read_watch_t test_notify_domain;
+typeattribute test_read_watch_t testdomain;
+
+allow test_read_watch_t test_notify_file_t:file { read write open watch watch_reads };
+
+# Domain which CAN set any watch which CAN read accesses
+type test_perm_read_watch_t;
+domain_type(test_perm_read_watch_t);
+unconfined_runs_test(test_perm_read_watch_t);
+
+typeattribute test_perm_read_watch_t test_notify_domain;
+typeattribute test_perm_read_watch_t testdomain;
+
+allow test_perm_read_watch_t test_notify_file_t:file { read write open watch watch_with_perm watch_reads };
+
+# Domain which CANNOT set any watches
+type test_no_watch_t;
+domain_type(test_no_watch_t);
+unconfined_runs_test(test_no_watch_t);
+
+typeattribute test_no_watch_t test_notify_domain;
+typeattribute test_no_watch_t testdomain;
+
+allow test_no_watch_t test_notify_file_t:file { read write open };
+
+# Domain which allows for mount watches
+type test_mount_watch_t;
+domain_type(test_mount_watch_t);
+unconfined_runs_test(test_mount_watch_t);
+
+typeattribute test_mount_watch_t test_notify_domain;
+typeattribute test_mount_watch_t testdomain;
+
+allow test_mount_watch_t test_notify_file_t:dir { read write open watch_mount };
+
+# Domain which allows for mount perm watches
+type test_mount_perm_t;
+domain_type(test_mount_perm_t);
+unconfined_runs_test(test_mount_perm_t);
+
+typeattribute test_mount_perm_t test_notify_domain;
+typeattribute test_mount_perm_t testdomain;
+
+allow test_mount_perm_t test_notify_file_t:dir { read write open watch_mount watch_with_perm };
+
+# Domain which has no write access but can watch
+type test_rdonly_t;
+domain_type(test_rdonly_t);
+unconfined_runs_test(test_rdonly_t);
+
+typeattribute test_rdonly_t test_notify_domain;
+typeattribute test_rdonly_t testdomain;
+
+allow test_rdonly_t test_notify_file_t:dir { read open watch };
+
+miscfiles_domain_entry_test_files(test_notify_domain);
+userdom_sysadm_entry_spec_domtrans_to(test_notify_domain);
@@ -50,6 +50,10 @@ ifeq ($(shell grep "^SELINUX_INFINIBAND_PKEY_TEST=" infiniband_pkey/ibpkey_test.
SUBDIRS += infiniband_pkey
endif
+ifeq ($(shell grep -q all_file_perms.*watch $(POLDEV)/include/support/all_perms.spt && echo true),true)
+SUBDIRS+=notify
+endif
+
ifeq ($(DISTRO),RHEL4)
SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp_nosuid overlay unix_socket, $(SUBDIRS))
endif
new file mode 100644
@@ -0,0 +1,5 @@
+TARGETS=test_inotify test_fanotify
+
+all: $(TARGETS)
+clean:
+ rm -f $(TARGETS)
new file mode 100755
@@ -0,0 +1,133 @@
+#!/usr/bin/perl
+
+use Test;
+BEGIN { plan tests => 18 } # number of tests to run
+
+# help the test script locate itself
+$basedir = $0;
+$basedir =~ s|(.*)/[^/]*|$1|;
+
+# Get rid of a testfile and dir from last run if it's there (just in case)
+system("rm -f $basedir/watch_me");
+system("rm -rf $basedir/watch_dir");
+
+# Create a new test file
+system("touch $basedir/watch_me");
+system("chcon -t test_notify_file_t $basedir/watch_me");
+
+# Create test dir
+system("mkdir $basedir/watch_dir");
+system("chcon -t test_notify_file_t $basedir/watch_dir");
+
+## TESTS
+
+## TEST BASIC WATCH PERMISSION
+# Should be able to set inotify watch
+$exit_val =
+ system("runcon -t test_watch_t $basedir/test_inotify $basedir/watch_me 2>&1");
+ok( $exit_val, 0 );
+
+# Should be able to set non-permissions based fanotify watch
+$exit_val = system(
+ "runcon -t test_watch_t $basedir/test_fanotify $basedir/watch_me 2>&1");
+ok( $exit_val, 0 );
+
+# Should NOT be able to set permission based fanotify watch
+$exit_val = system(
+ "runcon -t test_watch_t $basedir/test_fanotify -p $basedir/watch_me 2>&1");
+ok($exit_val); # this should fail
+
+# Should NOT be able to set read based fanotify watch
+$exit_val = system(
+ "runcon -t test_watch_t $basedir/test_fanotify -r $basedir/watch_me 2>&1");
+ok($exit_val); # this should fail
+
+# Should NOT be able to set read based inotify watch
+$exit_val = system(
+ "runcon -t test_watch_t $basedir/test_inotify -r $basedir/watch_me 2>&1");
+ok($exit_val); # this should fail
+
+## TEST PERM WATCH
+# Should be able to set permission based fanotify watch
+$exit_val = system(
+"runcon -t test_perm_watch_t $basedir/test_fanotify -p $basedir/watch_me 2>&1"
+);
+ok( $exit_val, 0 );
+
+# Should NOT be able to set watch of accesses
+$exit_val = system(
+"runcon -t test_perm_watch_t $basedir/test_fanotify -r $basedir/watch_me 2>&1"
+);
+ok($exit_val); # this should fail
+
+## TEST READ NO PERM WATCH PERMSISSIONS
+# Should NOT be able to set read and perm watch
+$exit_val = system(
+"runcon -t test_read_watch_t $basedir/test_fanotify -p -r $basedir/watch_me 2>&1"
+);
+ok($exit_val); # should fail
+
+# Should be able to set read inotify watch
+$exit_val = system(
+"runcon -t test_read_watch_t $basedir/test_inotify -r $basedir/watch_me 2>&1"
+);
+ok( $exit_val, 0 );
+
+## TEST READ WITH PERM WATCH PERMSISSIONS
+# Should be able to set read and perm watch
+$exit_val = system(
+"runcon -t test_perm_read_watch_t $basedir/test_fanotify -p -r $basedir/watch_me 2>&1"
+);
+ok( $exit_val, 0 );
+
+## TEST NO WATCH PERMSISSIONS
+# Should NOT be able to set inotify watch
+$exit_val = system(
+ "runcon -t test_no_watch_t $basedir/test_inotify $basedir/watch_me 2>&1");
+ok($exit_val); # this should fail
+
+# Should NOT be able to set any fanotify watch
+$exit_val = system(
+ "runcon -t test_no_watch_t $basedir/test_fanotify $basedir/watch_me 2>&1");
+ok($exit_val); # this should fail
+
+## TEST READ ONLY
+# Should NOT be able to get read-write descriptor
+$exit_val = system(
+ "runcon -t test_rdonly_t $basedir/test_fanotify -l $basedir/watch_me 2>&1");
+ok($exit_val); # this should fail
+
+# Should be able to get read-write descriptor
+$exit_val = system(
+ "runcon -t test_watch_t $basedir/test_fanotify -l $basedir/watch_me 2>&1");
+ok( $exit_val, 0 );
+
+## TEST MOUNT WATCHES
+# Should NOT be able to set a watch on a mount point
+$exit_val = system(
+ "runcon -t test_watch_t $basedir/test_fanotify -m $basedir/watch_dir 2>&1");
+ok($exit_val); # this should fail
+
+# Should be able to set a watch on mount point
+$exit_val = system(
+"runcon -t test_mount_watch_t $basedir/test_fanotify -m $basedir/watch_dir 2>&1"
+);
+ok( $exit_val, 0 );
+
+# Should NOT be able to set a perm watch on a mount
+$exit_val = system(
+"runcon -t test_mount_watch_t $basedir/test_fanotify -m -p $basedir/watch_dir 2>&1"
+);
+ok($exit_val); # this should fail
+
+# Should be able to set a perm watch on a mount object
+$exit_val = system(
+"runcon -t test_mount_perm_t $basedir/test_fanotify -p -m $basedir/watch_dir 2>&1"
+);
+ok( $exit_val, 0 );
+
+# Clean up test file
+system("rm -f $basedir/watch_me");
+
+# Clean up test dir
+system("rm -rf $basedir/watch_dir");
new file mode 100644
@@ -0,0 +1,107 @@
+#define _GNU_SOURCE 1
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <getopt.h>
+
+#include <fcntl.h>
+#include <poll.h>
+#include <sys/fanotify.h>
+#include <unistd.h>
+
+void printUsage() {
+ fprintf(stderr, "Usage: test_fanotify [-p] [-r] [-l] [-m] file_name\n");
+ exit(1);
+}
+
+int main(int argc, char *argv[]) {
+ if (argc < 2) {
+ printUsage();
+ }
+
+ int fd, ret, arg;
+ int mask = FAN_OPEN; // default mask
+ int flags = FAN_MARK_ADD;
+ int listening = 0;
+
+ // the -p flag will test for watch_with_perm
+ // the mask used at mark will contain FAN_OPEN_PERM
+ //
+ // the -r flag will test for watching accesses to files for reads
+ // the mask will contain FAN_ACCESS
+ while ((arg = getopt(argc, argv, "prlm")) != -1) {
+ switch (arg) {
+ case 'p':
+ mask |= FAN_OPEN_PERM;
+ break;
+ case 'r':
+ mask |= FAN_ACCESS;
+ break;
+ case 'l':
+ listening = 1;
+ break;
+ case 'm':
+ flags |= FAN_MARK_MOUNT;
+ break;
+ default:
+ printUsage();
+ }
+ }
+
+ // get file descriptor for new fanotify event queue
+ fd = fanotify_init(FAN_CLASS_CONTENT, O_RDWR);
+ if (fd < 0) {
+ perror("fanotify_init:bad file descriptor");
+ exit(1);
+ }
+
+ // mark a filesystem object and add mark to event queue
+ // get notifications on file opens, accesses, and closes
+ // use current working directory as base dir
+ ret = fanotify_mark(fd, flags, mask, AT_FDCWD, argv[optind]);
+
+ if (ret < 0) {
+ perror("test_fanotify:watch denied");
+ exit(1);
+ }
+
+ // logic to actually listen for an event if the -l flag is passed
+ // this is used to test if an app with read-only access can get a read/write
+ // handle to the watched file
+ if (listening) {
+ if (fork() == 0) { // fork a child process to cause an event on the file
+ FILE *f;
+
+ f = fopen(argv[optind], "r"); // open file for reading
+ fgetc(f); // read char from file
+
+ fclose(f);
+ } else { // logic to watch for events and try to access file read/write
+ struct pollfd fds;
+ fds.fd = fd;
+ fds.events = POLLIN;
+
+ while (listening) {
+ int polled = poll(&fds, 1, 1);
+ if (polled > 0) {
+ if (fds.revents & POLLIN) {
+ struct fanotify_event_metadata buff[200];
+
+ size_t len = read(fd, (void *)&buff, sizeof(buff));
+ if (len == -1) {
+ perror("test_fanotify:can't open file");
+ exit(1);
+ } else {
+ listening = 0;
+ break;
+ }
+ }
+ } else if (polled == -1) {
+ listening = 0;
+ }
+ }
+ }
+ }
+ exit(0);
+}
new file mode 100644
@@ -0,0 +1,43 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/inotify.h>
+#include <getopt.h>
+
+int main(int argc, char *argv[])
+{
+ if (argc < 2) {
+ fprintf(stderr, "Usage: test_inotify [-r] file_name\n");
+ exit(1);
+ }
+
+ int fd, wd, arg;
+ int mask = IN_MODIFY;
+
+ while ((arg = getopt(argc, argv, "pr")) != -1) {
+ switch (arg) {
+ case 'r':
+ mask |= IN_ACCESS;
+ break;
+ default:
+ fprintf(stderr, "Usage: test_inotify [-r] file_name\n");
+ exit(1);
+ }
+ }
+
+ // get new file descriptor for inotify access
+ fd = inotify_init();
+ if (fd < 0) {
+ perror("inotify_init:bad file descriptor");
+ exit(1);
+ }
+
+ // set watch on file and get watch descriptor for accessing events on it
+ wd = inotify_add_watch(fd, argv[optind], mask);
+
+ if (wd < 0) {
+ perror("test_inotify:watch denied");
+ exit(1);
+ }
+
+ exit(0);
+}
Added a suite to test permissions for setting inotify and fanotify watches on filesystem objects. Tests watch, watch_with_perm, and watch_reads permissions. Signed-off-by: Aaron Goidel <acgoide@tycho.nsa.gov> --- policy/Makefile | 4 ++ policy/test_notify.te | 94 +++++++++++++++++++++++++ tests/Makefile | 4 ++ tests/notify/Makefile | 5 ++ tests/notify/test | 133 +++++++++++++++++++++++++++++++++++ tests/notify/test_fanotify.c | 107 ++++++++++++++++++++++++++++ tests/notify/test_inotify.c | 43 +++++++++++ 7 files changed, 390 insertions(+) create mode 100644 policy/test_notify.te create mode 100644 tests/notify/Makefile create mode 100755 tests/notify/test create mode 100644 tests/notify/test_fanotify.c create mode 100644 tests/notify/test_inotify.c