@@ -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
@@ -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
new file mode 100644
@@ -0,0 +1,104 @@
+#
+######### Check watch_queue for key changes 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 device_t:chr_file { ioctl open read write };
+allow test_perf_t self:perf_event { open cpu kernel tracepoint read write };
+allow_map(test_perf_t, device_t, chr_file)
+
+################# 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 device_t:chr_file { ioctl open read write };
+allow test_perf_no_admin_t self:perf_event { open cpu kernel tracepoint read write };
+allow_map(test_perf_no_admin_t, device_t, chr_file)
+
+################# 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 device_t:chr_file { ioctl open read write };
+allow_map(test_perf_no_open_t, device_t, chr_file)
+
+################# 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 device_t:chr_file { ioctl open read write };
+allow test_perf_no_cpu_t self:perf_event { open kernel tracepoint read write };
+allow_map(test_perf_no_cpu_t, device_t, chr_file)
+
+################# 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 device_t:chr_file { ioctl open read write };
+allow test_perf_no_kernel_t self:perf_event { open cpu tracepoint read write };
+allow_map(test_perf_no_kernel_t, device_t, chr_file)
+
+################# 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 device_t:chr_file { ioctl open read write };
+allow test_perf_no_tracepoint_t self:perf_event { open cpu kernel read write };
+allow_map(test_perf_no_tracepoint_t, device_t, chr_file)
+
+################# 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 device_t:chr_file { ioctl open read write };
+allow test_perf_no_read_t self:perf_event { open cpu kernel tracepoint write };
+allow_map(test_perf_no_read_t, device_t, chr_file)
+
+################# 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 device_t:chr_file { ioctl open read write };
+allow test_perf_no_write_t self:perf_event { open cpu kernel tracepoint read };
+allow_map(test_perf_no_write_t, device_t, chr_file)
+
+#
+########### Allow these domains to be entered from sysadm domain ############
+#
+miscfiles_domain_entry_test_files(perfdomain)
+userdom_sysadm_entry_spec_domtrans_to(perfdomain)
@@ -78,6 +78,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
new file mode 100644
@@ -0,0 +1 @@
+perf_event
new file mode 100644
@@ -0,0 +1,7 @@
+TARGETS = perf_event
+LDLIBS += -lselinux
+
+all: $(TARGETS)
+
+clean:
+ rm -f $(TARGETS)
new file mode 100644
@@ -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;
+}
new file mode 100755
@@ -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;
Test perf_event permissions. Signed-off-by: Richard Haines <richard_c_haines@btinternet.com> --- V2 Changes: Remove neverallows from policy Check /proc/sys/kernel/perf_event_paranoid, if < 2 then bypass the capability { sys_admin } test. defconfig | 6 ++ policy/Makefile | 4 + policy/test_perf_event.te | 104 ++++++++++++++++++++ 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, 397 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