[apparmor] [PATCH v3 7/7] tests: Add unnamed socket tests
Tyler Hicks
tyhicks at canonical.com
Tue Sep 23 00:09:17 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>
---
* Changes since v2:
- Added unix_socket_unnamed to the TESTS variable in the Makefile
- Adjusted unix_socket_abstract.sh to call do_test()
tests/regression/apparmor/Makefile | 1 +
tests/regression/apparmor/unix_socket.c | 91 ++++++++++++-----
tests/regression/apparmor/unix_socket_client.c | 113 +++++++++++++--------
tests/regression/apparmor/unix_socket_unnamed.sh | 121 +++++++++++++++++++++++
4 files changed, 263 insertions(+), 63 deletions(-)
create mode 100755 tests/regression/apparmor/unix_socket_unnamed.sh
diff --git a/tests/regression/apparmor/Makefile b/tests/regression/apparmor/Makefile
index bacd375..497652b 100644
--- a/tests/regression/apparmor/Makefile
+++ b/tests/regression/apparmor/Makefile
@@ -185,6 +185,7 @@ TESTS=access \
unix_fd_server \
unix_socket_pathname \
unix_socket_abstract \
+ unix_socket_unnamed \
unlink\
xattrs\
longpath
diff --git a/tests/regression/apparmor/unix_socket.c b/tests/regression/apparmor/unix_socket.c
index fe593d3..bd43a9e 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,20 +23,26 @@
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
+#include <fcntl.h>
#include "unix_socket_common.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);
@@ -90,7 +98,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,
@@ -113,6 +122,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++;
@@ -141,29 +152,49 @@ 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 = socketpair(AF_UNIX, type, 0, sv);
+ if (rc == -1) {
+ perror("FAIL - socketpair");
+ exit(1);
+ }
+ sock = sv[0];
+ peer_sock = sv[1];
+
+ 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 = set_sock_io_timeo(sock);
if (rc)
exit(1);
- rc = bind(sock, (struct sockaddr *)&addr,
- sun_path_len + sizeof(addr.sun_family));
- if (rc < 0) {
- perror("FAIL - bind");
- exit(1);
- }
-
- if (type & SOCK_STREAM || type & SOCK_SEQPACKET) {
- rc = listen(sock, 2);
+ if (!unnamed) {
+ 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);
+ }
+ }
}
rc = get_sock_io_timeo(sock);
@@ -175,13 +206,25 @@ 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);
}
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 b9da92b..7619aaf 100644
--- a/tests/regression/apparmor/unix_socket_client.c
+++ b/tests/regression/apparmor/unix_socket_client.c
@@ -24,11 +24,13 @@
#include "unix_socket_common.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)
{
@@ -39,10 +41,12 @@ static int connection_based_messaging(int sock, struct sockaddr_un *peer_addr,
if (rc)
return 1;
- 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);
@@ -60,37 +64,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 = get_sock_io_timeo(sock);
@@ -134,18 +143,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);
}
@@ -161,6 +178,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++;
@@ -182,10 +206,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 = set_sock_io_timeo(sock);
@@ -196,8 +229,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..3293fec
--- /dev/null
+++ b/tests/regression/apparmor/unix_socket_unnamed.sh
@@ -0,0 +1,121 @@
+#! /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
+do_test "unnamed" \
+ "server" \
+ "" \
+ "create,getopt,setopt,shutdown" \
+ stream \
+ "$addr" \
+ "read,write" \
+ "$test" \
+ "" \
+ dgram \
+ "@none" \
+ "${test}XXX" \
+ ""
+do_test "unnamed" \
+ "client" \
+ "" \
+ "getopt,setopt,getattr" \
+ stream \
+ "" \
+ "write,read" \
+ "$test" \
+ "$addr" \
+ seqpacket \
+ "" \
+ "${test}XXX" \
+ "@none"
+
+# Test unnamed dgram server and client
+do_test "unnamed" \
+ "server" \
+ "" \
+ "create,getopt,setopt,shutdown" \
+ dgram \
+ "$addr" \
+ "read,write" \
+ "$test" \
+ "$client_addr" \
+ seqpacket \
+ "@none" \
+ "${test}XXX" \
+ "@none"
+do_test "unnamed" \
+ "client" \
+ "" \
+ "getopt,setopt,getattr" \
+ dgram \
+ "$client_addr" \
+ "write,read" \
+ "$test" \
+ "$addr" \
+ stream \
+ "@none" \
+ "${test}XXX" \
+ "@none"
+
+# Test unnamed seqpacket server and client
+do_test "unnamed" \
+ "server" \
+ "" \
+ "create,getopt,setopt,shutdown" \
+ seqpacket \
+ "$addr" \
+ "read,write" \
+ "$test" \
+ "" \
+ stream \
+ "@none" \
+ "${test}XXX" \
+ ""
+do_test "unnamed" \
+ "client" \
+ "" \
+ "getopt,setopt,getattr" \
+ seqpacket \
+ "" \
+ "write,read" \
+ "$test" \
+ "$addr" \
+ dgram \
+ "" \
+ "${test}XXX" \
+ "@none"
--
2.1.0
More information about the AppArmor
mailing list