[apparmor] [PATCH v2 11/11] tests: Add unnamed socket tests

Tyler Hicks tyhicks at canonical.com
Mon Sep 15 19:56:04 UTC 2014


Tests abstract UNIX domain sockets with various combinations of implied
permissions, explicit permissions, and conditionals. It also tests with
bad permissions and conditionals.

Signed-off-by: Tyler Hicks <tyhicks at canonical.com>
---
 tests/regression/apparmor/unix_socket.c          |  89 +++++++++++++-----
 tests/regression/apparmor/unix_socket_client.c   | 113 +++++++++++++++--------
 tests/regression/apparmor/unix_socket_unnamed.sh | 109 ++++++++++++++++++++++
 3 files changed, 248 insertions(+), 63 deletions(-)
 create mode 100755 tests/regression/apparmor/unix_socket_unnamed.sh

diff --git a/tests/regression/apparmor/unix_socket.c b/tests/regression/apparmor/unix_socket.c
index 1b89c45..a895a26 100644
--- a/tests/regression/apparmor/unix_socket.c
+++ b/tests/regression/apparmor/unix_socket.c
@@ -14,6 +14,8 @@
  * along with this program; if not, contact Canonical Ltd.
  */
 
+#define _GNU_SOURCE
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -21,18 +23,24 @@
 #include <sys/types.h>
 #include <sys/un.h>
 #include <unistd.h>
+#include <fcntl.h>
 
-#define MSG_BUF_MAX 1024
+#define MSG_BUF_MAX 		1024
+#define PATH_FOR_UNNAMED	"none"
 
