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 <[email protected]>
---
 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


-- 
AppArmor mailing list
[email protected]
Modify settings or unsubscribe at: 
https://lists.ubuntu.com/mailman/listinfo/apparmor

Reply via email to