mirror of
https://gitlab.com/apparmor/apparmor
synced 2025-09-01 06:45:38 +00:00
tests: Add unnamed socket tests
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@canonical.com> Acked-by: Steve Beattie <steve@nxnw.org>
This commit is contained in:
@@ -185,6 +185,7 @@ TESTS=access \
|
|||||||
unix_fd_server \
|
unix_fd_server \
|
||||||
unix_socket_pathname \
|
unix_socket_pathname \
|
||||||
unix_socket_abstract \
|
unix_socket_abstract \
|
||||||
|
unix_socket_unnamed \
|
||||||
unlink\
|
unlink\
|
||||||
xattrs\
|
xattrs\
|
||||||
longpath
|
longpath
|
||||||
|
@@ -14,6 +14,8 @@
|
|||||||
* along with this program; if not, contact Canonical Ltd.
|
* along with this program; if not, contact Canonical Ltd.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -21,20 +23,26 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
#include "unix_socket_common.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,
|
static int connection_based_messaging(int sock, int sock_is_peer_sock,
|
||||||
size_t msg_buf_len)
|
char *msg_buf, size_t msg_buf_len)
|
||||||
{
|
{
|
||||||
int peer_sock, rc;
|
int peer_sock, rc;
|
||||||
|
|
||||||
peer_sock = accept(sock, NULL, NULL);
|
if (sock_is_peer_sock) {
|
||||||
if (peer_sock < 0) {
|
peer_sock = sock;
|
||||||
perror("FAIL - accept");
|
} else {
|
||||||
return 1;
|
peer_sock = accept(sock, NULL, NULL);
|
||||||
|
if (peer_sock < 0) {
|
||||||
|
perror("FAIL - accept");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = write(peer_sock, msg_buf, msg_buf_len);
|
rc = write(peer_sock, msg_buf, msg_buf_len);
|
||||||
@@ -90,7 +98,8 @@ int main (int argc, char *argv[])
|
|||||||
const char *sun_path;
|
const char *sun_path;
|
||||||
size_t sun_path_len;
|
size_t sun_path_len;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int sock, type, rc;
|
int sock, peer_sock, type, rc;
|
||||||
|
int unnamed = 0;
|
||||||
|
|
||||||
if (argc != 5) {
|
if (argc != 5) {
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
@@ -113,6 +122,8 @@ int main (int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
memcpy(addr.sun_path, sun_path, sun_path_len);
|
memcpy(addr.sun_path, sun_path, sun_path_len);
|
||||||
addr.sun_path[0] = '\0';
|
addr.sun_path[0] = '\0';
|
||||||
|
} else if (!strcmp(sun_path, PATH_FOR_UNNAMED)) {
|
||||||
|
unnamed = 1;
|
||||||
} else {
|
} else {
|
||||||
/* include the nul terminator for pathname addr types */
|
/* include the nul terminator for pathname addr types */
|
||||||
sun_path_len++;
|
sun_path_len++;
|
||||||
@@ -141,29 +152,49 @@ int main (int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
memcpy(msg_buf, argv[3], msg_buf_len);
|
memcpy(msg_buf, argv[3], msg_buf_len);
|
||||||
|
|
||||||
sock = socket(AF_UNIX, type | SOCK_CLOEXEC, 0);
|
if (unnamed) {
|
||||||
if (sock == -1) {
|
int sv[2];
|
||||||
perror("FAIL - socket");
|
|
||||||
exit(1);
|
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);
|
rc = set_sock_io_timeo(sock);
|
||||||
if (rc)
|
if (rc)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
rc = bind(sock, (struct sockaddr *)&addr,
|
if (!unnamed) {
|
||||||
sun_path_len + sizeof(addr.sun_family));
|
rc = bind(sock, (struct sockaddr *)&addr,
|
||||||
if (rc < 0) {
|
sun_path_len + sizeof(addr.sun_family));
|
||||||
perror("FAIL - bind");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (type & SOCK_STREAM || type & SOCK_SEQPACKET) {
|
|
||||||
rc = listen(sock, 2);
|
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
perror("FAIL - listen");
|
perror("FAIL - bind");
|
||||||
exit(1);
|
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);
|
rc = get_sock_io_timeo(sock);
|
||||||
@@ -175,13 +206,25 @@ int main (int argc, char *argv[])
|
|||||||
perror("FAIL - fork");
|
perror("FAIL - fork");
|
||||||
exit(1);
|
exit(1);
|
||||||
} else if (!pid) {
|
} 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");
|
perror("FAIL - execl");
|
||||||
|
free(fd_number);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = (type & SOCK_STREAM || type & SOCK_SEQPACKET) ?
|
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);
|
connectionless_messaging(sock, msg_buf, msg_buf_len);
|
||||||
if (rc)
|
if (rc)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@@ -24,11 +24,13 @@
|
|||||||
|
|
||||||
#include "unix_socket_common.h"
|
#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 ".client"
|
||||||
#define SUN_PATH_SUFFIX_LEN strlen(SUN_PATH_SUFFIX)
|
#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,
|
static int connection_based_messaging(int sock, struct sockaddr_un *peer_addr,
|
||||||
socklen_t peer_addr_len)
|
socklen_t peer_addr_len)
|
||||||
{
|
{
|
||||||
@@ -39,10 +41,12 @@ static int connection_based_messaging(int sock, struct sockaddr_un *peer_addr,
|
|||||||
if (rc)
|
if (rc)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
rc = connect(sock, (struct sockaddr *)peer_addr, peer_addr_len);
|
if (peer_addr) {
|
||||||
if (rc < 0) {
|
rc = connect(sock, (struct sockaddr *)peer_addr, peer_addr_len);
|
||||||
perror("FAIL CLIENT - connect");
|
if (rc < 0) {
|
||||||
exit(1);
|
perror("FAIL CLIENT - connect");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rc = read(sock, msg_buf, MSG_BUF_MAX);
|
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;
|
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,
|
static int connectionless_messaging(int sock, struct sockaddr_un *peer_addr,
|
||||||
socklen_t peer_addr_len)
|
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];
|
char msg_buf[MSG_BUF_MAX];
|
||||||
socklen_t len = peer_addr_len;
|
socklen_t len = peer_addr_len;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
if (path_len > sizeof(addr.sun_path)) {
|
if (peer_addr) {
|
||||||
fprintf(stderr, "FAIL CLIENT - path_len too big\n");
|
struct sockaddr_un addr;
|
||||||
return 1;
|
size_t peer_path_len = peer_addr_len - sizeof(addr.sun_family);
|
||||||
}
|
size_t path_len = peer_path_len + SUN_PATH_SUFFIX_LEN;
|
||||||
|
|
||||||
/**
|
if (path_len > sizeof(addr.sun_path)) {
|
||||||
* Subtract 1 to get rid of nul-terminator in pathname address types.
|
fprintf(stderr, "FAIL CLIENT - path_len too big\n");
|
||||||
* We're essentially moving the nul char so path_len stays the same.
|
return 1;
|
||||||
*/
|
}
|
||||||
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);
|
* Subtract 1 to get rid of nul-terminator in pathname address
|
||||||
strcpy(addr.sun_path + peer_path_len, SUN_PATH_SUFFIX);
|
* types. We're essentially moving the nul char so path_len
|
||||||
|
* stays the same.
|
||||||
|
*/
|
||||||
|
if (peer_addr->sun_path[0])
|
||||||
|
peer_path_len--;
|
||||||
|
|
||||||
rc = bind(sock, (struct sockaddr *)&addr,
|
addr.sun_family = AF_UNIX;
|
||||||
path_len + sizeof(addr.sun_family));
|
memcpy(addr.sun_path, peer_addr->sun_path, peer_path_len);
|
||||||
if (rc < 0) {
|
strcpy(addr.sun_path + peer_path_len, SUN_PATH_SUFFIX);
|
||||||
perror("FAIL CLIENT - bind");
|
|
||||||
return 1;
|
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);
|
rc = get_sock_io_timeo(sock);
|
||||||
@@ -134,18 +143,26 @@ static int test_getattr(int sock)
|
|||||||
return 0;
|
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[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
struct sockaddr_un peer_addr, *pa;
|
struct sockaddr_un peer_addr, *pa = NULL;
|
||||||
socklen_t pa_len;
|
socklen_t pa_len = 0;
|
||||||
const char *sun_path;
|
const char *sun_path;
|
||||||
size_t sun_path_len;
|
size_t sun_path_len;
|
||||||
int sock, type, rc;
|
int sock, type, rc;
|
||||||
|
int unnamed = 0;
|
||||||
|
const char *fd_number = NULL;
|
||||||
|
|
||||||
if (argc != 3) {
|
if (argc < 3 || argc > 4) {
|
||||||
fprintf(stderr, "Usage: %s <socket> <type>\n\n"
|
usage(argv[0]);
|
||||||
" type\t\tstream, dgram, or seqpacket\n",
|
|
||||||
argv[0]);
|
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,6 +178,13 @@ int main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
memcpy(peer_addr.sun_path, sun_path, sun_path_len);
|
memcpy(peer_addr.sun_path, sun_path, sun_path_len);
|
||||||
peer_addr.sun_path[0] = '\0';
|
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 {
|
} else {
|
||||||
/* include the nul terminator for pathname addr types */
|
/* include the nul terminator for pathname addr types */
|
||||||
sun_path_len++;
|
sun_path_len++;
|
||||||
@@ -182,10 +206,19 @@ int main(int argc, char *argv[])
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
sock = socket(AF_UNIX, type, 0);
|
if (unnamed) {
|
||||||
if (sock < 0) {
|
rc = sscanf(fd_number, "%d", &sock);
|
||||||
perror("FAIL CLIENT - socket");
|
if (rc != 1) {
|
||||||
exit(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);
|
rc = set_sock_io_timeo(sock);
|
||||||
@@ -196,8 +229,10 @@ int main(int argc, char *argv[])
|
|||||||
if (rc)
|
if (rc)
|
||||||
exit(1);
|
exit(1);
|
||||||
|
|
||||||
pa = &peer_addr;
|
if (!unnamed) {
|
||||||
pa_len = sun_path_len + sizeof(peer_addr.sun_family);
|
pa = &peer_addr;
|
||||||
|
pa_len = sun_path_len + sizeof(peer_addr.sun_family);
|
||||||
|
}
|
||||||
|
|
||||||
rc = (type == SOCK_STREAM || type == SOCK_SEQPACKET) ?
|
rc = (type == SOCK_STREAM || type == SOCK_SEQPACKET) ?
|
||||||
connection_based_messaging(sock, pa, pa_len) :
|
connection_based_messaging(sock, pa, pa_len) :
|
||||||
|
121
tests/regression/apparmor/unix_socket_unnamed.sh
Normal file
121
tests/regression/apparmor/unix_socket_unnamed.sh
Normal file
@@ -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"
|
Reference in New Issue
Block a user