AS_IF([test x$enable_apparmor = xno],
[have_apparmor=no],
[
- PKG_CHECK_MODULES([APPARMOR], [libapparmor >= 2.8.95],
+ PKG_CHECK_MODULES([APPARMOR], [libapparmor >= 2.10],
[have_apparmor=yes], [have_apparmor=no])
AS_IF([test x$enable_apparmor = xauto && test x$have_apparmor = xno],
-I$(top_srcdir) \
$(DBUS_STATIC_BUILD_CPPFLAGS) \
-DDBUS_COMPILATION \
+ $(APPARMOR_CFLAGS) \
$(GLIB_CFLAGS) \
$(GIO_UNIX_CFLAGS) \
$(NULL)
testexec_PROGRAMS =
testmeta_DATA =
+installable_helpers = \
+ $(NULL)
installable_tests = \
test-shell \
test-printf \
$(NULL)
dist_installable_test_scripts = \
$(NULL)
+dist_installed_test_scripts = \
+ $(NULL)
if DBUS_WIN
installable_manual_tests += manual-paths
$(NULL)
if DBUS_UNIX
+# These binaries are used in tests but are not themselves tests
+installable_helpers += \
+ test-apparmor-activation \
+ $(NULL)
+
installable_tests += \
test-sd-activation \
$(NULL)
test-dbus-daemon-fork.sh \
$(NULL)
+# Only runnable when installed, not from the source tree
+dist_installed_test_scripts += \
+ test-apparmor-activation.sh \
+ $(NULL)
+
# Testing dbus-launch relies on special code in that binary.
if DBUS_ENABLE_EMBEDDED_TESTS
dist_installable_test_scripts += \
installable_test_meta = \
$(dist_installable_test_scripts:=.test) \
+ $(dist_installed_test_scripts:=.test) \
$(installable_tests:=.test) \
$(NULL)
installable_test_meta_with_config = \
$(dist_installable_test_scripts:=_with_config.test) \
+ $(dist_installed_test_scripts:=_with_config.test) \
$(installable_tests:=_with_config.test) \
$(NULL)
$(GLIB_LIBS) \
$(NULL)
+if DBUS_UNIX
+test_apparmor_activation_CPPFLAGS = \
+ $(AM_CPPFLAGS) \
+ -DDBUS_TEST_APPARMOR_ACTIVATION \
+ $(NULL)
+test_apparmor_activation_SOURCES = \
+ sd-activation.c \
+ $(NULL)
+test_apparmor_activation_LDADD = \
+ libdbus-testutils.la \
+ $(APPARMOR_LIBS) \
+ $(GLIB_LIBS) \
+ $(NULL)
+endif
+
test_corrupt_SOURCES = corrupt.c
test_corrupt_LDADD = \
libdbus-testutils.la \
installcheck_tests += $(installable_tests)
if DBUS_ENABLE_INSTALLED_TESTS
- testexec_PROGRAMS += $(installable_tests) $(installable_manual_tests)
+ testexec_PROGRAMS += $(installable_helpers)
+ testexec_PROGRAMS += $(installable_manual_tests)
+ testexec_PROGRAMS += $(installable_tests)
+ dist_testexec_SCRIPTS += $(dist_installed_test_scripts)
dist_testexec_SCRIPTS += $(dist_installable_test_scripts)
testmeta_DATA += $(installable_test_meta)
endif DBUS_ENABLE_INSTALLED_TESTS
in_data = \
+ data/dbus-installed-tests.aaprofile.in \
+ data/systemd-activation/com.example.ReceiveDeniedByAppArmorLabel.service.in \
+ data/systemd-activation/com.example.SendDeniedByAppArmorLabel.service.in \
data/valid-config-files-system/debug-allow-all-fail.conf.in \
data/valid-config-files-system/debug-allow-all-pass.conf.in \
data/valid-config-files/debug-allow-all-sha1.conf.in \
data/sha-1/byte-messages.sha1 \
data/systemd-activation/com.example.ReceiveDenied.service \
data/systemd-activation/com.example.SendDenied.service \
+ data/systemd-activation/com.example.SendDeniedByAppArmorName.service \
data/systemd-activation/com.example.SystemdActivatable1.service \
data/systemd-activation/com.example.SystemdActivatable2.service \
data/systemd-activation/com.example.SystemdActivatable3.service \
echo '[Test]'; \
echo 'Type=session'; \
echo 'Output=TAP'; \
- echo 'Exec=env DBUS_TEST_DATA=$(testexecdir)/data $(testexecdir)/$* --tap'; \
+ echo 'Exec=env DBUS_TEST_EXEC=$(testexecdir) DBUS_TEST_DATA=$(testexecdir)/data $(testexecdir)/$* --tap'; \
) > $@.tmp && mv $@.tmp $@
# Add rules for code-coverage testing, as defined by AX_CODE_COVERAGE
--- /dev/null
+# Copyright © 2016 Collabora Ltd.
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+#include <tunables/global>
+#include <tunables/sys>
+
+@DBUS_TEST_EXEC@/test-apparmor-activation {
+ #include <abstractions/apparmor_api/change_profile>
+ #include <abstractions/apparmor_api/find_mountpoint>
+ #include <abstractions/apparmor_api/is_enabled>
+ #include <abstractions/base>
+
+ # We aren't really confining this process seriously; allow most things.
+ /** mrix,
+ @{sys}/kernel/security/apparmor/** w,
+ dbus (send, receive, bind),
+ network,
+ signal,
+
+ # "Hat" subprofile used for the part of the process that imitates a client
+ # trying to cause service activation via auto-starting.
+ ^caller {
+ #include <abstractions/apparmor_api/change_profile>
+ #include <abstractions/base>
+
+ /** mrix,
+ @{sys}/kernel/security/apparmor/** w,
+ dbus (send, receive, bind),
+ network,
+ signal,
+
+ deny dbus send peer=(label=@DBUS_TEST_EXEC@/test-apparmor-activation//com.example.SendDeniedByAppArmorLabel),
+ deny dbus send peer=(name=com.example.SendDeniedByAppArmorName),
+ }
+
+ # Used when we check that XML-based policy still works.
+ ^com.example.ReceiveDenied {
+ #include <abstractions/apparmor_api/change_profile>
+ #include <abstractions/base>
+
+ /** mrix,
+ @{sys}/kernel/security/apparmor/** w,
+ dbus,
+ network,
+ signal,
+ }
+
+ # This one is never actually used, but needs to exist so ^caller can
+ # refer to it
+ ^com.example.SendDeniedByAppArmorLabel {
+ #include <abstractions/apparmor_api/change_profile>
+ #include <abstractions/base>
+
+ /** mrix,
+ @{sys}/kernel/security/apparmor/** w,
+ dbus (send, receive, bind),
+ network,
+ signal,
+ }
+
+ # "Hat" subprofile used for the part of the process that imitates a service
+ # that is not allowed to receive from the caller.
+ ^com.example.ReceiveDeniedByAppArmorLabel {
+ #include <abstractions/apparmor_api/change_profile>
+ #include <abstractions/base>
+
+ /** mrix,
+ @{sys}/kernel/security/apparmor/** w,
+ dbus (send, receive, bind),
+ network,
+ signal,
+
+ deny dbus receive peer=(label=@DBUS_TEST_EXEC@/test-apparmor-activation//caller),
+ }
+}
--- /dev/null
+[D-BUS Service]
+Name=com.example.ReceiveDeniedByAppArmorLabel
+Exec=/bin/false ReceiveDeniedByAppArmorLabel
+SystemdService=dbus-com.example.ReceiveDeniedByAppArmorLabel.service
+AssumedAppArmorLabel=@DBUS_TEST_EXEC@/test-apparmor-activation//com.example.ReceiveDeniedByAppArmorLabel
--- /dev/null
+[D-BUS Service]
+Name=com.example.SendDeniedByAppArmorLabel
+Exec=/bin/false SendDeniedByAppArmorLabel
+SystemdService=dbus-com.example.SendDeniedByAppArmorLabel.service
+AssumedAppArmorLabel=@DBUS_TEST_EXEC@/test-apparmor-activation//com.example.SendDeniedByAppArmorLabel
--- /dev/null
+[D-BUS Service]
+Name=com.example.SendDeniedByAppArmorName
+Exec=/bin/false SendDeniedByAppArmorName
+SystemdService=dbus-com.example.SendDeniedByAppArmorName.service
-/* Unit tests for systemd activation.
+/* Unit tests for systemd activation, with or without AppArmor.
+ *
+ * We compile this source file twice: once with AppArmor support (if available)
+ * and once without.
*
* Copyright © 2010-2011 Nokia Corporation
* Copyright © 2015 Collabora Ltd.
#include <config.h>
+#include <errno.h>
+#include <unistd.h>
#include <string.h>
+#include <sys/types.h>
+
+#if defined(HAVE_APPARMOR) && defined(DBUS_TEST_APPARMOR_ACTIVATION)
+#include <sys/apparmor.h>
+#endif
#include "test-utils-glib.h"
setup (Fixture *f,
gconstpointer context G_GNUC_UNUSED)
{
+#if defined(DBUS_TEST_APPARMOR_ACTIVATION) && !defined(HAVE_APPARMOR)
+
+ g_test_skip ("AppArmor support not compiled");
+ return;
+
+#else
+
+#if defined(DBUS_TEST_APPARMOR_ACTIVATION)
+ aa_features *features;
+
+ if (!aa_is_enabled ())
+ {
+ g_test_message ("aa_is_enabled() -> %s", g_strerror (errno));
+ g_test_skip ("AppArmor not enabled");
+ return;
+ }
+
+ if (aa_features_new_from_kernel (&features) != 0)
+ {
+ g_test_skip ("Unable to check AppArmor features");
+ return;
+ }
+
+ if (!aa_features_supports (features, "dbus/mask/send") ||
+ !aa_features_supports (features, "dbus/mask/receive"))
+ {
+ g_test_skip ("D-Bus send/receive mediation unavailable");
+ aa_features_unref (features);
+ return;
+ }
+
+ aa_features_unref (features);
+#endif
+
f->ctx = test_main_context_get ();
f->ge = NULL;
if (f->address == NULL)
return;
+#if defined(DBUS_TEST_APPARMOR_ACTIVATION)
+ /*
+ * Make use of the fact that the LSM security label (and other process
+ * properties) that are used for access-control are whatever was current
+ * at the time the connection was opened.
+ *
+ * 42 is arbitrary. In a real use of AppArmor it would be a securely-random
+ * value, to prevent less-privileged code (that does not know the magic
+ * value) from changing back.
+ */
+ if (aa_change_hat ("caller", 42) != 0)
+ g_error ("Unable to change profile to ...//^caller: %s",
+ g_strerror (errno));
+#endif
+
f->caller = test_connect_to_bus (f->ctx, f->address);
f->caller_name = dbus_bus_get_unique_name (f->caller);
+
+#if defined(DBUS_TEST_APPARMOR_ACTIVATION)
+ if (aa_change_hat (NULL, 42) != 0)
+ g_error ("Unable to change back to initial profile: %s",
+ g_strerror (errno));
+#endif
+
+#endif
}
static void
gconstpointer context)
{
DBusMessage *m;
+ const char *bus_name = context;
if (f->address == NULL)
return;
f->caller_filter_added = TRUE;
/* The sender sends a message to an activatable service. */
- m = dbus_message_new_method_call ("com.example.SendDenied", "/foo",
+ m = dbus_message_new_method_call (bus_name, "/foo",
"com.example.bar", "Call");
if (m == NULL)
g_error ("OOM");
dbus_connection_send (f->caller, m, NULL);
dbus_message_unref (m);
- /* Even before the fake systemd connects to the bus, we get an error
- * back: activation is not allowed. */
+ /*
+ * Even before the fake systemd connects to the bus, we get an error
+ * back: activation is not allowed.
+ *
+ * In the normal case, this is because the XML policy does not allow
+ * anyone to send messages to the bus name com.example.SendDenied.
+ *
+ * In the AppArmor case, this is because the AppArmor policy does not allow
+ * this process to send messages to the bus name
+ * com.example.SendDeniedByAppArmorName, or to the label
+ * @DBUS_TEST_EXEC@/com.example.SendDeniedByAppArmorLabel that we assume the
+ * service com.example.SendDeniedByAppArmorLabel will receive after systemd
+ * runs it.
+ */
while (f->caller_message == NULL)
test_main_context_iterate (f->ctx, TRUE);
gconstpointer context)
{
DBusMessage *m;
+ const char *bus_name = context;
if (f->address == NULL)
return;
f->caller_filter_added = TRUE;
- /* The sender sends a message to an activatable service. */
- m = dbus_message_new_method_call ("com.example.ReceiveDenied", "/foo",
- "com.example.ReceiveDenied", "Call");
+ /* The sender sends a message to an activatable service.
+ * We set the interface name equal to the bus name to make it
+ * easier to write the necessary policy rules. */
+ m = dbus_message_new_method_call (bus_name, "/foo", bus_name, "Call");
if (m == NULL)
g_error ("OOM");
dbus_message_unref (m);
/* systemd starts the activatable service. */
+
+#if defined(DBUS_TEST_APPARMOR_ACTIVATION) && defined(HAVE_APPARMOR)
+ /* The use of 42 here is arbitrary, see setup(). */
+ if (aa_change_hat (bus_name, 42) != 0)
+ g_error ("Unable to change profile to ...//^%s: %s",
+ bus_name, g_strerror (errno));
+#endif
+
f->activated = test_connect_to_bus (f->ctx, f->address);
if (!dbus_connection_add_filter (f->activated, activated_filter,
f, NULL))
g_error ("OOM");
f->activated_filter_added = TRUE;
f->activated_name = dbus_bus_get_unique_name (f->activated);
- take_well_known_name (f, f->activated, "com.example.ReceiveDenied");
-
- /* We re-do the message matching, and now the message is
- * forbidden by the receive policy. */
+ take_well_known_name (f, f->activated, bus_name);
+
+#if defined(DBUS_TEST_APPARMOR_ACTIVATION) && defined(HAVE_APPARMOR)
+ if (aa_change_hat (NULL, 42) != 0)
+ g_error ("Unable to change back to initial profile: %s",
+ g_strerror (errno));
+#endif
+
+ /*
+ * We re-do the message matching, and now the message is
+ * forbidden by the receive policy.
+ *
+ * In the normal case, this is because the XML policy does not allow
+ * receiving any message with interface com.example.ReceiveDenied.
+ * We can't use the recipient's bus name here because the XML policy
+ * has no syntax for preventing the owner of a name from receiving
+ * messages - that would be pointless, because the sender could just
+ * open another connection and not own the same name on that connection.
+ *
+ * In the AppArmor case, this is because the AppArmor policy does not allow
+ * receiving messages with interface com.example.ReceiveDeniedByAppArmor
+ * from a peer with the same label we have. Again, we can't use the
+ * recipient's bus name because there is no syntax for this.
+ */
while (f->caller_message == NULL)
test_main_context_iterate (f->ctx, TRUE);
setup, test_activation, teardown);
g_test_add ("/sd-activation/uae", Fixture, NULL,
setup, test_uae, teardown);
- g_test_add ("/sd-activation/deny-send", Fixture, NULL,
+ g_test_add ("/sd-activation/deny-send", Fixture,
+ "com.example.SendDenied",
+ setup, test_deny_send, teardown);
+ g_test_add ("/sd-activation/deny-receive", Fixture,
+ "com.example.ReceiveDenied",
+ setup, test_deny_receive, teardown);
+
+#if defined(DBUS_TEST_APPARMOR_ACTIVATION)
+ g_test_add ("/sd-activation/apparmor/deny-send/by-label", Fixture,
+ "com.example.SendDeniedByAppArmorLabel",
+ setup, test_deny_send, teardown);
+ g_test_add ("/sd-activation/apparmor/deny-send/by-name", Fixture,
+ "com.example.SendDeniedByAppArmorName",
setup, test_deny_send, teardown);
- g_test_add ("/sd-activation/deny-receive", Fixture, NULL,
+ g_test_add ("/sd-activation/apparmor/deny-receive/by-label", Fixture,
+ "com.example.ReceiveDeniedByAppArmorLabel",
setup, test_deny_receive, teardown);
+#endif
return g_test_run ();
}
--- /dev/null
+#!/bin/sh
+
+# Copyright © 2016 Collabora Ltd.
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this software and associated documentation files
+# (the "Software"), to deal in the Software without restriction,
+# including without limitation the rights to use, copy, modify, merge,
+# publish, distribute, sublicense, and/or sell copies of the Software,
+# and to permit persons to whom the Software is furnished to do so,
+# subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+set -e
+
+if [ "x$(id -u)" != "x0" ]; then
+ echo "1..0 # SKIP - this test can only be run as root"
+ exit 0
+fi
+
+if [ -z "$DBUS_TEST_EXEC" ]; then
+ DBUS_TEST_EXEC="$(dirname "$0")"
+ if ! [ -x "$DBUS_TEST_EXEC/test-apparmor-activation" ]; then
+ echo "1..0 # SKIP - executable not found and DBUS_TEST_EXEC not set"
+ exit 0
+ fi
+fi
+
+if [ -z "$DBUS_TEST_DATA" ]; then
+ DBUS_TEST_DATA="$DBUS_TEST_EXEC/data"
+ if ! [ -e "$DBUS_TEST_DATA/dbus-installed-tests.aaprofile" ]; then
+ echo "1..0 # SKIP - required data not found and DBUS_TEST_DATA not set"
+ exit 0
+ fi
+fi
+
+echo "# Attempting to load AppArmor profiles"
+if ! apparmor_parser --skip-cache --replace \
+ "$DBUS_TEST_DATA/dbus-installed-tests.aaprofile"; then
+ echo "1..0 # SKIP - unable to load AppArmor profiles"
+ exit 0
+fi
+
+exec "$DBUS_TEST_EXEC/test-apparmor-activation" --tap "$@"
+
+# vim:set sts=4 sw=4 et: