[apparmor] [PATCH] tests: Add dbus tests for unrequested reply messages

Seth Arnold seth.arnold at canonical.com
Thu Aug 28 21:07:48 UTC 2014


On Thu, Aug 28, 2014 at 02:41:21AM -0500, Tyler Hicks wrote:
> Unrequested replies are message types that are typically replies, such
> as error and method_return message types, but have not been requested by
> the recipient.
> 
> The AppArmor mediation code in dbus-daemon allows requested reply
> messages through if the original message was allowed. However,
> unrequested reply messages should be checked against the system policy
> to make certain that they should be allowed.
> 
> This test verifies that the dbus-daemon is properly querying system
> policy when it detects that a message is an unrequested reply.
> 
> Signed-off-by: Tyler Hicks <tyhicks at canonical.com>

Acked-by: Seth Arnold <seth.arnold at canonical.com>

There's some small suggestions for usability improvements inline:

Thanks

> ---
>  tests/regression/apparmor/Makefile                 |   7 +-
>  tests/regression/apparmor/dbus.inc                 |  22 ++
>  tests/regression/apparmor/dbus_unrequested_reply.c | 221 +++++++++++++++++++++
>  .../regression/apparmor/dbus_unrequested_reply.sh  | 126 ++++++++++++
>  4 files changed, 374 insertions(+), 2 deletions(-)
>  create mode 100644 tests/regression/apparmor/dbus_unrequested_reply.c
>  create mode 100644 tests/regression/apparmor/dbus_unrequested_reply.sh
> 
> diff --git a/tests/regression/apparmor/Makefile b/tests/regression/apparmor/Makefile
> index 13bc5d3..c9374f5 100644
> --- a/tests/regression/apparmor/Makefile
> +++ b/tests/regression/apparmor/Makefile
> @@ -126,7 +126,7 @@ endif
>  
>  #only do dbus if proper libs are installl
>  ifneq (,$(shell pkg-config --exists dbus-1 && echo TRUE))
> -SRC+=dbus_eavesdrop.c dbus_message.c dbus_service.c
> +SRC+=dbus_eavesdrop.c dbus_message.c dbus_service.c dbus_unrequested_reply.c
>  else
>  $(warning ${nl}\
>  ************************************************************************${nl}\
> @@ -190,7 +190,7 @@ TESTS=access \
>  
>  #only do dbus if proper libs are installl
>  ifneq (,$(shell pkg-config --exists dbus-1 && echo TRUE))
> -TESTS+=dbus_eavesdrop dbus_message dbus_service
> +TESTS+=dbus_eavesdrop dbus_message dbus_service dbus_unrequested_reply
>  endif
>  
>  # Tests that can crash the kernel should be placed here
> @@ -224,6 +224,9 @@ dbus_message: dbus_message.c dbus_common.o
>  dbus_service: dbus_message dbus_service.c dbus_common.o
>  	${CC} ${CFLAGS} ${LDFLAGS} $(filter-out dbus_message, $^) -o $@ ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
>  
> +dbus_unrequested_reply: dbus_service dbus_unrequested_reply.c dbus_common.o
> +	${CC} ${CFLAGS} ${LDFLAGS} $(filter-out dbus_service, $^) -o $@ ${LDLIBS} $(shell pkg-config --cflags --libs dbus-1)
> +
>  tests: all
>  	@if [ `whoami` = "root" ] ;\
>  	then \
> diff --git a/tests/regression/apparmor/dbus.inc b/tests/regression/apparmor/dbus.inc
> index 539d128..57cb849 100755
> --- a/tests/regression/apparmor/dbus.inc
> +++ b/tests/regression/apparmor/dbus.inc
> @@ -98,6 +98,28 @@ sendmethod()
>    send "$bus" "method_call" "$dest" "$path" "${iface}.Method"
>  }
>  
> +# parameters: bus message_type destination
> +#
> +# destination must be a connection name
> +sendunrequestedreply()
> +{
> +  out=$(./dbus_unrequested_reply --$1 --type=$2 --name=$3 2>&1)
> +  if [ $? -ne 0 ]
> +  then
> +    fatalerror "$out"
> +  fi
> +}
> +
> +sendmethodreturn()
> +{
> +  sendunrequestedreply "$bus" "method_return" "$dest"
> +}
> +
> +senderror()
> +{
> +  sendunrequestedreply "$bus" "error" "$dest"
> +}
> +
>  compare_logs()
>  {
>  	local msg
> diff --git a/tests/regression/apparmor/dbus_unrequested_reply.c b/tests/regression/apparmor/dbus_unrequested_reply.c
> new file mode 100644
> index 0000000..143f292
> --- /dev/null
> +++ b/tests/regression/apparmor/dbus_unrequested_reply.c
> @@ -0,0 +1,221 @@
> +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
> +/* dbus_message.c  Utility program to send messages from the command line
> + *
> + * Copyright (C) 2003 Philip Blundell <philb at gnu.org>
> + * Copyright (C) 2014 Canonical, Ltd.
> + *
> + * Originally dbus-send.c from the dbus package. It has been heavily modified
> + * to work within the regression test framework.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * 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, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
> + *
> + */
> +
> +#define _GNU_SOURCE
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <sys/types.h>
> +#include <sys/stat.h>
> +#include <fcntl.h>
> +
> +#include "dbus_common.h"
> +
> +DBusConnection *connection;
> +DBusError error;
> +DBusBusType type = DBUS_BUS_SESSION;
> +const char *type_str = NULL;
> +const char *name = NULL;
> +int message_type = DBUS_MESSAGE_TYPE_INVALID;
> +const char *address = NULL;
> +int session_or_system = FALSE;
> +int log_fd = -1;
> +
> +static void usage(int ecode)
> +{
> +	char *prefix = ecode ? "FAIL: " : "";
> +
> +	fprintf(stderr,
> +		"%6sUsage: dbus_unrequested_reply [ADDRESS] --name=NAME --type=TYPE\n"
> +		"    ADDRESS\t\t--system, --session (default), or --address=ADDR\n"
> +		"    NAME\t\tthe message destination\n"
> +		"    TYPE\t\tmethod_return or error\n",
> +		prefix);
> +	exit(ecode);
> +}
> +
> +static int do_unrequested_reply(void)
> +{
> +	DBusMessage *message;
> +
> +	if (message_type == DBUS_MESSAGE_TYPE_METHOD_RETURN) {
> +		message = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
> +
> +		if (message) {
> +			dbus_message_set_no_reply(message, TRUE);
> +
> +			/* Make up an invalid reply_serial */
> +			if (!dbus_message_set_reply_serial(message,
> +							   123456789)) {
> +				fprintf(stderr,
> +					"FAIL: Couldn't set reply_serial\n");
> +				return 1;
> +			}
> +		}
> +	} else if (message_type == DBUS_MESSAGE_TYPE_ERROR) {
> +		message = dbus_message_new(DBUS_MESSAGE_TYPE_ERROR);
> +
> +		if (message) {
> +			dbus_message_set_no_reply(message, TRUE);
> +
> +			/* Make up an invalid reply_serial */
> +			if (!dbus_message_set_reply_serial(message,
> +							   123456789)) {
> +				fprintf(stderr,
> +					"FAIL: Couldn't set reply_serial\n");
> +				return 1;
> +			}
> +
> +			/* Make up an error */
> +			if (!dbus_message_set_error_name(message,
> +					DBUS_ERROR_PROPERTY_READ_ONLY)) {
> +				fprintf(stderr,
> +					"FAIL: Couldn't set error name\n");
> +				return 1;
> +			}
> +		}
> +	} else {
> +		fprintf(stderr, "FAIL: Internal error, unknown message type\n");
> +		return 1;
> +	}
> +
> +	if (message == NULL) {
> +		fprintf(stderr, "FAIL: Couldn't allocate D-Bus message\n");
> +		return 1;
> +	}
> +
> +	if (!dbus_message_set_destination(message, name)) {
> +		fprintf(stderr, "FAIL: Not enough memory\n");
> +		return 1;
> +	}
> +
> +	log_message(log_fd, "sent ", message);
> +	dbus_connection_send(connection, message, NULL);
> +	dbus_connection_flush(connection);
> +
> +	dbus_message_unref(message);
> +
> +	return 0;
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +	int i, rc;
> +
> +	if (argc < 3)
> +		usage(1);
> +
> +	for (i = 1; i < argc; i++) {
> +		char *arg = argv[i];
> +
> +		if (strcmp(arg, "--system") == 0) {
> +			type = DBUS_BUS_SYSTEM;
> +			session_or_system = TRUE;
> +		} else if (strcmp(arg, "--session") == 0) {
> +			type = DBUS_BUS_SESSION;
> +			session_or_system = TRUE;
> +		} else if (strstr(arg, "--address") == arg) {
> +			address = strchr(arg, '=');
> +
> +			if (address == NULL) {
> +				fprintf(stderr,
> +					"FAIL: \"--address=\" requires an ADDRESS\n");
> +				usage(1);
> +			} else {
> +				address = address + 1;
> +			}
> +		} else if (strstr(arg, "--name=") == arg)
> +			name = strchr(arg, '=') + 1;

No NULL check here..

> +		else if (strstr(arg, "--type=") == arg)
> +			type_str = strchr(arg, '=') + 1;

No NULL check here..

> +		else if (strstr(arg, "--log=") == arg) {
> +			char *path = strchr(arg, '=') + 1;

No NULL check here..

> +
> +			log_fd = open(path, O_CREAT | O_TRUNC | O_WRONLY,
> +				      S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP |
> +				      S_IROTH | S_IWOTH);
> +			if (log_fd < 0) {
> +				fprintf(stderr,
> +					"FAIL: Couldn't open log file \"%s\": %m\n",
> +					path);
> +				exit(1);
> +			}
> +		} else if (!strcmp(arg, "--help"))
> +			usage(0);
> +		else if (arg[0] == '-')
> +			usage(1);
> +		else
> +			usage(1);
> +	}
> +
> +	if (!name)
> +		usage(1);
> +
> +	if (!type_str) {
> +		usage(1);
> +	} else {
> +		message_type = dbus_message_type_from_string(type_str);
> +		if (message_type != DBUS_MESSAGE_TYPE_METHOD_RETURN &&
> +		    message_type != DBUS_MESSAGE_TYPE_ERROR) {
> +			fprintf(stderr,
> +				"FAIL: Message type \"%s\" is not supported\n",
> +				type_str);
> +			exit(1);
> +		}
> +	}
> +
> +	if (session_or_system && address != NULL) {
> +		fprintf(stderr,
> +			"FAIL: \"--address\" may not be used with \"--system\" or \"--session\"\n");
> +		usage(1);
> +	}
> +
> +	dbus_error_init(&error);
> +
> +	if (address != NULL)
> +		connection = dbus_connection_open(address, &error);
> +	else
> +		connection = dbus_bus_get(type, &error);
> +
> +	if (connection == NULL) {
> +		fprintf(stderr,
> +			"FAIL: Failed to open connection to \"%s\" message bus: %s\n",
> +			(address !=
> +			 NULL) ? address : ((type ==
> +					     DBUS_BUS_SYSTEM) ? "system" :
> +					    "session"), error.message);
> +		dbus_error_free(&error);
> +		exit(1);
> +	} else if (address != NULL)
> +		dbus_bus_register(connection, &error);
> +
> +	rc = do_unrequested_reply();
> +	dbus_connection_unref(connection);
> +	if (rc == 0)
> +		printf("PASS\n");
> +
> +	exit(rc);
> +}
> diff --git a/tests/regression/apparmor/dbus_unrequested_reply.sh b/tests/regression/apparmor/dbus_unrequested_reply.sh
> new file mode 100644
> index 0000000..1cfd8d4
> --- /dev/null
> +++ b/tests/regression/apparmor/dbus_unrequested_reply.sh
> @@ -0,0 +1,126 @@
> +#! /bin/bash
> +#	Copyright (C) 2013 Canonical, Ltd.
> +#
> +#	This program is free software; you can redistribute it and/or
> +#	modify it under the terms of the GNU General Public License as
> +#	published by the Free Software Foundation, version 2 of the
> +#	License.
> +
> +#=NAME dbus_unrequested_reply
> +#=DESCRIPTION
> +# This test verifies that unrequested reply messages are not allowed through.
> +#=END
> +
> +pwd=`dirname $0`
> +pwd=`cd $pwd ; /bin/pwd`
> +
> +bin=$pwd
> +
> +. $bin/prologue.inc
> +requires_features dbus
> +. $bin/dbus.inc
> +
> +service="--$bus --name=$dest $path $iface"
> +unconfined_log="${tmpdir}/unconfined.log"
> +confined_log="${tmpdir}/confined.log"
> +
> +ur_runtestbg()
> +{
> +	local lock=${tmpdir}/lock
> +	local lockfd=-1
> +	local args=$service
> +
> +	if [ $# -gt 2 ]
> +	then
> +		args="--log=$3 $args"
> +	fi
> +
> +	exec {lockfd}>$lock
> +	flock -n $lockfd
> +	args="--lock-fd=$lockfd $args"
> +
> +	runtestbg "$1" "$2" $args
> +
> +	exec {lockfd}>&-
> +	flock -w 30 $lock true
> +	rm $lock
> +}
> +
> +ur_checktestbg()
> +{
> +	kill -SIGTERM $_pid 2>/dev/null
> +	checktestbg "$@"
> +}
> +
> +ur_runchecktest()
> +{
> +	ur_runtestbg "$@"
> +	ur_checktestbg
> +}
> +
> +ur_gendbusprofile()
> +{
> +	gendbusprofile "$confined_log w,
> +  dbus bind bus=$bus name=$dest,
> +  $@"
> +}
> +
> +start_bus
> +
> +settest dbus_service
> +
> +# Start a dbus service and send unrequested method_return and error messages to
> +# the service. The service should always start and stop just fine. The test
> +# results hinge on comparing the message log from confined services to the
> +# message log from the initial unconfined run.
> +
> +# Do an unconfined run to get an "expected" log for comparisons
> +ur_runtestbg "unrequested_reply (method_return, unconfined)" pass $unconfined_log
> +sendmethodreturn
> +ur_checktestbg
> +
> +# All dbus perms are granted so the logs should be equal
> +ur_gendbusprofile "dbus,"
> +ur_runtestbg "unrequested_reply (method_return, dbus allowed)" pass $confined_log
> +sendmethodreturn
> +ur_checktestbg "compare_logs $unconfined_log eq $confined_log"
> +
> +# Only send perm is granted so the confined service should not be able to
> +# receive unrequested replies from the client
> +ur_gendbusprofile "dbus send,"
> +ur_runtestbg "unrequested_reply (method_return, send allowed)" pass $confined_log
> +sendmethodreturn
> +ur_checktestbg "compare_logs $unconfined_log ne $confined_log"
> +
> +# Send and receive perms are granted so the logs should be equal
> +ur_gendbusprofile "dbus (send receive),"
> +ur_runtestbg "unrequested_reply (method_return, send receive allowed)" pass $confined_log
> +sendmethodreturn
> +ur_checktestbg "compare_logs $unconfined_log eq $confined_log"
> +
> +# Now test unrequested error replies
> +
> +# Do an unconfined run to get an "expected" log for comparisons
> +removeprofile
> +ur_runtestbg "unrequested_reply (error, unconfined)" pass $unconfined_log
> +senderror
> +ur_checktestbg
> +
> +# All dbus perms are granted so the logs should be equal
> +ur_gendbusprofile "dbus,"
> +ur_runtestbg "unrequested_reply (error, dbus allowed)" pass $confined_log
> +senderror
> +ur_checktestbg "compare_logs $unconfined_log eq $confined_log"
> +
> +# Only send perm is granted so the confined service should not be able to
> +# receive unrequested replies from the client
> +ur_gendbusprofile "dbus send,"
> +ur_runtestbg "unrequested_reply (error, send allowed)" pass $confined_log
> +senderror
> +ur_checktestbg "compare_logs $unconfined_log ne $confined_log"
> +
> +# Send and receive perms are granted so the logs should be equal
> +ur_gendbusprofile "dbus (send receive),"
> +ur_runtestbg "unrequested_reply (error, send receive allowed)" pass $confined_log
> +senderror
> +ur_checktestbg "compare_logs $unconfined_log eq $confined_log"
> -- 
> 2.1.0
> 
> 
> -- 
> 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: 473 bytes
Desc: Digital signature
URL: <https://lists.ubuntu.com/archives/apparmor/attachments/20140828/6d8762f1/attachment.pgp>


More information about the AppArmor mailing list