-static int connection_based_messaging(int sock, char *msg_buf,
-				      size_t msg_buf_len)
+static int connection_based_messaging(int sock, int sock_is_peer_sock,
+				      char *msg_buf, size_t msg_buf_len)
 {
 	int peer_sock, rc;
 
-	peer_sock = accept(sock, NULL, NULL);
-	if (peer_sock < 0) {
-		perror("FAIL - accept");
-		return 1;
+	if (sock_is_peer_sock) {
+		peer_sock = sock;
+	} else {
+		peer_sock = accept(sock, NULL, NULL);
+		if (peer_sock < 0) {
+			perror("FAIL - accept");
+			return 1;
+		}
 	}
 
 	rc = write(peer_sock, msg_buf, msg_buf_len);
@@ -118,7 +126,8 @@ int main (int argc, char *argv[])
 	const char *sun_path;
 	size_t sun_path_len;
 	pid_t pid;
-	int sock, type, rc;
+	int sock, peer_sock, type, rc;
+	int unnamed = 0;
 
 	if (argc != 5) {
 		fprintf(stderr,
@@ -141,6 +150,8 @@ int main (int argc, char *argv[])
 		}
 		memcpy(addr.sun_path, sun_path, sun_path_len);
 		addr.sun_path[0] = '\0';
+	} else if (!strcmp(sun_path, PATH_FOR_UNNAMED)) {
+		unnamed = 1;
 	} else {
 		/* include the nul terminator for pathname addr types */
 		sun_path_len++;
@@ -169,25 +180,43 @@ int main (int argc, char *argv[])
 	}
 	memcpy(msg_buf, argv[3], msg_buf_len);
 
-	sock = socket(AF_UNIX, type | SOCK_CLOEXEC, 0);
-	if (sock == -1) {
-		perror("FAIL - socket");
-		exit(1);
-	}
+	if (unnamed) {
+		int sv[2];
 
-	rc = bind(sock, (struct sockaddr *)&addr,
-		  sun_path_len + sizeof(addr.sun_family));
-	if (rc < 0) {
-		perror("FAIL - bind");
-		exit(1);
-	}
+		rc = socketpair(AF_UNIX, type, 0, sv);
+		if (rc == -1) {
+			perror("FAIL - socketpair");
+			exit(1);
+		}
+		sock = sv[0];
+		peer_sock = sv[1];
 
-	if (type & SOCK_STREAM || type & SOCK_SEQPACKET) {
-		rc = listen(sock, 2);
+		rc = fcntl(sock, F_SETFD, FD_CLOEXEC);
+		if (rc == -1) {
+			perror("FAIL - fcntl");
+			exit(1);
+		}
+	} else {
+		sock = socket(AF_UNIX, type | SOCK_CLOEXEC, 0);
+		if (sock == -1) {
+			perror("FAIL - socket");
+			exit(1);
+		}
+
+		rc = bind(sock, (struct sockaddr *)&addr,
+			  sun_path_len + sizeof(addr.sun_family));
 		if (rc < 0) {
-			perror("FAIL - listen");
+			perror("FAIL - bind");
 			exit(1);
 		}
+
+		if (type & SOCK_STREAM || type & SOCK_SEQPACKET) {
+			rc = listen(sock, 2);
+			if (rc < 0) {
+				perror("FAIL - listen");
+				exit(1);
+			}
+		}
 	}
 
 	pid = fork();
@@ -195,8 +224,20 @@ int main (int argc, char *argv[])
 		perror("FAIL - fork");
 		exit(1);
 	} else if (!pid) {
-		execl(argv[4], argv[4], sun_path, argv[2], NULL);
+		char *fd_number = NULL;
+
+		if (unnamed) {
+			rc = asprintf(&fd_number, "%d", peer_sock);
+			if (rc == -1) {
+				perror("FAIL - asprintf");
+				exit(1);
+			}
+		}
+
+		/* fd_number will be NULL for pathname and abstract sockets */
+		execl(argv[4], argv[4], sun_path, argv[2], fd_number, NULL);
 		perror("FAIL - execl");
+		free(fd_number);
 		exit(1);
 	}
 
@@ -205,7 +246,7 @@ int main (int argc, char *argv[])
 		exit(1);
 
 	rc = (type & SOCK_STREAM || type & SOCK_SEQPACKET) ?
-		connection_based_messaging(sock, msg_buf, msg_buf_len) :
+		connection_based_messaging(sock, unnamed, msg_buf, msg_buf_len) :
 		connectionless_messaging(sock, msg_buf, msg_buf_len);
 	if (rc)
 		exit(1);
diff --git a/tests/regression/apparmor/unix_socket_client.c b/tests/regression/apparmor/unix_socket_client.c
index 015c41d..a4ccf0c 100644
--- a/tests/regression/apparmor/unix_socket_client.c
+++ b/tests/regression/apparmor/unix_socket_client.c
@@ -22,21 +22,25 @@
 #include <sys/un.h>
 #include <unistd.h>
 
-#define MSG_BUF_MAX	1024
+#define MSG_BUF_MAX 		1024
+#define PATH_FOR_UNNAMED	"none"
 
 #define SUN_PATH_SUFFIX		".client"
 #define SUN_PATH_SUFFIX_LEN	strlen(SUN_PATH_SUFFIX)
 
+/* Pass NULL for peer_addr if the two sockets are already connected */
 static int connection_based_messaging(int sock, struct sockaddr_un *peer_addr,
 				      socklen_t peer_addr_len)
 {
 	char msg_buf[MSG_BUF_MAX];
 	int rc;
 
-	rc = connect(sock, (struct sockaddr *)peer_addr, peer_addr_len);
-	if (rc < 0) {
-		perror("FAIL CLIENT - connect");
-		exit(1);
+	if (peer_addr) {
+		rc = connect(sock, (struct sockaddr *)peer_addr, peer_addr_len);
+		if (rc < 0) {
+			perror("FAIL CLIENT - connect");
+			exit(1);
+		}
 	}
 
 	rc = read(sock, msg_buf, MSG_BUF_MAX);
@@ -54,37 +58,42 @@ static int connection_based_messaging(int sock, struct sockaddr_un *peer_addr,
 	return 0;
 }
 
+/* Pass NULL for peer_addr if the two sockets are already connected */
 static int connectionless_messaging(int sock, struct sockaddr_un *peer_addr,
 				    socklen_t peer_addr_len)
 {
-	struct sockaddr_un addr;
-	size_t peer_path_len = peer_addr_len - sizeof(addr.sun_family);
-	size_t path_len = peer_path_len + SUN_PATH_SUFFIX_LEN;
 	char msg_buf[MSG_BUF_MAX];
 	socklen_t len = peer_addr_len;
 	int rc;
 
-	if (path_len > sizeof(addr.sun_path)) {
-		fprintf(stderr, "FAIL CLIENT - path_len too big\n");
-		return 1;
-	}
-
-	/**
-	 * Subtract 1 to get rid of nul-terminator in pathname address types.
-	 * We're essentially moving the nul char so path_len stays the same.
-	 */
-	if (peer_addr->sun_path[0])
-		peer_path_len--;
+	if (peer_addr) {
+		struct sockaddr_un addr;
+		size_t peer_path_len = peer_addr_len - sizeof(addr.sun_family);
+		size_t path_len = peer_path_len + SUN_PATH_SUFFIX_LEN;
 
-	addr.sun_family = AF_UNIX;
-	memcpy(addr.sun_path, peer_addr->sun_path, peer_path_len);
-	strcpy(addr.sun_path + peer_path_len, SUN_PATH_SUFFIX);
+		if (path_len > sizeof(addr.sun_path)) {
+			fprintf(stderr, "FAIL CLIENT - path_len too big\n");
+			return 1;
+		}
 
-	rc = bind(sock, (struct sockaddr *)&addr,
-		  path_len + sizeof(addr.sun_family));
-	if (rc < 0) {
-		perror("FAIL CLIENT - bind");
-		return 1;
+		/**
+		 * Subtract 1 to get rid of nul-terminator in pathname address
+		 * types. We're essentially moving the nul char so path_len
+		 * stays the same.
+		 */
+		if (peer_addr->sun_path[0])
+			peer_path_len--;
+
+		addr.sun_family = AF_UNIX;
+		memcpy(addr.sun_path, peer_addr->sun_path, peer_path_len);
+		strcpy(addr.sun_path + peer_path_len, SUN_PATH_SUFFIX);
+
+		rc = bind(sock, (struct sockaddr *)&addr,
+			  path_len + sizeof(addr.sun_family));
+		if (rc < 0) {
+			perror("FAIL CLIENT - bind");
+			return 1;
+		}
 	}
 
 	rc = sendto(sock, NULL, 0, 0, (struct sockaddr *)peer_addr, len);
@@ -154,18 +163,26 @@ static int test_getattr(int sock)
 	return 0;
 }
 
+static void usage(const char *name)
+{
+	fprintf(stderr, "Usage: %s <socket> <type> [<fd_number>]\n\n"
+		"  type\t\tstream, dgram, or seqpacket\n"
+		"  fd_number\t\tfd number for inherited unnamed socket\n",
+		name);
+}
+
 int main(int argc, char *argv[])
 {
-	struct sockaddr_un peer_addr, *pa;
-	socklen_t pa_len;
+	struct sockaddr_un peer_addr, *pa = NULL;
+	socklen_t pa_len = 0;
 	const char *sun_path;
 	size_t sun_path_len;
 	int sock, type, rc;
+	int unnamed = 0;
+	const char *fd_number = NULL;
 
-	if (argc != 3) {
-		fprintf(stderr, "Usage: %s <socket> <type>\n\n"
-			"  type\t\tstream, dgram, or seqpacket\n",
-			argv[0]);
+	if (argc < 3 || argc > 4) {
+		usage(argv[0]);
 		exit(1);
 	}
 
@@ -181,6 +198,13 @@ int main(int argc, char *argv[])
 		}
 		memcpy(peer_addr.sun_path, sun_path, sun_path_len);
 		peer_addr.sun_path[0] = '\0';
+	} else if (!strcmp(sun_path, PATH_FOR_UNNAMED)) {
+		unnamed = 1;
+		if (argc != 4) {
+			usage(argv[0]);
+			exit(1);
+		}
+		fd_number = argv[3];
 	} else {
 		/* include the nul terminator for pathname addr types */
 		sun_path_len++;
@@ -202,10 +226,19 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	sock = socket(AF_UNIX, type, 0);
-	if (sock < 0) {
-		perror("FAIL CLIENT - socket");
-		exit(1);
+	if (unnamed) {
+		rc = sscanf(fd_number, "%d", &sock);
+		if (rc != 1) {
+			perror("FAIL CLIENT - sscanf");
+			usage(argv[0]);
+			exit(1);
+		}
+	} else {
+		sock = socket(AF_UNIX, type, 0);
+		if (sock < 0) {
+			perror("FAIL CLIENT - socket");
+			exit(1);
+		}
 	}
 
 	rc = get_set_sock_io_timeo(sock);
@@ -216,8 +249,10 @@ int main(int argc, char *argv[])
 	if (rc)
 		exit(1);
 
-	pa = &peer_addr;
-	pa_len = sun_path_len + sizeof(peer_addr.sun_family);
+	if (!unnamed) {
+		pa = &peer_addr;
+		pa_len = sun_path_len + sizeof(peer_addr.sun_family);
+	}
 
 	rc = (type == SOCK_STREAM || type == SOCK_SEQPACKET) ?
 		connection_based_messaging(sock, pa, pa_len) :
diff --git a/tests/regression/apparmor/unix_socket_unnamed.sh b/tests/regression/apparmor/unix_socket_unnamed.sh
new file mode 100755
index 0000000..4da51f9
--- /dev/null
+++ b/tests/regression/apparmor/unix_socket_unnamed.sh
@@ -0,0 +1,109 @@
+#! /bin/bash
+#
+# Copyright (C) 2014 Canonical, Ltd.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of version 2 of the GNU General Public
+# License published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, contact Canonical Ltd.
+
+#=NAME unix_socket_unnamed
+#=DESCRIPTION
+# This tests access to unnamed unix domain sockets. The server opens a socket,
+# forks a client with it's own profile, passes an fd across exec, sends a
+# message to the client over the socket pair, and sees what happens.
+#=END
+
+pwd=`dirname $0`
+pwd=`cd $pwd ; /bin/pwd`
+
+bin=$pwd
+
+. $bin/prologue.inc
+. $bin/unix_socket.inc
+requires_features policy/versions/v7
+requires_features network/af_unix
+
+settest unix_socket
+
+addr=none
+client_addr=none
+
+# Test unnamed stream server and client
+test_server "unnamed" \
+	    "create,getopt,setopt,shutdown" \
+	    stream \
+	    "$addr" \
+	    "read,write" \
+	    "$test" \
+	    "" \
+	    dgram \
+	    "@none" \
+	    "${test}XXX" \
+	    ""
+test_client "unnamed" \
+	    "getopt,setopt,getattr" \
+	    stream \
+	    "" \
+	    "write,read" \
+	    "$test" \
+	    "$addr" \
+	    seqpacket \
+	    "" \
+	    "${test}XXX" \
+	    "@none"
+
+# Test unnamed dgram server and client
+test_server "unnamed" \
+	    "create,getopt,setopt,shutdown" \
+	    dgram \
+	    "$addr" \
+	    "read,write" \
+	    "$test" \
+	    "$client_addr" \
+	    seqpacket \
+	    "@none" \
+	    "${test}XXX" \
+	    "@none"
+test_client "unnamed" \
+	    "getopt,setopt,getattr" \
+	    dgram \
+	    "$client_addr" \
+	    "write,read" \
+	    "$test" \
+	    "$addr" \
+	    stream \
+	    "@none" \
+	    "${test}XXX" \
+	    "@none"
+
+# Test unnamed seqpacket server and client
+test_server "unnamed" \
+	    "create,getopt,setopt,shutdown" \
+	    seqpacket \
+	    "$addr" \
+	    "read,write" \
+	    "$test" \
+	    "" \
+	    stream \
+	    "@none" \
+	    "${test}XXX" \
+	    ""
+test_client "unnamed" \
+	    "getopt,setopt,getattr" \
+	    seqpacket \
+	    "" \
+	    "write,read" \
+	    "$test" \
+	    "$addr" \
+	    dgram \
+	    "" \
+	    "${test}XXX" \
+	    "@none"
-- 
2.1.0




More information about the AppArmor mailing list