[apparmor] [PATCH] tests: Verify mediation of path-based UNIX domain sockets

Tyler Hicks tyhicks at canonical.com
Sat Oct 26 03:53:23 UTC 2013


On 2013-10-08 14:08:16, Tyler Hicks wrote:
> The purpose is to provide test coverage for accessing UNIX domain socket
> files. AppArmor write permissions are needed to create the socket files
> and both read and write permissions are needed to connect to the socket.
> 
> This patch adds a test to the UNIX file descriptor passing tests and
> creates an entirely new set of tests for sending and receiving messages
> using path-based SOCK_STREAM, SOCK_DGRAM, and SOCK_SEQPACKET UNIX domain
> sockets.
> 
> Signed-off-by: Tyler Hicks <tyhicks at canonical.com>
> ---

I plan on merging these new tests on Monday unless I hear any
objections. Of course, I'll be happy to address any review comments
after it is merged, as well. :)

Tyler

>  tests/regression/apparmor/Makefile                 |   3 +
>  tests/regression/apparmor/unix_fd_server.sh        |   8 +
>  tests/regression/apparmor/unix_socket_file.c       | 177 +++++++++++++++++++++
>  tests/regression/apparmor/unix_socket_file.sh      | 105 ++++++++++++
>  .../regression/apparmor/unix_socket_file_client.c  | 126 +++++++++++++++
>  5 files changed, 419 insertions(+)
>  create mode 100644 tests/regression/apparmor/unix_socket_file.c
>  create mode 100755 tests/regression/apparmor/unix_socket_file.sh
>  create mode 100644 tests/regression/apparmor/unix_socket_file_client.c
> 
> diff --git a/tests/regression/apparmor/Makefile b/tests/regression/apparmor/Makefile
> index 370690f..0e49517 100644
> --- a/tests/regression/apparmor/Makefile
> +++ b/tests/regression/apparmor/Makefile
> @@ -71,6 +71,8 @@ SRC=access.c \
>      tcp.c \
>      unix_fd_client.c \
>      unix_fd_server.c \
> +    unix_socket_file.c \
> +    unix_socket_file_client.c \
>      unlink.c \
>      xattrs.c
>  
> @@ -158,6 +160,7 @@ TESTS=access \
>        syscall \
>        tcp \
>        unix_fd_server \
> +      unix_socket_file \
>        unlink\
>        xattrs\
>        longpath
> diff --git a/tests/regression/apparmor/unix_fd_server.sh b/tests/regression/apparmor/unix_fd_server.sh
> index 68fdcf2..4de3b26 100755
> --- a/tests/regression/apparmor/unix_fd_server.sh
> +++ b/tests/regression/apparmor/unix_fd_server.sh
> @@ -131,3 +131,11 @@ runchecktest "fd passing; confined -> confined (no perm)" fail $file $socket $fd
>  
>  sleep 1
>  rm -f ${socket}
> +
> +# FAIL - confined client, no access to the socket file
> +
> +genprofile $file:$okperm $socket:rw $fd_client:px -- image=$fd_client $file:$okperm
> +runchecktest "fd passing; confined client w/o socket access" fail $file $socket $fd_client
> +
> +sleep 1
> +rm -f ${socket}
> diff --git a/tests/regression/apparmor/unix_socket_file.c b/tests/regression/apparmor/unix_socket_file.c
> new file mode 100644
> index 0000000..a24e84e
> --- /dev/null
> +++ b/tests/regression/apparmor/unix_socket_file.c
> @@ -0,0 +1,177 @@
> +/*
> + * Copyright (C) 2013 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.
> + */
> +
> +#include <poll.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/socket.h>
> +#include <sys/types.h>
> +#include <sys/un.h>
> +#include <unistd.h>
> +
> +#define MSG_BUF_MAX 1024
> +
> +static int connection_based_messaging(int 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;
> +	}
> +
> +	rc = write(peer_sock, msg_buf, msg_buf_len);
> +	if (rc < 0) {
> +		perror("FAIL - write");
> +		return 1;
> +	}
> +
> +	rc = read(peer_sock, msg_buf, msg_buf_len);
> +	if (rc < 0) {
> +		perror("FAIL - read");
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int connectionless_messaging(int sock, char *msg_buf, size_t msg_buf_len)
> +{
> +	struct sockaddr_un peer_addr;
> +	socklen_t peer_addr_len = sizeof(peer_addr);
> +	int rc;
> +
> +	peer_addr.sun_family = AF_UNIX;
> +	rc = recvfrom(sock, NULL, 0, 0, (struct sockaddr *)&peer_addr,
> +		      &peer_addr_len);
> +	if (rc < 0) {
> +		perror("FAIL - recvfrom");
> +		return 1;
> +	}
> +
> +	rc = sendto(sock, msg_buf, msg_buf_len, 0,
> +		    (struct sockaddr *)&peer_addr, peer_addr_len);
> +	if (rc < 0) {
> +		perror("FAIL - sendto");
> +		return 1;
> +	}
> +
> +	rc = recv(sock, msg_buf, msg_buf_len, 0);
> +	if (rc < 0) {
> +		perror("FAIL - recv");
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +int main (int argc, char *argv[])
> +{
> +	struct sockaddr_un addr;
> +	struct pollfd pfd;
> +	char msg_buf[MSG_BUF_MAX];
> +	size_t msg_buf_len;
> +	pid_t pid;
> +	int sock, type, rc;
> +
> +	if (argc != 5) {
> +		fprintf(stderr,
> +			"Usage: %s <socket> <type> <message> <client>\n\n"
> +			"  type\t\tstream, dgram, or seqpacket\n",
> +			argv[0]);
> +		exit(1);
> +	}
> +
> +	if (!strcmp(argv[2], "stream")) {
> +		type = SOCK_STREAM;
> +	} else if (!strcmp(argv[2], "dgram")) {
> +		type = SOCK_DGRAM;
> +	} else if (!strcmp(argv[2], "seqpacket")) {
> +		type = SOCK_SEQPACKET;
> +	} else {
> +		fprintf(stderr, "FAIL - bad socket type: %s\n", argv[2]);
> +		exit(1);
> +	}
> +
> +	msg_buf_len = strlen(argv[3]) + 1;
> +	if (msg_buf_len > MSG_BUF_MAX) {
> +		fprintf(stderr, "FAIL - message too big\n");
> +		exit(1);
> +	}
> +	memcpy(msg_buf, argv[3], msg_buf_len);
> +
> +	sock = socket(AF_UNIX, type, 0);
> +	if (sock == -1) {
> +		perror("FAIL - socket");
> +		exit(1);
> +	}
> +
> +	addr.sun_family = AF_UNIX;
> +	strcpy(addr.sun_path, argv[1]);
> +	rc = bind(sock, (struct sockaddr *)&addr,
> +		  strlen(addr.sun_path) + sizeof(addr.sun_family));
> +	if (rc < 0) {
> +		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();
> +	if (pid < 0) {
> +		perror("FAIL - fork");
> +		exit(1);
> +	} else if (!pid) {
> +		execl(argv[4], argv[4], argv[1], argv[2], NULL);
> +		exit(0);
> +	}
> +
> +	pfd.fd = sock;
> +	pfd.events = POLLIN;
> +	rc = poll(&pfd, 1, 500);
> +	if (rc < 0) {
> +		perror("FAIL - poll");
> +		exit(1);
> +	} else if (!rc) {
> +		fprintf(stderr, "FAIL - poll timed out\n");
> +		exit(1);
> +	}
> +
> +	rc = (type == SOCK_STREAM || type == SOCK_SEQPACKET) ?
> +		connection_based_messaging(sock, msg_buf, msg_buf_len) :
> +		connectionless_messaging(sock, msg_buf, msg_buf_len);
> +	if (rc)
> +		exit(1);
> +
> +	if (memcmp(argv[3], msg_buf, msg_buf_len)) {
> +		msg_buf[msg_buf_len] = '\0';
> +		fprintf(stderr, "FAIL - buffer comparison. Got \"%s\", expected \"%s\"\n",
> +			msg_buf, argv[3]);
> +		exit(1);
> +	}
> +
> +	printf("PASS\n");
> +	exit(0);
> +}
> diff --git a/tests/regression/apparmor/unix_socket_file.sh b/tests/regression/apparmor/unix_socket_file.sh
> new file mode 100755
> index 0000000..6f38acb
> --- /dev/null
> +++ b/tests/regression/apparmor/unix_socket_file.sh
> @@ -0,0 +1,105 @@
> +#! /bin/bash
> +#
> +# Copyright (C) 2013 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_file
> +#=DESCRIPTION
> +# This tests file access to path-based unix domain sockets. The server
> +# opens a socket, forks a client with it's own profile, sends a message
> +# to the client over the socket, and sees what happens.
> +#=END
> +
> +pwd=`dirname $0`
> +pwd=`cd $pwd ; /bin/pwd`
> +
> +bin=$pwd
> +
> +. $bin/prologue.inc
> +
> +client=$bin/unix_socket_file_client
> +socket=${tmpdir}/unix_socket_file.sock
> +message=4a0c83d87aaa7afa2baab5df3ee4df630f0046d5bfb7a3080c550b721f401b3b\
> +8a738e1435a3b77aa6482a70fb51c44f20007221b85541b0184de66344d46a4c
> +okserver=w
> +badserver=r
> +
> +okclient=rw
> +badclient1=r
> +badclient2=w
> +
> +removesocket()
> +{
> +	rm -f ${socket}
> +}
> +
> +testsocktype()
> +{
> +	local socktype=$1 # socket type - stream, dgram, or seqpacket
> +	local args="$socket $socktype $message $client"
> +
> +	# PASS - unconfined
> +
> +	runchecktest "socket file ($socktype); unconfined" pass $args
> +	removesocket
> +
> +	# PASS - server w/ access to the file
> +
> +	genprofile $socket:$okserver $client:Ux
> +	runchecktest "socket file ($socktype); confined server w/ access ($okserver)" pass $args
> +	removesocket
> +
> +	# FAIL - server w/o access to the file
> +
> +	genprofile $client:Ux
> +	runchecktest "socket file ($socktype); confined server w/o access" fail $args
> +	removesocket
> +
> +	# FAIL - server w/ bad access to the file
> +
> +	genprofile $socket:$badserver $client:Ux
> +	runchecktest "socket file ($socktype); confined server w/ bad access ($badserver)" fail $args
> +	removesocket
> +
> +	# PASS - client w/ access to the file
> +
> +	genprofile $socket:$okserver $client:px -- image=$client $socket:$okclient
> +	runchecktest "socket file ($socktype); confined client w/ access ($okclient)" pass $args
> +	removesocket
> +
> +	# FAIL - client w/o access to the file
> +
> +	genprofile $socket:$okserver $client:px -- image=$client
> +	runchecktest "socket file ($socktype); confined client w/o access" fail $args
> +	removesocket
> +
> +	# FAIL - client w/ bad access to the file
> +
> +	genprofile $socket:$okserver $client:px -- image=$client $socket:$badclient1
> +	runchecktest "socket file ($socktype); confined client w/ bad access ($badclient1)" fail $args
> +	removesocket
> +
> +	# FAIL - client w/ bad access to the file
> +
> +	genprofile $socket:$okserver $client:px -- image=$client $socket:$badclient2
> +	runchecktest "socket file ($socktype); confined client w/ bad access ($badclient2)" fail $args
> +	removesocket
> +
> +	removeprofile
> +}
> +
> +removesocket
> +testsocktype stream
> +testsocktype dgram
> +testsocktype seqpacket
> diff --git a/tests/regression/apparmor/unix_socket_file_client.c b/tests/regression/apparmor/unix_socket_file_client.c
> new file mode 100644
> index 0000000..73aa8ba
> --- /dev/null
> +++ b/tests/regression/apparmor/unix_socket_file_client.c
> @@ -0,0 +1,126 @@
> +/*
> + * Copyright (C) 2013 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.
> + */
> +
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <sys/socket.h>
> +#include <sys/types.h>
> +#include <sys/un.h>
> +#include <unistd.h>
> +
> +#define MSG_BUF_MAX	1024
> +
> +static int connection_based_messaging(int sock)
> +{
> +	char msg_buf[MSG_BUF_MAX];
> +	int rc;
> +
> +	rc = read(sock, msg_buf, MSG_BUF_MAX);
> +	if (rc < 0) {
> +		perror("FAIL CLIENT - read");
> +		return 1;
> +	}
> +
> +	rc = write(sock, msg_buf, rc);
> +	if (rc < 0) {
> +		perror("FAIL CLIENT - write");
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +static int connectionless_messaging(int sock)
> +{
> +	struct sockaddr_un addr;
> +	char msg_buf[MSG_BUF_MAX];
> +	int rc;
> +
> +	addr.sun_family = AF_UNIX;
> +	rc = bind(sock, (struct sockaddr *)&addr, sizeof(sa_family_t));
> +	if (rc < 0) {
> +		perror("FAIL CLIENT - bind");
> +		return 1;
> +	}
> +
> +	rc = write(sock, NULL, 0);
> +	if (rc < 0) {
> +		perror("FAIL CLIENT - write");
> +		return 1;
> +	}
> +
> +	rc = read(sock, msg_buf, MSG_BUF_MAX);
> +	if (rc < 0) {
> +		perror("FAIL CLIENT - read");
> +		return 1;
> +	}
> +
> +	rc = write(sock, msg_buf, rc);
> +	if (rc < 0) {
> +		perror("FAIL CLIENT - write");
> +		return 1;
> +	}
> +
> +	return 0;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	struct sockaddr_un peer_addr;
> +	int sock, type, rc;
> +
> +	if (argc != 3) {
> +		fprintf(stderr, "Usage: %s <socket> <type>\n\n"
> +			"  type\t\tstream, dgram, or seqpacket\n",
> +			argv[0]);
> +		exit(1);
> +	}
> +
> +	if (!strcmp(argv[2], "stream")) {
> +		type = SOCK_STREAM;
> +	} else if (!strcmp(argv[2], "dgram")) {
> +		type = SOCK_DGRAM;
> +	} else if (!strcmp(argv[2], "seqpacket")) {
> +		type = SOCK_SEQPACKET;
> +	} else {
> +		fprintf(stderr, "FAIL CLIENT - bad socket type: %s\n", argv[2]);
> +		exit(1);
> +	}
> +
> +	sock = socket(AF_UNIX, type, 0);
> +	if (sock < 0) {
> +		perror("FAIL CLIENT - socket");
> +		exit(1);
> +	}
> +
> +	peer_addr.sun_family = AF_UNIX;
> +	strcpy(peer_addr.sun_path, argv[1]);
> +	rc = connect(sock, (struct sockaddr *)&peer_addr,
> +		     strlen(peer_addr.sun_path) + sizeof(peer_addr.sun_family));
> +	if (rc < 0) {
> +		perror("FAIL CLIENT - connect");
> +		exit(1);
> +	}
> +
> +	rc = (type == SOCK_STREAM || type == SOCK_SEQPACKET) ?
> +		connection_based_messaging(sock) :
> +		connectionless_messaging(sock);
> +	if (rc)
> +		exit(1);
> +
> +	exit(0);
> +}
> -- 
> 1.8.3.2
> 
> 
> -- 
> AppArmor mailing list
> AppArmor at lists.ubuntu.com
> Modify settings or unsubscribe at: https://lists.ubuntu.com/mailman/listinfo/apparmor
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 836 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20131025/92adf86a/attachment-0001.pgp>


More information about the AppArmor mailing list