[PATCH v2] selinux-testsuite: add inet_socket tests

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

 



Add a set of tests for INET sockets that exercise the SO_PEERSEC
and SCM_SECURITY functionality and test the peer recv permission check.
Load a NetLabel configuration during testing to enable full SELinux
labeling over loopback.

Other candidates for future tests:
- Test other INET socket permission checks, such as socket name_bind,
node_bind, name_connect, netif ingress/egress, and node recvfrom/sendto,
- Test SECMARK packet labeling and packet permission checks,
- Test labeled IPSEC peer labeling (over loopback possible?),
- Optionally test cross-machine peer labeling via NetLabel or labeled IPSEC
(requires more complex test setup).

Presently this test does not work on F22 due to a problem with
netlabel_tools, but it did pass on F21 for me.

Signed-off-by: Stephen Smalley <sds@xxxxxxxxxxxxx>
---

Changes from V1:
Fixed a comment.
Fixed a couple of compiler warnings.

 policy/Makefile                  |   2 +-
 policy/test_inet_socket.te       |  60 ++++++++++++++
 tests/Makefile                   |   2 +-
 tests/inet_socket/Makefile       |   7 ++
 tests/inet_socket/client.c       | 102 +++++++++++++++++++++++
 tests/inet_socket/netlabel-flush |   8 ++
 tests/inet_socket/netlabel-load  |  11 +++
 tests/inet_socket/server.c       | 174 +++++++++++++++++++++++++++++++++++++++
 tests/inet_socket/test           |  50 +++++++++++
 tests/unix_socket/server.c       |   1 -
 10 files changed, 414 insertions(+), 3 deletions(-)
 create mode 100644 policy/test_inet_socket.te
 create mode 100644 tests/inet_socket/Makefile
 create mode 100644 tests/inet_socket/client.c
 create mode 100755 tests/inet_socket/netlabel-flush
 create mode 100755 tests/inet_socket/netlabel-load
 create mode 100644 tests/inet_socket/server.c
 create mode 100755 tests/inet_socket/test

diff --git a/policy/Makefile b/policy/Makefile
index 25777bb..742fd03 100644
--- a/policy/Makefile
+++ b/policy/Makefile
@@ -19,7 +19,7 @@ TARGETS = \
 	test_setnice.te test_sigkill.te test_stat.te test_sysctl.te \
 	test_task_create.te test_task_getpgid.te test_task_getsched.te \
 	test_task_getsid.te test_task_setpgid.te test_task_setsched.te \
-	test_transition.te test_unix_socket.te test_wait.te
+	test_transition.te test_inet_socket.te test_unix_socket.te test_wait.te
 
 ifeq ($(shell [ $(POL_VERS) -ge 24 ] && echo true),true)
 TARGETS += test_bounds.te
