@@ -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
@@ -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
new file mode 100644
@@ -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)
@@ -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
new file mode 100644
@@ -0,0 +1 @@
+key_sock
new file mode 100644
@@ -0,0 +1,7 @@
+TARGETS = key_sock
+LDLIBS += -lselinux
+
+all: $(TARGETS)
+
+clean:
+ rm -f $(TARGETS)
new file mode 100644
@@ -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;
+}
new file mode 100755
@@ -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;
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