Re: [V4 PATCH 1/1] selinux-testsuite: Add perf_event tests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 12/10/19 10:31 AM, Stephen Smalley wrote:
On 12/8/19 12:06 PM, Richard Haines wrote:
Test perf_event permissions.

Signed-off-by: Richard Haines <richard_c_haines@xxxxxxxxxxxxxx>

Acked-by: Stephen Smalley <sds@xxxxxxxxxxxxx>

I'll fix the merge conflict.

Thanks, merged.


---
V2 Changes:
Remove neverallows from policy
Check /proc/sys/kernel/perf_event_paranoid, if < 2 then bypass the
capability { sys_admin } test.
V3 Changes:
Remove allow_map() and device_t:chr_file rules as not required.
V4 Change:
Correct policy module comment header.

  defconfig                     |   6 ++
  policy/Makefile               |   4 +
  policy/test_perf_event.te     |  89 +++++++++++++++++
  tests/Makefile                |   4 +
  tests/perf_event/.gitignore   |   1 +
  tests/perf_event/Makefile     |   7 ++
  tests/perf_event/perf_event.c | 178 ++++++++++++++++++++++++++++++++++
  tests/perf_event/test         |  93 ++++++++++++++++++
  8 files changed, 382 insertions(+)
  create mode 100644 policy/test_perf_event.te
  create mode 100644 tests/perf_event/.gitignore
  create mode 100644 tests/perf_event/Makefile
  create mode 100644 tests/perf_event/perf_event.c
  create mode 100755 tests/perf_event/test

diff --git a/defconfig b/defconfig
index 0574f1d..2d9c092 100644
--- a/defconfig
+++ b/defconfig
@@ -78,3 +78,9 @@ CONFIG_KEY_DH_OPERATIONS=y
  # Test key management socket.
  # This is not required for SELinux operation itself.
  CONFIG_NET_KEY=m