diff --git a/policy/test_inet_socket.te b/policy/test_inet_socket.te
new file mode 100644
index 0000000..9e01a8c
--- /dev/null
+++ b/policy/test_inet_socket.te
@@ -0,0 +1,60 @@
+#################################
+#
+# Policy for testing INET domain sockets.
+#
+
+attribute inetsocketdomain;
+
+# Do not break NFS when we load NetLabel configuration.
+gen_require(`
+	type kernel_t;
+')
+corenet_all_recvfrom_unlabeled(kernel_t)
+
+# Domain for server process.
+type test_inet_server_t;
+domain_type(test_inet_server_t)
+unconfined_runs_test(test_inet_server_t)
+typeattribute test_inet_server_t testdomain;
+typeattribute test_inet_server_t inetsocketdomain;
+allow test_inet_server_t self:tcp_socket create_stream_socket_perms;
+allow test_inet_server_t self:udp_socket create_socket_perms;
+corenet_tcp_bind_generic_port(test_inet_server_t)
+corenet_udp_bind_generic_port(test_inet_server_t)
+corenet_tcp_bind_all_nodes(test_inet_server_t)
+corenet_udp_bind_all_nodes(test_inet_server_t)
+corenet_inout_generic_if(test_inet_server_t)
+corenet_inout_generic_node(test_inet_server_t)
+
+# Domain for client process.
+type test_inet_client_t;
+domain_type(test_inet_client_t)
+unconfined_runs_test(test_inet_client_t)
+typeattribute test_inet_client_t testdomain;
+typeattribute test_inet_client_t inetsocketdomain;
+allow test_inet_client_t self:tcp_socket create_stream_socket_perms;
+allow test_inet_client_t self:udp_socket create_socket_perms;
+corenet_tcp_connect_generic_port(test_inet_client_t)
+corenet_inout_generic_if(test_inet_client_t)
+corenet_inout_generic_node(test_inet_client_t)
+
+# The server can receive labeled packets from the client.
+allow test_inet_server_t test_inet_client_t:peer recv;
+# And vice versa.
+allow test_inet_client_t test_inet_server_t:peer recv;
+
+# Domain for a client process not authorized to communicate with the server.
+type test_inet_bad_client_t;
+domain_type(test_inet_bad_client_t)
+unconfined_runs_test(test_inet_bad_client_t)
+typeattribute test_inet_bad_client_t testdomain;
+typeattribute test_inet_bad_client_t inetsocketdomain;
+allow test_inet_bad_client_t self:tcp_socket create_stream_socket_perms;
+allow test_inet_bad_client_t self:udp_socket create_socket_perms;
+corenet_tcp_connect_generic_port(test_inet_bad_client_t)
+corenet_inout_generic_if(test_inet_bad_client_t)
+corenet_inout_generic_node(test_inet_bad_client_t)
+
+# Allow all of these domains to be entered from the sysadm domain.
+miscfiles_domain_entry_test_files(inetsocketdomain)
+userdom_sysadm_entry_spec_domtrans_to(inetsocketdomain)
diff --git a/tests/Makefile b/tests/Makefile
index 5e45bf9..507123b 100644
--- a/tests/Makefile
+++ b/tests/Makefile
@@ -5,7 +5,7 @@ DISTRO=$(shell ./os_detect)
 
 SUBDIRS_COMMON:=domain_trans entrypoint execshare exectrace execute_no_trans fdreceive inherit link mkdir msg open ptrace readlink relabel rename rxdir sem setattr setnice shm sigkill stat sysctl task_create task_setnice task_setscheduler task_getscheduler task_getsid task_getpgid task_setpgid wait file ioctl capable_file capable_net capable_sys unix_socket
 
-SUBDIRS:= $(SUBDIRS_COMMON) dyntrans dyntrace bounds nnp
+SUBDIRS:= $(SUBDIRS_COMMON) dyntrans dyntrace bounds nnp inet_socket
 
 ifeq ($(DISTRO),RHEL4)
     SUBDIRS:=$(SUBDIRS_COMMON)
diff --git a/tests/inet_socket/Makefile b/tests/inet_socket/Makefile
new file mode 100644
index 0000000..5266096
--- /dev/null
+++ b/tests/inet_socket/Makefile
@@ -0,0 +1,7 @@
+TARGETS=client server
+
+LDLIBS+= -lselinux
+
+all: $(TARGETS)
+clean:
+	rm -f $(TARGETS)
diff --git a/tests/inet_socket/client.c b/tests/inet_socket/client.c
new file mode 100644
index 0000000..ffc154c
--- /dev/null
+++ b/tests/inet_socket/client.c
@@ -0,0 +1,102 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/un.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <selinux/selinux.h>
+
+void usage(char *progname)
+{
+	fprintf(stderr,
+		"usage:  %s [stream|dgram] port\n",
+		progname);
+	exit(1);
+}
+
+int
+main(int argc, char **argv)
+{
+	char byte, label[256];
+	int sock;
+	int result;
+	struct sockaddr_in sin;
+	socklen_t sinlen;
+	int type;
+	char *mycon;
+	unsigned short port;
+
+	if (argc != 3)
+		usage(argv[0]);
+
+	if (!strcmp(argv[1], "stream"))
+		type = SOCK_STREAM;
+	else if (!strcmp(argv[1], "dgram"))
+		type = SOCK_DGRAM;
+	else
+		usage(argv[0]);
+
+	port = atoi(argv[2]);
+	if (!port)
+		usage(argv[0]);
+
+	sock = socket(AF_INET, type, 0);
+	if (sock < 0) {
+		perror("socket");
+		exit(1);
+	}
+
+	bzero(&sin, sizeof(struct sockaddr_in));
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(port);
+	if (inet_aton("127.0.0.1", &sin.sin_addr) == 0) {
+		fprintf(stderr, "%s: inet_ntoa: invalid address\n", argv[0]);
+		close(sock);
+		exit(1);
+	}
+
+	sinlen = sizeof(sin);
+	result = connect(sock, (struct sockaddr *) &sin, sinlen);
+	if (result < 0) {
+		perror("connect");
+		close(sock);
+		exit(1);
+	}
+
+	byte = 0;
+	result = write(sock, &byte, 1);
+	if (result < 0) {
+		perror("write");
+		close(sock);
+		exit(1);
+	}
+	result = read(sock, label, sizeof(label));
+	if (result < 0) {
+		perror("read");
+		close(sock);
+		exit(1);
+	}
+	label[result] = 0;
+
+	result = getcon(&mycon);
+	if (result < 0) {
+		perror("getcon");
+		close(sock);
+		exit(1);
+	}
+
+	if (strcmp(mycon, label)) {
+		fprintf(stderr, "%s:  expected %s, got %s\n",
+			argv[0], mycon, label);
+		exit(1);
+	}
+
+	close(sock);
+	exit(0);
+}
diff --git a/tests/inet_socket/netlabel-flush b/tests/inet_socket/netlabel-flush
new file mode 100755
index 0000000..32a5b73
--- /dev/null
+++ b/tests/inet_socket/netlabel-flush
@@ -0,0 +1,8 @@
+#!/bin/sh
+# Reset NetLabel configuration to unlabeled for all.
+netlabelctl map del default
+netlabelctl cipsov4 del doi:1
+netlabelctl map add default protocol:unlbl
+# Display the configuration.
+netlabelctl -p map list
+netlabelctl -p cipsov4 list
diff --git a/tests/inet_socket/netlabel-load b/tests/inet_socket/netlabel-load
new file mode 100755
index 0000000..8110d18
--- /dev/null
+++ b/tests/inet_socket/netlabel-load
@@ -0,0 +1,11 @@
+#!/bin/sh
+# Define a localhost/loopback doi and apply it to the loopback address
+# so that we get full SELinux labels over loopback connections.
+netlabelctl cipsov4 add local doi:1
+netlabelctl map del default
+netlabelctl map add default address:0.0.0.0/0 protocol:unlbl
+netlabelctl map add default address:::/0 protocol:unlbl
+netlabelctl map add default address:127.0.0.1 protocol:cipsov4,1
+# Display the configuration.
+netlabelctl -p cipsov4 list
+netlabelctl -p map list
diff --git a/tests/inet_socket/server.c b/tests/inet_socket/server.c
new file mode 100644
index 0000000..f7f4fdd
--- /dev/null
+++ b/tests/inet_socket/server.c
@@ -0,0 +1,174 @@
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+
+#ifndef SO_PEERSEC
+#define SO_PEERSEC 31
+#endif
+
+#ifndef SCM_SECURITY
+#define SCM_SECURITY 0x03
+#endif
+
+void usage(char *progname)
+{
+	fprintf(stderr, "usage:  %s [stream|dgram] port\n", progname);
+	exit(1);
+}
+
+static const int on = 1;
+
+int
+main(int argc, char **argv)
+{
+	int sock;
+	int result;
+	struct sockaddr_in sin;
+	socklen_t sinlen;
+	int type;
+	char byte;
+	unsigned short port;
+
+	if (argc != 3)
+		usage(argv[0]);
+
+	if (!strcmp(argv[1], "stream"))
+		type = SOCK_STREAM;
+	else if (!strcmp(argv[1], "dgram"))
+		type = SOCK_DGRAM;
+	else
+		usage(argv[0]);
+
+	port = atoi(argv[2]);
+	if (!port)
+		usage(argv[0]);
+
+	sock = socket(AF_INET, type, 0);
+	if (sock < 0) {
+		perror("socket");
+		exit(1);
+	}
+
+	result = setsockopt(sock, SOL_IP, IP_PASSSEC, &on, sizeof(on));
+	if (result < 0) {
+		perror("setsockopt: SO_PASSSEC");
+		close(sock);
+		exit(1);
+	}
+
+	result = setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
+	if (result < 0) {
+		perror("setsockopt: SO_PASSSEC");
+		close(sock);
+		exit(1);
+	}
+
+	bzero(&sin, sizeof(struct sockaddr_in));
+	sin.sin_family = AF_INET;
+	sin.sin_port = htons(port);
+	sin.sin_addr.s_addr = INADDR_ANY;
+	sinlen = sizeof(sin);
+	if (bind(sock, (struct sockaddr *) &sin, sinlen) < 0) {
+		perror("bind");
+		close(sock);
+		exit(1);
+	}
+
+	if (type == SOCK_STREAM) {
+		int newsock;
+		char peerlabel[256];
+		socklen_t labellen = sizeof(peerlabel);
+
+		if (listen(sock, SOMAXCONN)) {
+			perror("listen");
+			close(sock);
+			exit(1);
+		}
+
+		sinlen = sizeof(sin);
+		newsock = accept(sock, (struct sockaddr *)&sin,
+				 &sinlen);
+		if (newsock < 0) {
+			perror("accept");
+			close(sock);
+			exit(1);
+		}
+
+		peerlabel[0] = 0;
+		result = getsockopt(newsock, SOL_SOCKET, SO_PEERSEC, peerlabel,
+				    &labellen);
+		if (result < 0) {
+			perror("getsockopt: SO_PEERSEC");
+			exit(1);
+		}
+		printf("%s:  Got peer label=%s\n", argv[0], peerlabel);
+
+		result = read(newsock, &byte, 1);
+		if (result < 0) {
+			perror("read");
+			exit(1);
+		}
+
+		result = write(newsock, peerlabel, strlen(peerlabel));
+		if (result < 0) {
+			perror("write");
+			exit(1);
+		}
+		close(newsock);
+	} else {
+		struct iovec iov;
+		struct msghdr msg;
+		struct cmsghdr *cmsg;
+		char msglabel[256];
+		union {
+			struct cmsghdr cmsghdr;
+			char buf[CMSG_SPACE(sizeof(msglabel))];
+		} control;
+
+		memset(&iov, 0, sizeof(iov));
+		iov.iov_base = &byte;
+		iov.iov_len = 1;
+		memset(&msg, 0, sizeof(msg));
+		msglabel[0] = 0;
+		msg.msg_name = &sin;
+		msg.msg_namelen = sizeof(sin);
+		msg.msg_iov = &iov;
+		msg.msg_iovlen = 1;
+		msg.msg_control = &control;
+		msg.msg_controllen = sizeof(control);
+		result = recvmsg(sock, &msg, 0);
+		if (result < 0) {
+			perror("recvmsg");
+			exit(1);
+		}
+		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+		     cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+			if (cmsg->cmsg_level == SOL_IP &&
+			    cmsg->cmsg_type == SCM_SECURITY) {
+				size_t len = cmsg->cmsg_len - CMSG_LEN(0);
+
+				if (len > 0 && len < sizeof(msglabel)) {
+					memcpy(msglabel, CMSG_DATA(cmsg), len);
+					msglabel[len] = 0;
+					printf("%s: Got SCM_SECURITY=%s\n",
+					       argv[0], msglabel);
+				}
+			}
+		}
+
+		result = sendto(sock, msglabel, strlen(msglabel), 0,
+				msg.msg_name, msg.msg_namelen);
+		if (result < 0) {
+			perror("sendto");
+			exit(1);
+		}
+	}
+
+	close(sock);
+	exit(0);
+}
diff --git a/tests/inet_socket/test b/tests/inet_socket/test
new file mode 100755
index 0000000..58debd9
--- /dev/null
+++ b/tests/inet_socket/test
@@ -0,0 +1,50 @@
+#!/usr/bin/perl
+
+use Test;
+BEGIN { plan tests => 4}
+
+$basedir = $0;  $basedir =~ s|(.*)/[^/]*|$1|;
+
+# Load NetLabel configuration.
+system "$basedir/netlabel-load";
+
+# Start the stream server.
+if (($pid = fork()) == 0) {
+    exec "runcon -t test_inet_server_t $basedir/server stream 65535";
+}
+
+sleep 1; # Give it a moment to initialize.
+
+# Verify that authorized client can communicate with the server.
+$result = system "runcon -t test_inet_client_t $basedir/client stream 65535";
+ok($result, 0);
+
+# Verify that unauthorized client cannot communicate with the server.
+$result = system "runcon -t test_inet_bad_client_t -- $basedir/client stream 65535 2>&1";
+ok($result);
+
+# Kill the server.
+kill TERM, $pid;
+
+# Start the dgram server.
+if (($pid = fork()) == 0) {
+    exec "runcon -t test_inet_server_t $basedir/server dgram 65535";
+}
+
+sleep 1; # Give it a moment to initialize
+
+# Verify that authorized client can communicate with the server.
+$result = system "runcon -t test_inet_client_t $basedir/client dgram 65535";
+ok($result, 0);
+
+# Verify that unauthorized client cannot communicate with the server.
+$result = system "runcon -t test_inet_bad_client_t -- $basedir/client dgram 65535 2>&1";
+ok($result);
+
+# Kill the server.
+kill TERM, $pid;
+
+# Flush NetLabel configuration.
+system "$basedir/netlabel-flush";
+
+exit;
diff --git a/tests/unix_socket/server.c b/tests/unix_socket/server.c
index 2532de7..89bfdb3 100644
--- a/tests/unix_socket/server.c
+++ b/tests/unix_socket/server.c
@@ -1,4 +1,3 @@
-#define _GNU_SOURCE
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <sys/un.h>
-- 
2.1.0

_______________________________________________
Selinux mailing list
Selinux@xxxxxxxxxxxxx
To unsubscribe, send email to Selinux-leave@xxxxxxxxxxxxx.
To get help, send an email containing "help" to Selinux-request@xxxxxxxxxxxxx.



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

  Powered by Linux