All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] selinux-testsuite:  add inet_socket tests
@ 2015-06-16 17:06 Stephen Smalley
  0 siblings, 0 replies; only message in thread
From: Stephen Smalley @ 2015-06-16 17:06 UTC (permalink / raw)
  To: selinux; +Cc: Stephen Smalley

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@tycho.nsa.gov>
---
 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       | 176 +++++++++++++++++++++++++++++++++++++++
 tests/inet_socket/test           |  50 +++++++++++
 9 files changed, 416 insertions(+), 2 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..f3c5348
--- /dev/null
+++ b/policy/test_inet_socket.te
@@ -0,0 +1,60 @@
+#################################
+#
+# Policy for testing Inet/local 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..10edb22
--- /dev/null
+++ b/tests/inet_socket/server.c
@@ -0,0 +1,176 @@
+#define _GNU_SOURCE
+#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 (%u)\n", argv[0], peerlabel,
+		       labellen);
+
+		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 (%u)\n",
+					       argv[0], msglabel, len);
+				}
+			}
+		}
+
+		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;
-- 
2.1.0

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2015-06-16 17:06 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-06-16 17:06 [PATCH] selinux-testsuite: add inet_socket tests Stephen Smalley

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.