+
+# Test perf events.
+# This is not required for SELinux operation itself.
+CONFIG_HAVE_PERF_EVENTS=y
+CONFIG_PERF_EVENTS=y
+CONFIG_TRACEPOINTS=y
diff --git a/policy/Makefile b/policy/Makefile
index dda2e16..3f60991 100644
--- a/policy/Makefile
+++ b/policy/Makefile
@@ -101,6 +101,10 @@ ifeq ($(shell grep -q module_load $(POLDEV)/include/support/all_perms.spt && ech
  TARGETS+=test_module_load.te
  endif
+ifeq ($(shell grep -q perf_event $(POLDEV)/include/support/all_perms.spt && echo true),true)
+TARGETS += test_perf_event.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_perf_event.te b/policy/test_perf_event.te
new file mode 100644
index 0000000..67250a4
--- /dev/null
+++ b/policy/test_perf_event.te
@@ -0,0 +1,89 @@
+#
+######### perf_event policy module ##########
+#
+attribute perfdomain;
+
+################# Allow perf_event { * } ##########################
+type test_perf_t;
+domain_type(test_perf_t)
+unconfined_runs_test(test_perf_t)
+typeattribute test_perf_t testdomain;
+typeattribute test_perf_t perfdomain;
+
+allow test_perf_t self:capability { sys_admin };
+allow test_perf_t self:perf_event { open cpu kernel tracepoint read write };
+
+################# Deny capability { sys_admin } ##########################
+type test_perf_no_admin_t;
+domain_type(test_perf_no_admin_t)
+unconfined_runs_test(test_perf_no_admin_t)
+typeattribute test_perf_no_admin_t testdomain;
+typeattribute test_perf_no_admin_t perfdomain;
+
+allow test_perf_no_admin_t self:perf_event { open cpu kernel tracepoint read write };
+
+################# Deny perf_event { open } ##########################
+type test_perf_no_open_t;
+domain_type(test_perf_no_open_t)
+unconfined_runs_test(test_perf_no_open_t)
+typeattribute test_perf_no_open_t testdomain;
+typeattribute test_perf_no_open_t perfdomain;
+
+allow test_perf_no_open_t self:capability { sys_admin };
+allow test_perf_no_open_t self:perf_event { cpu kernel tracepoint read write };
+
+################# Deny perf_event { cpu } ##########################
+type test_perf_no_cpu_t;
+domain_type(test_perf_no_cpu_t)
+unconfined_runs_test(test_perf_no_cpu_t)
+typeattribute test_perf_no_cpu_t testdomain;
+typeattribute test_perf_no_cpu_t perfdomain;
+
+allow test_perf_no_cpu_t self:capability { sys_admin };
+allow test_perf_no_cpu_t self:perf_event { open kernel tracepoint read write };
+
+################# Deny perf_event { kernel } ##########################
+type test_perf_no_kernel_t;
+domain_type(test_perf_no_kernel_t)
+unconfined_runs_test(test_perf_no_kernel_t)
+typeattribute test_perf_no_kernel_t testdomain;
+typeattribute test_perf_no_kernel_t perfdomain;
+
+allow test_perf_no_kernel_t self:capability { sys_admin };
+allow test_perf_no_kernel_t self:perf_event { open cpu tracepoint read write };
+
+################# Deny perf_event { tracepoint } ##########################
+type test_perf_no_tracepoint_t;
+domain_type(test_perf_no_tracepoint_t)
+unconfined_runs_test(test_perf_no_tracepoint_t)
+typeattribute test_perf_no_tracepoint_t testdomain;
+typeattribute test_perf_no_tracepoint_t perfdomain;
+
+allow test_perf_no_tracepoint_t self:capability { sys_admin };
+allow test_perf_no_tracepoint_t self:perf_event { open cpu kernel read write };
+
+################# Deny perf_event { read } ##########################
+type test_perf_no_read_t;
+domain_type(test_perf_no_read_t)
+unconfined_runs_test(test_perf_no_read_t)
+typeattribute test_perf_no_read_t testdomain;
+typeattribute test_perf_no_read_t perfdomain;
+
+allow test_perf_no_read_t self:capability { sys_admin };
+allow test_perf_no_read_t self:perf_event { open cpu kernel tracepoint write };
+
+################# Deny perf_event { write } ##########################
+type test_perf_no_write_t;
+domain_type(test_perf_no_write_t)
+unconfined_runs_test(test_perf_no_write_t)
+typeattribute test_perf_no_write_t testdomain;
+typeattribute test_perf_no_write_t perfdomain;
+
+allow test_perf_no_write_t self:capability { sys_admin };
+allow test_perf_no_write_t self:perf_event { open cpu kernel tracepoint read };
+
+#
+########### Allow these domains to be entered from sysadm domain ############
+#
+miscfiles_domain_entry_test_files(perfdomain)
+userdom_sysadm_entry_spec_domtrans_to(perfdomain)
diff --git a/tests/Makefile b/tests/Makefile
index 0d33fbf..8f66996 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -79,6 +79,10 @@ SUBDIRS+=module_load
  endif
  endif
+ifeq ($(shell grep -q perf_event $(POLDEV)/include/support/all_perms.spt && echo true),true)
+SUBDIRS += perf_event
+endif
+
  ifeq ($(DISTRO),RHEL4)
      SUBDIRS:=$(filter-out bounds dyntrace dyntrans inet_socket mmap nnp_nosuid overlay unix_socket, $(SUBDIRS))
  endif
diff --git a/tests/perf_event/.gitignore b/tests/perf_event/.gitignore
new file mode 100644
index 0000000..8c2f931
--- /dev/null
+++ b/tests/perf_event/.gitignore
@@ -0,0 +1 @@
+perf_event
diff --git a/tests/perf_event/Makefile b/tests/perf_event/Makefile
new file mode 100644
index 0000000..988424c
--- /dev/null
+++ b/tests/perf_event/Makefile
@@ -0,0 +1,7 @@
+TARGETS = perf_event
+LDLIBS += -lselinux
+
+all: $(TARGETS)
+
+clean:
+    rm -f $(TARGETS)
diff --git a/tests/perf_event/perf_event.c b/tests/perf_event/perf_event.c
new file mode 100644
index 0000000..8983f02
--- /dev/null
+++ b/tests/perf_event/perf_event.c
@@ -0,0 +1,178 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <asm/unistd.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <linux/perf_event.h>
+#include <selinux/selinux.h>
+
+enum {
+    PERF_FILE_MMAP,
+    PERF_FILE,
+    PERF_MMAP
+} read_type;
+
+static void print_usage(char *progname)
+{
+    fprintf(stderr,
+        "usage:  %s [-f|-m] [-v]\n"
+        "Where:\n\t"
+        "-f  Read perf_event info using read(2)\n\t"
+        "-m  Read perf_event info using mmap(2)\n\t"
+        "    Default is to use read(2) and mmap(2)\n\t"
+        "-v  Print information\n", progname);
+    exit(-1);
+}
+
+static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
+                int cpu, int group_fd, unsigned long flags)
+{
+    return syscall(__NR_perf_event_open, hw_event, pid, cpu,
+               group_fd, flags);
+}
+
+int main(int argc, char **argv)
+{
+    int opt, result, page_size, mmap_size, fd;
+    long long count;
+    bool verbose = false;
+    char *context;
+    void *base;
+    struct perf_event_attr pe_attr;
+    struct perf_event_mmap_page *pe_page;
+
+    read_type = PERF_FILE_MMAP;
+
+    while ((opt = getopt(argc, argv, "fmv")) != -1) {
+        switch (opt) {
+        case 'f':
+            read_type = PERF_FILE;
+            break;
+        case 'm':
+            read_type = PERF_MMAP;
+            break;
+        case 'v':
+            verbose = true;
+            break;
+        default:
+            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);
+    }
+
+    /* Test perf_event { open cpu kernel tracepoint } */
+    memset(&pe_attr, 0, sizeof(struct perf_event_attr));
+    pe_attr.type = PERF_TYPE_HARDWARE | PERF_TYPE_TRACEPOINT;
+    pe_attr.size = sizeof(struct perf_event_attr);
+    pe_attr.config = PERF_COUNT_HW_INSTRUCTIONS;
+    pe_attr.disabled = 1;
+    pe_attr.exclude_hv = 1;
+
+    fd = perf_event_open(&pe_attr, -1, 1, -1, 0);
+    if (fd < 0) {
+        fprintf(stderr, "Failed perf_event_open(): %s\n",
+            strerror(errno));
+        if (errno == EACCES)
+            exit(1);
+        else
+            exit(-1);
+    }
+
+    /* Test perf_event { write }; */
+    result = ioctl(fd, PERF_EVENT_IOC_RESET, 0);
+    if (result < 0) {
+        fprintf(stderr, "Failed ioctl(PERF_EVENT_IOC_RESET): %s\n",
+            strerror(errno));
+        if (errno == EACCES)
+            result = 2;
+        goto err;
+    }
+
+    result = ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
+    if (result < 0) {
+        fprintf(stderr, "Failed ioctl(PERF_EVENT_IOC_ENABLE): %s\n",
+            strerror(errno));
+        if (errno == EACCES)
+            result = 3;
+        goto err;
+    }
+
+    result = ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
+    if (result < 0) {
+        fprintf(stderr, "Failed ioctl(PERF_EVENT_IOC_DISABLE): %s\n",
+            strerror(errno));
+        if (errno == EACCES)
+            result = 4;
+        goto err;
+    }
+
+    /* Test mmap(2) perf_event { read } */
+    if (read_type == PERF_MMAP || read_type == PERF_FILE_MMAP) {
+        page_size = sysconf(_SC_PAGESIZE);
+        if (page_size < 0) {
+            fprintf(stderr, "Failed sysconf(_SC_PAGESIZE): %s\n",
+                strerror(errno));
+            if (errno == EACCES)
+                result = 5;
+            else
+                result = -1;
+            goto err;
+        }
+        mmap_size = page_size * 2;
+
+        base = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE,
+                MAP_SHARED, fd, 0);
+        if (base == MAP_FAILED) {
+            fprintf(stderr, "Failed mmap(): %s\n", strerror(errno));
+            if (errno == EACCES)
+                result = 6;
+            else
+                result = -1;
+            goto err;
+        }
+
+        if (verbose) {
+            pe_page = base;
+            printf("perf mmap(2) return value: %lld\n",
+                   pe_page->offset);
+        }
+
+        munmap(base, mmap_size);
+    }
+
+    /* Test read(2) perf_event { read } */
+    if (read_type == PERF_FILE || read_type == PERF_FILE_MMAP) {
+        result = read(fd, &count, sizeof(long long));
+        if (result < 0) {
+            fprintf(stderr, "Failed read(): %s\n", strerror(errno));
+            if (errno == EACCES)
+                result = 7;
+            goto err;
+        }
+
+        if (verbose)
+            printf("perf read(2) return value: %lld\n", count);
+
+        close(fd);
+    }
+
+    return 0;
+
+err:
+    close(fd);
+    return result;
+}
diff --git a/tests/perf_event/test b/tests/perf_event/test
new file mode 100755
index 0000000..1c2e4a9
--- /dev/null
+++ b/tests/perf_event/test
@@ -0,0 +1,93 @@
+#!/usr/bin/perl
+use Test::More;
+
+BEGIN {
+    $basedir = $0;
+    $basedir =~ s|(.*)/[^/]*|$1|;
+
+    $test_count = 8;
+    $sys_admin  = 0;
+
+    # allow info to be shown during tests
+    $v = $ARGV[0];
+    if ($v) {
+        if ( $v ne "-v" ) {
+            plan skip_all => "Invalid option (use -v)";
+        }
+    }
+    else {
+        $v = " ";
+    }
+
+    $level = `cat /proc/sys/kernel/perf_event_paranoid`;
+    chomp($level);
+    if ( $level >= 2 ) {    # These tests require CAP_SYS_ADMIN
+        $test_count += 1;
+        $sys_admin = 1;
+    }
+
+    if ( $v eq "-v" ) {
+        print "Paranoid level: $level\n";
+        if ( $level < 0 ) {
+            print "\tNot paranoid\n";
+        }
+        elsif ( $level eq 0 ) {
+            print "\tDisallow raw tracepoint/ftrace without CAP_SYS_ADMIN\n";
+        }
+        elsif ( $level eq 1 ) {
+            print "\tDisallow CPU event access without CAP_SYS_ADMIN\n";
+        }
+        elsif ( $level eq 2 ) {
+            print "\tDisallow kernel profiling without CAP_SYS_ADMIN\n";
+        }
+        else {
+            print "\tUndefined level\n";
+        }
+    }
+
+    plan tests => $test_count;
+}
+
+# perf_event { open cpu kernel tracepoint read write };
+print "Test perf_event\n";
+$result = system "runcon -t test_perf_t $basedir/perf_event $v";
+ok( $result eq 0 );
+
+if ($sys_admin) {
+
+    # Deny capability { sys_admin } - EACCES perf_event_open(2)
+    $result =
+      system "runcon -t test_perf_no_admin_t $basedir/perf_event $v 2>&1";
+    ok( $result >> 8 eq 1 );
+}
+
+# Deny perf_event { open } - EACCES perf_event_open(2)
+$result = system "runcon -t test_perf_no_open_t $basedir/perf_event $v 2>&1";
+ok( $result >> 8 eq 1 );
+
+# Deny perf_event { cpu } - EACCES perf_event_open(2)
+$result = system "runcon -t test_perf_no_cpu_t $basedir/perf_event $v 2>&1";
+ok( $result >> 8 eq 1 );
+
+# Deny perf_event { kernel } - EACCES perf_event_open(2)
+$result = system "runcon -t test_perf_no_kernel_t $basedir/perf_event $v 2>&1";
+ok( $result >> 8 eq 1 );
+
+# Deny perf_event { tracepoint } - EACCES perf_event_open(2)
+$result =
+  system "runcon -t test_perf_no_tracepoint_t $basedir/perf_event $v 2>&1";
+ok( $result >> 8 eq 1 );
+
+# Deny perf_event { read } - EACCES mmap(2)
+$result = system "runcon -t test_perf_no_read_t $basedir/perf_event -m $v 2>&1";
+ok( $result >> 8 eq 6 );
+
+# Deny perf_event { read } - EACCES read(2)
+$result = system "runcon -t test_perf_no_read_t $basedir/perf_event -f $v 2>&1";
+ok( $result >> 8 eq 7 );
+
+# Deny perf_event { write } - EACCES ioctl(2) write
+$result = system "runcon -t test_perf_no_write_t $basedir/perf_event $v 2>&1";
+ok( $result >> 8 eq 2 );
+
+exit;






[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux