diff mbox series

selinux-testsuite: Add key_socket tests

Message ID 20191110162618.395932-1-richard_c_haines@btinternet.com (mailing list archive)
State Superseded
Headers show
Series selinux-testsuite: Add key_socket tests | expand

Commit Message

Richard Haines Nov. 10, 2019, 4:26 p.m. UTC
Test relevant key management socket permissions.

Signed-off-by: Richard Haines <richard_c_haines@btinternet.com>
---
 defconfig                   |   4 ++
 policy/Makefile             |   4 ++
 policy/test_key_socket.te   |  74 +++++++++++++++++++
 tests/Makefile              |   4 ++
 tests/key_socket/.gitignore |   1 +
 tests/key_socket/Makefile   |   7 ++
 tests/key_socket/key_sock.c | 139 ++++++++++++++++++++++++++++++++++++
 tests/key_socket/test       |  45 ++++++++++++
 8 files changed, 278 insertions(+)
 create mode 100644 policy/test_key_socket.te
 create mode 100644 tests/key_socket/.gitignore
 create mode 100644 tests/key_socket/Makefile
 create mode 100644 tests/key_socket/key_sock.c
 create mode 100755 tests/key_socket/test
diff mbox series

Patch

diff --git a/defconfig b/defconfig
index b13075d..0574f1d 100644
--- a/defconfig
+++ b/defconfig
@@ -74,3 +74,7 @@  CONFIG_BPF_SYSCALL=y
 CONFIG_KEYS=y
 CONFIG_KEYS_COMPAT=y
 CONFIG_KEY_DH_OPERATIONS=y
+
+# Test key management socket.
+# This is not required for SELinux operation itself.
+CONFIG_NET_KEY=m
diff --git a/policy/Makefile b/policy/Makefile
index ff65153..ad94c43 100644
--- a/policy/Makefile
+++ b/policy/Makefile
@@ -90,6 +90,10 @@  ifeq ($(shell grep -q all_file_perms.*watch $(POLDEV)/include/support/all_perms.
 TARGETS+=test_notify.te
 endif
 
+ifeq ($(shell grep -q key_socket $(POLDEV)/include/support/all_perms.spt && echo true),true)
+TARGETS += test_key_socket.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_key_socket.te b/policy/test_key_socket.te
new file mode 100644
index 0000000..6906010
--- /dev/null
+++ b/policy/test_key_socket.te
@@ -0,0 +1,74 @@ 
+#
+############## Test key management socket 'key_socket' #####################
+#
+attribute keysockdomain;
+
+type test_key_sock_t;
+domain_type(test_key_sock_t)
+unconfined_runs_test(test_key_sock_t)
+typeattribute test_key_sock_t testdomain;
+typeattribute test_key_sock_t keysockdomain;
+
+# key_socket rules:
+allow test_key_sock_t self:rawip_socket { create };
+allow test_key_sock_t self:capability { net_admin };
+allow test_key_sock_t self:key_socket { create write read setopt };
+# For CONFIG_NET_KEY=m
+allow test_key_sock_t kernel_t:system { module_request };
+
+################## Deny capability { net_admin } ##########################
+#
+# Note that when capability { net_admin } is removed for the test
+# there will not be an audit message in the log as the Fedora policy
+# is built with 'hide_broken_symptoms' that adds the following:
+#   dontaudit test_key_sock_no_net_admin_t self:capability { net_admin sys_module };
+#
+type test_key_sock_no_net_admin_t;
+domain_type(test_key_sock_no_net_admin_t)
+unconfined_runs_test(test_key_sock_no_net_admin_t)
+typeattribute test_key_sock_no_net_admin_t testdomain;
+typeattribute test_key_sock_no_net_admin_t keysockdomain;
+
+allow test_key_sock_no_net_admin_t self:rawip_socket { create };
+allow test_key_sock_no_net_admin_t self:key_socket { create write read setopt };
+allow test_key_sock_no_net_admin_t kernel_t:system { module_request };
+
+####################### Deny key_socket { create } ##########################
+type test_key_sock_no_create_t;
+domain_type(test_key_sock_no_create_t)
+unconfined_runs_test(test_key_sock_no_create_t)
+typeattribute test_key_sock_no_create_t testdomain;
+typeattribute test_key_sock_no_create_t keysockdomain;
+
+allow test_key_sock_no_create_t self:rawip_socket { create };
+allow test_key_sock_no_create_t self:capability { net_admin };
+allow test_key_sock_no_create_t self:key_socket { write read setopt };
+
+####################### Deny key_socket { write } ##########################
+type test_key_sock_no_write_t;
+domain_type(test_key_sock_no_write_t)
+unconfined_runs_test(test_key_sock_no_write_t)
+typeattribute test_key_sock_no_write_t testdomain;
+typeattribute test_key_sock_no_write_t keysockdomain;
+
+allow test_key_sock_no_write_t self:rawip_socket { create };
+allow test_key_sock_no_write_t self:capability { net_admin };
+allow test_key_sock_no_write_t self:key_socket { create read setopt };
+allow test_key_sock_no_write_t kernel_t:system { module_request };
+
+####################### Deny key_socket { read } ##########################
+type test_key_sock_no_read_t;
+domain_type(test_key_sock_no_read_t)
+unconfined_runs_test(test_key_sock_no_read_t)
+typeattribute test_key_sock_no_read_t testdomain;
+typeattribute test_key_sock_no_read_t keysockdomain;
+
+allow test_key_sock_no_read_t self:rawip_socket { create };
+allow test_key_sock_no_read_t self:capability { net_admin };
+allow test_key_sock_no_read_t self:key_socket { create write setopt };
+allow test_key_sock_no_read_t kernel_t:system { module_request };
+#
+########### Allow these domains to be entered from sysadm domain ############
+#
+miscfiles_domain_entry_test_files(keysockdomain)
+userdom_sysadm_entry_spec_domtrans_to(keysockdomain)
diff --git a/tests/Makefile b/tests/Makefile
index 0021590..cca6648 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -52,6 +52,10 @@  ifeq ($(shell grep -q all_key_perms $(POLDEV)/include/support/all_perms.spt && e
 SUBDIRS += keys
 endif
 
+ifeq ($(shell grep -q key_socket $(POLDEV)/include/support/all_perms.spt && test -e $(INCLUDEDIR)/keyutils.h && echo true),true)
+SUBDIRS += key_socket
+endif
+
 ifeq ($(shell grep "^SELINUX_INFINIBAND_ENDPORT_TEST=" infiniband_endport/ibendport_test.conf | cut -d'=' -f 2),1)
 SUBDIRS += infiniband_endport
 endif
diff --git a/tests/key_socket/.gitignore b/tests/key_socket/.gitignore
new file mode 100644
index 0000000..1a532c0
--- /dev/null
+++ b/tests/key_socket/.gitignore
@@ -0,0 +1 @@ 
+key_sock
diff --git a/tests/key_socket/Makefile b/tests/key_socket/Makefile
new file mode 100644
index 0000000..e5e6a58
--- /dev/null
+++ b/tests/key_socket/Makefile
@@ -0,0 +1,7 @@ 
+TARGETS = key_sock
+LDLIBS += -lselinux
+
+all: $(TARGETS)
+
+clean:
+	rm -f $(TARGETS)
diff --git a/tests/key_socket/key_sock.c b/tests/key_socket/key_sock.c
new file mode 100644
index 0000000..95622b7
--- /dev/null
+++ b/tests/key_socket/key_sock.c
@@ -0,0 +1,139 @@ 
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+#include <linux/pfkeyv2.h>
+#include <selinux/selinux.h>
+
+static void print_usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [-v]\n"
+		"Where:\n\t"
+		"-v  Print information.\n", progname);
+	exit(-1);
+}
+
+int main(int argc, char *argv[])
+{
+	char *context;
+	int opt, sock, result;
+	bool verbose = false;
+	struct timeval tm;
+	struct sadb_msg w_msg, r_msg;
+	int mlen = sizeof(struct sadb_msg);
+
+	while ((opt = getopt(argc, argv, "v")) != -1) {
+		switch (opt) {
+		case 'v':
+			verbose = true;
+			break;
+		default:
+			print_usage(argv[0]);
+		}
+	}
+
+	result = getcon(&context);
+	if (result < 0) {
+		fprintf(stderr, "Failed to obtain process context\n");
+		exit(1);
+	}
+
+	if (verbose)
+		printf("Process context:\n\t%s\n", context);
+
+	sock = socket(PF_KEY, SOCK_RAW, PF_KEY_V2);
+	if (sock < 0) {
+		fprintf(stderr, "Failed to open key management socket: %s\n",
+			strerror(errno));
+		/* Return errno as denying net_admin=EPERM, create=EACCES */
+		exit(errno);
+	}
+
+	if (verbose)
+		printf("Opened key management socket\n");
+
+	/* Set socket timeout for read in case no response from kernel */
+	tm.tv_sec = 3;
+	tm.tv_usec = 0;
+	result = setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tm, sizeof(tm));
+	if (result < 0) {
+		fprintf(stderr, "Failed setsockopt SO_RCVTIMEO: %s\n",
+			strerror(errno));
+		result = 2;
+		goto error;
+	}
+
+	if (verbose)
+		printf("setsocketopt: SO_RCVTIMEO - %ld seconds\n", tm.tv_sec);
+
+	memset(&w_msg, 0, mlen);
+	w_msg.sadb_msg_version = PF_KEY_V2;
+	w_msg.sadb_msg_type = SADB_FLUSH;
+	w_msg.sadb_msg_satype = SADB_SATYPE_AH;
+	/* sadb_msg_len contains length in 64-bit words */
+	w_msg.sadb_msg_len = (mlen / sizeof(uint64_t));
+	w_msg.sadb_msg_seq = 99;
+	w_msg.sadb_msg_pid = getpid();
+
+	result = write(sock, &w_msg, mlen);
+	if (result < 0) {
+		fprintf(stderr, "Failed write to key management socket: %s\n",
+			strerror(errno));
+		result = 3;
+		goto error;
+	}
+
+	if (verbose) {
+		printf("Write sadb_msg data to key management socket:\n");
+		printf("\tver: PF_KEY_V2 type: SADB_FLUSH sa_type: SADB_SATYPE_AH\n");
+		printf("\tseq: %d pid: %d\n", w_msg.sadb_msg_seq,
+		       w_msg.sadb_msg_pid);
+	}
+
+	memset(&r_msg, 0, mlen);
+
+	result = read(sock, &r_msg, mlen);
+	if (result < 0) {
+		fprintf(stderr, "Failed to read key management socket: %s\n",
+			strerror(errno));
+		result = 4;
+		goto error;
+	}
+
+	if (r_msg.sadb_msg_version != w_msg.sadb_msg_version ||
+	    r_msg.sadb_msg_type != w_msg.sadb_msg_type ||
+	    r_msg.sadb_msg_satype != w_msg.sadb_msg_satype ||
+	    r_msg.sadb_msg_seq != w_msg.sadb_msg_seq ||
+	    r_msg.sadb_msg_pid != getpid()) {
+		fprintf(stderr, "Failed to read correct sadb_msg data:\n");
+		fprintf(stderr, "\tSent - ver: %d type: %d sa_type: %d seq: %d pid: %d\n",
+			w_msg.sadb_msg_version, w_msg.sadb_msg_type,
+			w_msg.sadb_msg_satype, w_msg.sadb_msg_seq,
+			w_msg.sadb_msg_pid);
+		fprintf(stderr, "\tRecv - ver: %d type: %d sa_type: %d seq: %d pid: %d\n",
+			r_msg.sadb_msg_version, r_msg.sadb_msg_type,
+			r_msg.sadb_msg_satype, r_msg.sadb_msg_seq,
+			r_msg.sadb_msg_pid);
+		result = 5;
+		goto error;
+	}
+
+	if (verbose) {
+		printf("Read sadb_msg data from key management socket:\n");
+		printf("\tver: PF_KEY_V2 type: SADB_FLUSH sa_type: SADB_SATYPE_AH\n");
+		printf("\tseq: %d pid: %d\n", r_msg.sadb_msg_seq,
+		       r_msg.sadb_msg_pid);
+	}
+
+	result = 0;
+
+error:
+	close(sock);
+
+	return result;
+}
diff --git a/tests/key_socket/test b/tests/key_socket/test
new file mode 100755
index 0000000..9772611
--- /dev/null
+++ b/tests/key_socket/test
@@ -0,0 +1,45 @@ 
+#!/usr/bin/perl
+use Test::More;
+
+BEGIN {
+    $basedir = $0;
+    $basedir =~ s|(.*)/[^/]*|$1|;
+
+    # 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 = " ";
+    }
+
+    plan tests => 5;
+}
+
+############ Test key_socket #############
+print "Test key_socket class\n";
+$result = system "runcon -t test_key_sock_t $basedir/key_sock $v";
+ok( $result eq 0 );
+
+# Deny capability { net_admin } - EPERM
+$result =
+  system "runcon -t test_key_sock_no_net_admin_t $basedir/key_sock $v 2>&1";
+ok( $result >> 8 eq 1 );
+
+# Deny key_socket { create } - EACCES
+$result =
+  system "runcon -t test_key_sock_no_create_t $basedir/key_sock $v 2>&1";
+ok( $result >> 8 eq 13 );
+
+# Deny key_socket { write }
+$result = system "runcon -t test_key_sock_no_write_t $basedir/key_sock $v 2>&1";
+ok( $result >> 8 eq 3 );
+
+# Deny key_socket { read }
+$result = system "runcon -t test_key_sock_no_read_t $basedir/key_sock $v 2>&1";
+ok( $result >> 8 eq 4 );
+
+exit;