aboutsummaryrefslogtreecommitdiffstats
path: root/meta-security/recipes-core
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2018-01-24 11:38:43 +0100
committerJosé Bollo <jose.bollo@iot.bzh>2018-02-13 11:02:00 +0100
commitf70d712e4f505f5c5b50ae17f4f023d20a667568 (patch)
tree57b0aaa702651012e1adfc07f9b6b6c580506f66 /meta-security/recipes-core
parent3f962c7d202055777dd0238f12dbcf70f09ac07d (diff)
Integrate parts of meta-intel-iot-security
Adds the recipes of the sub layers - meta-security-framework - meta-security-smack Change-Id: I618608008a3b3d1d34adb6e38048110f13ac0643 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
Diffstat (limited to 'meta-security/recipes-core')
-rw-r--r--meta-security/recipes-core/base-files/base-files_%.bbappend73
-rw-r--r--meta-security/recipes-core/coreutils/coreutils_%.bbappend7
-rw-r--r--meta-security/recipes-core/dbus/dbus-cynara/0001-Fix-memleak-in-GetConnectionCredentials-handler.patch32
-rw-r--r--meta-security/recipes-core/dbus/dbus-cynara/0002-New-a-sv-helper-for-using-byte-arrays-as-the-variant.patch97
-rw-r--r--meta-security/recipes-core/dbus/dbus-cynara/0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch515
-rw-r--r--meta-security/recipes-core/dbus/dbus-cynara/0004-Integration-of-Cynara-asynchronous-security-checks.patch2253
-rw-r--r--meta-security/recipes-core/dbus/dbus-cynara/0005-Disable-message-dispatching-when-send-rule-result-is.patch941
-rw-r--r--meta-security/recipes-core/dbus/dbus-cynara/0006-Handle-unavailability-of-policy-results-for-broadcas.patch1071
-rw-r--r--meta-security/recipes-core/dbus/dbus-cynara/0007-Add-own-rule-result-unavailability-handling.patch1142
-rw-r--r--meta-security/recipes-core/dbus/dbus-cynara/0008-Add-GetConnectionSmackContext-D-Bus-daemon-method.patch99
-rw-r--r--meta-security/recipes-core/dbus/dbus-cynara/Perform-Cynara-runtime-policy-checks-by-default.patch116
-rw-r--r--meta-security/recipes-core/dbus/dbus-cynara_1.8.18.bb58
-rw-r--r--meta-security/recipes-core/dbus/dbus-oe-core.inc170
-rw-r--r--meta-security/recipes-core/dbus/dbus_%.bbappend27
-rw-r--r--meta-security/recipes-core/packagegroups/packagegroup-security-framework.bb22
-rw-r--r--meta-security/recipes-core/systemd/systemd/0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup-v216.patch49
-rw-r--r--meta-security/recipes-core/systemd/systemd/0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup.patch50
-rw-r--r--meta-security/recipes-core/systemd/systemd/0004-tizen-smack-Handling-of-dev-v216.patch82
-rw-r--r--meta-security/recipes-core/systemd/systemd/0004-tizen-smack-Handling-of-dev.patch68
-rw-r--r--meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v216.patch107
-rw-r--r--meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v225.patch191
-rw-r--r--meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v228.patch179
-rw-r--r--meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network.patch106
-rw-r--r--meta-security/recipes-core/systemd/systemd/0007-tizen-smack-Runs-systemd-journald-with-v216.patch41
-rw-r--r--meta-security/recipes-core/systemd/systemd/0007-tizen-smack-Runs-systemd-journald-with.patch37
-rw-r--r--meta-security/recipes-core/systemd/systemd/mount-setup.c-fix-handling-of-symlink-Smack-labellin-v228.patch58
-rw-r--r--meta-security/recipes-core/systemd/systemd/udev-smack-default.rules23
-rw-r--r--meta-security/recipes-core/systemd/systemd_%.bbappend120
-rw-r--r--meta-security/recipes-core/util-linux/util-linux_%.bbappend8
29 files changed, 7742 insertions, 0 deletions
diff --git a/meta-security/recipes-core/base-files/base-files_%.bbappend b/meta-security/recipes-core/base-files/base-files_%.bbappend
new file mode 100644
index 000000000..7a37eb9dc
--- /dev/null
+++ b/meta-security/recipes-core/base-files/base-files_%.bbappend
@@ -0,0 +1,73 @@
+# Install default Smack rules, copied from a running Tizen IVI 3.0.
+# Corresponds to manifest file from default-access-domains in Tizen:
+# https://review.tizen.org/git?p=platform/core/security/default-ac-domains.git;a=blob;f=packaging/default-ac-domains.manifest
+do_install_append_with-lsm-smack () {
+ install -d ${D}/${sysconfdir}/smack/accesses.d
+ cat >${D}/${sysconfdir}/smack/accesses.d/default-access-domains <<EOF
+System _ -----l
+System System::Log rwxa--
+System System::Run rwxat-
+System System::Shared rwxat-
+System ^ rwxa--
+_ System::Run rwxat-
+_ System -wx---
+^ System::Log rwxa--
+^ System::Run rwxat-
+^ System rwxa--
+EOF
+ chmod 0644 ${D}/${sysconfdir}/smack/accesses.d/default-access-domains
+
+ install -d ${D}/${libdir}/tmpfiles.d
+ cat >${D}/${libdir}/tmpfiles.d/packet-forwarding.conf <<EOF
+t /proc/sys/net/ipv4/conf/all/forwarding - - - - security.SMACK64=*
+t /proc/sys/net/ipv6/conf/all/forwarding - - - - security.SMACK64=*
+t /proc/sys/net/ipv4/conf/default/forwarding - - - - security.SMACK64=*
+t /proc/sys/net/ipv6/conf/default/forwarding - - - - security.SMACK64=*
+EOF
+ chmod 0644 ${D}/${libdir}/tmpfiles.d/packet-forwarding.conf
+
+ install -d ${D}/${base_libdir}/udev/rules.d
+ cat >${D}/${base_libdir}/udev/rules.d/85-netdev-ipconf-smacklabel.rules <<EOF
+SUBSYSTEM=="net", ENV{ID_NET_NAME}=="", RUN+="/bin/sh -c '/usr/bin/chsmack -a \* /proc/sys/net/ipv4/conf/%k/*'", RUN+="/bin/sh -c '/usr/bin/chsmack -a \* /proc/sys/net/ipv6/conf/%k/*'"
+
+SUBSYSTEM=="net", ENV{ID_NET_NAME}!="", RUN+="/bin/sh -c '/usr/bin/chsmack -a \* /proc/sys/net/ipv4/conf/\$env{ID_NET_NAME}/*'", RUN+="/bin/sh -c '/usr/bin/chsmack -a \* /proc/sys/net/ipv6/conf/\$env{ID_NET_NAME}/*'"
+EOF
+ chmod 0644 ${D}/${base_libdir}/udev/rules.d/85-netdev-ipconf-smacklabel.rules
+}
+
+# Do not rely on an rpm with manifest support. Apparently that approach
+# will no longer be used in Tizen 3.0. Instead set special Smack attributes
+# via postinst. This is much easier to use with bitbake, too:
+# - no need to maintain a patched rpm
+# - works for directories which are not packaged by default when empty
+RDEPENDS_${PN}_append_with-lsm-smack = " smack-userspace"
+DEPENDS_append_with-lsm-smack = " smack-userspace-native"
+pkg_postinst_${PN}_with-lsm-smack() {
+ #!/bin/sh -e
+
+ # https://review.tizen.org/gerrit/gitweb?p=platform/upstream/filesystem.git;a=blob;f=packaging/filesystem.manifest:
+ # <filesystem path="/etc" label="System::Shared" type="transmutable" />
+ install -d $D${sysconfdir}
+ # This has no effect on files installed into /etc during image construction
+ # because pseudo does not know the special semantic of SMACK::TRANSMUTE.
+ # To avoid having different xattrs on files inside /etc when pre-installed
+ # in an image vs. installed on a device, the xattr-images.bbclass has
+ # a workaround for this deficiency in pseudo.
+ chsmack -t $D${sysconfdir}
+ chsmack -a 'System::Shared' $D${sysconfdir}
+
+ # Same for /var. Any daemon running as "System" will get write access
+ # to everything.
+ install -d $D${localstatedir}
+ chsmack -t $D${localstatedir}
+ chsmack -a 'System::Shared' $D${localstatedir}
+
+ # <filesystem path="/tmp" label="*" />
+ mkdir -p $D/tmp
+ chsmack -a '*' $D/tmp
+
+ # <filesystem path="/var/log" label="System::Log" type="transmutable" />
+ # <filesystem path="/var/tmp" label="*" />
+ # These are in a file system mounted by systemd. We patch the systemd service
+ # to set these attributes.
+}
diff --git a/meta-security/recipes-core/coreutils/coreutils_%.bbappend b/meta-security/recipes-core/coreutils/coreutils_%.bbappend
new file mode 100644
index 000000000..ceaf6a29c
--- /dev/null
+++ b/meta-security/recipes-core/coreutils/coreutils_%.bbappend
@@ -0,0 +1,7 @@
+# Smack patches are included in coreutils v8.22, we just need to enable them.
+# The default is not deterministic (enabled if libsmack found), so disable
+# explicitly otherwise.
+EXTRA_OECONF_SMACK = "--disable-libsmack"
+EXTRA_OECONF_SMACK_with-lsm-smack = "--enable-libsmack"
+EXTRA_OECONF_append = " ${EXTRA_OECONF_SMACK}"
+DEPENDS_append_with-lsm-smack = " smack"
diff --git a/meta-security/recipes-core/dbus/dbus-cynara/0001-Fix-memleak-in-GetConnectionCredentials-handler.patch b/meta-security/recipes-core/dbus/dbus-cynara/0001-Fix-memleak-in-GetConnectionCredentials-handler.patch
new file mode 100644
index 000000000..271ac48a1
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-cynara/0001-Fix-memleak-in-GetConnectionCredentials-handler.patch
@@ -0,0 +1,32 @@
+From eacdc525a1f7bfc534e248a5a946c08b6f4aab35 Mon Sep 17 00:00:00 2001
+From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
+Date: Wed, 17 Jun 2015 18:53:41 +0100
+Subject: [PATCH 1/8] Fix memleak in GetConnectionCredentials handler
+
+Reply message was not unreferenced when GetConnectionCredentials
+handler was successful.
+
+Signed-off-by: Jacek Bukarewicz <j.bukarewicz@samsung.com>
+[smcv: changed bus_message_unref() to dbus_message_unref()]
+Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=91008
+---
+ bus/driver.c | 2 ++
+ 1 file changed, 2 insertions(+)
+
+diff --git a/bus/driver.c b/bus/driver.c
+index f5d3ebe..888c7ca 100644
+--- a/bus/driver.c
++++ b/bus/driver.c
+@@ -1613,6 +1613,8 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
+ goto oom;
+ }
+
++ dbus_message_unref (reply);
++
+ return TRUE;
+
+ oom:
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/dbus/dbus-cynara/0002-New-a-sv-helper-for-using-byte-arrays-as-the-variant.patch b/meta-security/recipes-core/dbus/dbus-cynara/0002-New-a-sv-helper-for-using-byte-arrays-as-the-variant.patch
new file mode 100644
index 000000000..64c8b9b50
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-cynara/0002-New-a-sv-helper-for-using-byte-arrays-as-the-variant.patch
@@ -0,0 +1,97 @@
+From 25cb15916402c55112cae2be0954d24afe74e2f2 Mon Sep 17 00:00:00 2001
+From: Tyler Hicks <tyhicks@canonical.com>
+Date: Thu, 13 Mar 2014 17:37:38 -0500
+Subject: [PATCH 2/8] New a{sv} helper for using byte arrays as the variant
+
+Create a new helper for using a byte array as the value in the mapping
+from string to variant.
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=75113
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=89041
+Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
+Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
+---
+ dbus/dbus-asv-util.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++++
+ dbus/dbus-asv-util.h | 4 ++++
+ 2 files changed, 58 insertions(+)
+
+diff --git a/dbus/dbus-asv-util.c b/dbus/dbus-asv-util.c
+index 583e41f..d3ac5e9 100644
+--- a/dbus/dbus-asv-util.c
++++ b/dbus/dbus-asv-util.c
+@@ -258,3 +258,57 @@ _dbus_asv_add_string (DBusMessageIter *arr_iter,
+
+ return TRUE;
+ }
++
++/**
++ * Create a new entry in an a{sv} (map from string to variant)
++ * with a byte array value.
++ *
++ * If this function fails, the a{sv} must be abandoned, for instance
++ * with _dbus_asv_abandon().
++ *
++ * @param arr_iter the iterator which is appending to the array
++ * @param key a UTF-8 key for the map
++ * @param value the value
++ * @param n_elements the number of elements to append
++ * @returns #TRUE on success, or #FALSE if not enough memory
++ */
++dbus_bool_t
++_dbus_asv_add_byte_array (DBusMessageIter *arr_iter,
++ const char *key,
++ const void *value,
++ int n_elements)
++{
++ DBusMessageIter entry_iter;
++ DBusMessageIter var_iter;
++ DBusMessageIter byte_array_iter;
++
++ if (!_dbus_asv_open_entry (arr_iter, &entry_iter, key, "ay", &var_iter))
++ return FALSE;
++
++ if (!dbus_message_iter_open_container (&var_iter, DBUS_TYPE_ARRAY,
++ DBUS_TYPE_BYTE_AS_STRING,
++ &byte_array_iter))
++ {
++ _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
++ return FALSE;
++ }
++
++ if (!dbus_message_iter_append_fixed_array (&byte_array_iter, DBUS_TYPE_BYTE,
++ &value, n_elements))
++ {
++ dbus_message_iter_abandon_container (&var_iter, &byte_array_iter);
++ _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
++ return FALSE;
++ }
++
++ if (!dbus_message_iter_close_container (&var_iter, &byte_array_iter))
++ {
++ _dbus_asv_abandon_entry (arr_iter, &entry_iter, &var_iter);
++ return FALSE;
++ }
++
++ if (!_dbus_asv_close_entry (arr_iter, &entry_iter, &var_iter))
++ return FALSE;
++
++ return TRUE;
++}
+diff --git a/dbus/dbus-asv-util.h b/dbus/dbus-asv-util.h
+index 0337260..277ab80 100644
+--- a/dbus/dbus-asv-util.h
++++ b/dbus/dbus-asv-util.h
+@@ -42,5 +42,9 @@ dbus_bool_t _dbus_asv_add_uint32 (DBusMessageIter *arr_iter,
+ dbus_bool_t _dbus_asv_add_string (DBusMessageIter *arr_iter,
+ const char *key,
+ const char *value);
++dbus_bool_t _dbus_asv_add_byte_array (DBusMessageIter *arr_iter,
++ const char *key,
++ const void *value,
++ int n_elements);
+
+ #endif
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/dbus/dbus-cynara/0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch b/meta-security/recipes-core/dbus/dbus-cynara/0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch
new file mode 100644
index 000000000..fcb85504d
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-cynara/0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch
@@ -0,0 +1,515 @@
+From 9da49d4eb6982c659fec988231baef8cd1b05be2 Mon Sep 17 00:00:00 2001
+From: Simon McVittie <simon.mcvittie@collabora.co.uk>
+Date: Wed, 11 Feb 2015 13:19:15 +0000
+Subject: [PATCH 3/8] Add LSM-agnostic support for LinuxSecurityLabel
+ credential
+
+Bug: https://bugs.freedesktop.org/show_bug.cgi?id=89041
+Change-Id: I70512843d1a7661c87461b1b6d86fbfbda934ad5
+Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
+Acked-by: Stephen Smalley <sds@tycho.nsa.gov> (for SELinux)
+Acked-by: John Johansen <john.johansen@canonical.com> (for AppArmor)
+Acked-by: Casey Schaufler <casey@schaufler-ca.com> (for Smack)
+Tested-by: Tyler Hicks <tyhicks@canonical.com>
+---
+ bus/driver.c | 19 ++++++++
+ dbus/dbus-auth.c | 11 +++--
+ dbus/dbus-connection-internal.h | 3 ++
+ dbus/dbus-connection.c | 26 ++++++++++
+ dbus/dbus-credentials.c | 68 ++++++++++++++++++++++++++
+ dbus/dbus-credentials.h | 4 ++
+ dbus/dbus-sysdeps-unix.c | 105 ++++++++++++++++++++++++++++++++++++++++
+ dbus/dbus-transport.c | 27 +++++++++++
+ dbus/dbus-transport.h | 3 ++
+ 9 files changed, 262 insertions(+), 4 deletions(-)
+
+diff --git a/bus/driver.c b/bus/driver.c
+index 888c7ca..11706f8 100644
+--- a/bus/driver.c
++++ b/bus/driver.c
+@@ -34,6 +34,7 @@
+ #include "utils.h"
+
+ #include <dbus/dbus-asv-util.h>
++#include <dbus/dbus-connection-internal.h>
+ #include <dbus/dbus-string.h>
+ #include <dbus/dbus-internals.h>
+ #include <dbus/dbus-message.h>
+@@ -1567,6 +1568,7 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
+ DBusMessageIter reply_iter;
+ DBusMessageIter array_iter;
+ unsigned long ulong_val;
++ char *s;
+ const char *service;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+@@ -1601,6 +1603,23 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
+ goto oom;
+ }
+
++ if (_dbus_connection_get_linux_security_label (conn, &s))
++ {
++ if (s == NULL)
++ goto oom;
++
++ /* use the GVariant bytestring convention for strings of unknown
++ * encoding: include the \0 in the payload, for zero-copy reading */
++ if (!_dbus_asv_add_byte_array (&array_iter, "LinuxSecurityLabel",
++ s, strlen (s) + 1))
++ {
++ dbus_free (s);
++ goto oom;
++ }
++
++ dbus_free (s);
++ }
++
+ if (!_dbus_asv_close (&reply_iter, &array_iter))
+ goto oom;
+
+diff --git a/dbus/dbus-auth.c b/dbus/dbus-auth.c
+index 6a07665..aee877d 100644
+--- a/dbus/dbus-auth.c
++++ b/dbus/dbus-auth.c
+@@ -1102,20 +1102,23 @@ handle_server_data_external_mech (DBusAuth *auth,
+ auth->desired_identity))
+ return FALSE;
+
+- /* also copy process ID from the socket credentials
++ /* also copy misc process info from the socket credentials
+ */
+ if (!_dbus_credentials_add_credential (auth->authorized_identity,
+ DBUS_CREDENTIAL_UNIX_PROCESS_ID,
+ auth->credentials))
+ return FALSE;
+
+- /* also copy audit data from the socket credentials
+- */
+ if (!_dbus_credentials_add_credential (auth->authorized_identity,
+ DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
+ auth->credentials))
+ return FALSE;
+-
++
++ if (!_dbus_credentials_add_credential (auth->authorized_identity,
++ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
++ auth->credentials))
++ return FALSE;
++
+ if (!send_ok (auth))
+ return FALSE;
+
+diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h
+index 2897404..64ef336 100644
+--- a/dbus/dbus-connection-internal.h
++++ b/dbus/dbus-connection-internal.h
+@@ -107,6 +107,9 @@ void _dbus_connection_set_pending_fds_function (DBusConnectio
+ DBusPendingFdsChangeFunction callback,
+ void *data);
+
++dbus_bool_t _dbus_connection_get_linux_security_label (DBusConnection *connection,
++ char **label_p);
++
+ /* if DBUS_ENABLE_STATS */
+ void _dbus_connection_get_stats (DBusConnection *connection,
+ dbus_uint32_t *in_messages,
+diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
+index b574207..8952b75 100644
+--- a/dbus/dbus-connection.c
++++ b/dbus/dbus-connection.c
+@@ -5322,6 +5322,32 @@ dbus_connection_set_unix_user_function (DBusConnection *connection,
+ (* old_free_function) (old_data);
+ }
+
++/* Same calling convention as dbus_connection_get_windows_user */
++dbus_bool_t
++_dbus_connection_get_linux_security_label (DBusConnection *connection,
++ char **label_p)
++{
++ dbus_bool_t result;
++
++ _dbus_assert (connection != NULL);
++ _dbus_assert (label_p != NULL);
++
++ CONNECTION_LOCK (connection);
++
++ if (!_dbus_transport_try_to_authenticate (connection->transport))
++ result = FALSE;
++ else
++ result = _dbus_transport_get_linux_security_label (connection->transport,
++ label_p);
++#ifndef __linux__
++ _dbus_assert (!result);
++#endif
++
++ CONNECTION_UNLOCK (connection);
++
++ return result;
++}
++
+ /**
+ * Gets the Windows user SID of the connection if known. Returns
+ * #TRUE if the ID is filled in. Always returns #FALSE on non-Windows
+diff --git a/dbus/dbus-credentials.c b/dbus/dbus-credentials.c
+index 7325125..151bb00 100644
+--- a/dbus/dbus-credentials.c
++++ b/dbus/dbus-credentials.c
+@@ -50,6 +50,7 @@ struct DBusCredentials {
+ dbus_uid_t unix_uid;
+ dbus_pid_t pid;
+ char *windows_sid;
++ char *linux_security_label;
+ void *adt_audit_data;
+ dbus_int32_t adt_audit_data_size;
+ };
+@@ -79,6 +80,7 @@ _dbus_credentials_new (void)
+ creds->unix_uid = DBUS_UID_UNSET;
+ creds->pid = DBUS_PID_UNSET;
+ creds->windows_sid = NULL;
++ creds->linux_security_label = NULL;
+ creds->adt_audit_data = NULL;
+ creds->adt_audit_data_size = 0;
+
+@@ -133,6 +135,7 @@ _dbus_credentials_unref (DBusCredentials *credentials)
+ if (credentials->refcount == 0)
+ {
+ dbus_free (credentials->windows_sid);
++ dbus_free (credentials->linux_security_label);
+ dbus_free (credentials->adt_audit_data);
+ dbus_free (credentials);
+ }
+@@ -193,6 +196,30 @@ _dbus_credentials_add_windows_sid (DBusCredentials *credentials,
+ }
+
+ /**
++ * Add a Linux security label, as used by LSMs such as SELinux, Smack and
++ * AppArmor, to the credentials.
++ *
++ * @param credentials the object
++ * @param label the label
++ * @returns #FALSE if no memory
++ */
++dbus_bool_t
++_dbus_credentials_add_linux_security_label (DBusCredentials *credentials,
++ const char *label)
++{
++ char *copy;
++
++ copy = _dbus_strdup (label);
++ if (copy == NULL)
++ return FALSE;
++
++ dbus_free (credentials->linux_security_label);
++ credentials->linux_security_label = copy;
++
++ return TRUE;
++}
++
++/**
+ * Add ADT audit data to the credentials.
+ *
+ * @param credentials the object
+@@ -236,6 +263,8 @@ _dbus_credentials_include (DBusCredentials *credentials,
+ return credentials->unix_uid != DBUS_UID_UNSET;
+ case DBUS_CREDENTIAL_WINDOWS_SID:
+ return credentials->windows_sid != NULL;
++ case DBUS_CREDENTIAL_LINUX_SECURITY_LABEL:
++ return credentials->linux_security_label != NULL;
+ case DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID:
+ return credentials->adt_audit_data != NULL;
+ }
+@@ -284,6 +313,19 @@ _dbus_credentials_get_windows_sid (DBusCredentials *credentials)
+ }
+
+ /**
++ * Gets the Linux security label (as used by LSMs) from the credentials,
++ * or #NULL if the credentials object doesn't contain a security label.
++ *
++ * @param credentials the object
++ * @returns the security label
++ */
++const char *
++_dbus_credentials_get_linux_security_label (DBusCredentials *credentials)
++{
++ return credentials->linux_security_label;
++}
++
++/**
+ * Gets the ADT audit data in the credentials, or #NULL if
+ * the credentials object doesn't contain ADT audit data.
+ *
+@@ -329,6 +371,10 @@ _dbus_credentials_are_superset (DBusCredentials *credentials,
+ (possible_subset->windows_sid == NULL ||
+ (credentials->windows_sid && strcmp (possible_subset->windows_sid,
+ credentials->windows_sid) == 0)) &&
++ (possible_subset->linux_security_label == NULL ||
++ (credentials->linux_security_label != NULL &&
++ strcmp (possible_subset->linux_security_label,
++ credentials->linux_security_label) == 0)) &&
+ (possible_subset->adt_audit_data == NULL ||
+ (credentials->adt_audit_data && memcmp (possible_subset->adt_audit_data,
+ credentials->adt_audit_data,
+@@ -348,6 +394,7 @@ _dbus_credentials_are_empty (DBusCredentials *credentials)
+ credentials->pid == DBUS_PID_UNSET &&
+ credentials->unix_uid == DBUS_UID_UNSET &&
+ credentials->windows_sid == NULL &&
++ credentials->linux_security_label == NULL &&
+ credentials->adt_audit_data == NULL;
+ }
+
+@@ -388,6 +435,9 @@ _dbus_credentials_add_credentials (DBusCredentials *credentials,
+ DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
+ other_credentials) &&
+ _dbus_credentials_add_credential (credentials,
++ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
++ other_credentials) &&
++ _dbus_credentials_add_credential (credentials,
+ DBUS_CREDENTIAL_WINDOWS_SID,
+ other_credentials);
+ }
+@@ -427,6 +477,13 @@ _dbus_credentials_add_credential (DBusCredentials *credentials,
+ if (!_dbus_credentials_add_windows_sid (credentials, other_credentials->windows_sid))
+ return FALSE;
+ }
++ else if (which == DBUS_CREDENTIAL_LINUX_SECURITY_LABEL &&
++ other_credentials->linux_security_label != NULL)
++ {
++ if (!_dbus_credentials_add_linux_security_label (credentials,
++ other_credentials->linux_security_label))
++ return FALSE;
++ }
+ else if (which == DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID &&
+ other_credentials->adt_audit_data != NULL)
+ {
+@@ -449,6 +506,8 @@ _dbus_credentials_clear (DBusCredentials *credentials)
+ credentials->unix_uid = DBUS_UID_UNSET;
+ dbus_free (credentials->windows_sid);
+ credentials->windows_sid = NULL;
++ dbus_free (credentials->linux_security_label);
++ credentials->linux_security_label = NULL;
+ dbus_free (credentials->adt_audit_data);
+ credentials->adt_audit_data = NULL;
+ credentials->adt_audit_data_size = 0;
+@@ -540,6 +599,15 @@ _dbus_credentials_to_string_append (DBusCredentials *credentials,
+ else
+ join = FALSE;
+
++ if (credentials->linux_security_label != NULL)
++ {
++ if (!_dbus_string_append_printf (string, "%slsm='%s'",
++ join ? " " : "",
++ credentials->linux_security_label))
++ goto oom;
++ join = TRUE;
++ }
++
+ return TRUE;
+ oom:
+ return FALSE;
+diff --git a/dbus/dbus-credentials.h b/dbus/dbus-credentials.h
+index abcc4bb..ab74eac 100644
+--- a/dbus/dbus-credentials.h
++++ b/dbus/dbus-credentials.h
+@@ -34,6 +34,7 @@ typedef enum {
+ DBUS_CREDENTIAL_UNIX_PROCESS_ID,
+ DBUS_CREDENTIAL_UNIX_USER_ID,
+ DBUS_CREDENTIAL_ADT_AUDIT_DATA_ID,
++ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL,
+ DBUS_CREDENTIAL_WINDOWS_SID
+ } DBusCredentialType;
+
+@@ -47,6 +48,8 @@ dbus_bool_t _dbus_credentials_add_unix_uid (DBusCredentials
+ dbus_uid_t uid);
+ dbus_bool_t _dbus_credentials_add_windows_sid (DBusCredentials *credentials,
+ const char *windows_sid);
++dbus_bool_t _dbus_credentials_add_linux_security_label (DBusCredentials *credentials,
++ const char *label);
+ dbus_bool_t _dbus_credentials_add_adt_audit_data (DBusCredentials *credentials,
+ void *audit_data,
+ dbus_int32_t size);
+@@ -55,6 +58,7 @@ dbus_bool_t _dbus_credentials_include (DBusCredentials
+ dbus_pid_t _dbus_credentials_get_pid (DBusCredentials *credentials);
+ dbus_uid_t _dbus_credentials_get_unix_uid (DBusCredentials *credentials);
+ const char* _dbus_credentials_get_windows_sid (DBusCredentials *credentials);
++const char * _dbus_credentials_get_linux_security_label (DBusCredentials *credentials);
+ void * _dbus_credentials_get_adt_audit_data (DBusCredentials *credentials);
+ dbus_int32_t _dbus_credentials_get_adt_audit_data_size (DBusCredentials *credentials);
+ dbus_bool_t _dbus_credentials_are_superset (DBusCredentials *credentials,
+diff --git a/dbus/dbus-sysdeps-unix.c b/dbus/dbus-sysdeps-unix.c
+index fe891ab..61af423 100644
+--- a/dbus/dbus-sysdeps-unix.c
++++ b/dbus/dbus-sysdeps-unix.c
+@@ -1639,6 +1639,105 @@ write_credentials_byte (int server_fd,
+ }
+ }
+
++/* return FALSE on OOM, TRUE otherwise, even if no credentials were found */
++static dbus_bool_t
++add_linux_security_label_to_credentials (int client_fd,
++ DBusCredentials *credentials)
++{
++#if defined(__linux__) && defined(SO_PEERSEC)
++ DBusString buf;
++ socklen_t len = 1024;
++ dbus_bool_t oom = FALSE;
++
++ if (!_dbus_string_init_preallocated (&buf, len) ||
++ !_dbus_string_set_length (&buf, len))
++ return FALSE;
++
++ while (getsockopt (client_fd, SOL_SOCKET, SO_PEERSEC,
++ _dbus_string_get_data (&buf), &len) < 0)
++ {
++ int e = errno;
++
++ _dbus_verbose ("getsockopt failed with %s, len now %lu\n",
++ _dbus_strerror (e), (unsigned long) len);
++
++ if (e != ERANGE || len <= _dbus_string_get_length (&buf))
++ {
++ _dbus_verbose ("Failed to getsockopt(SO_PEERSEC): %s\n",
++ _dbus_strerror (e));
++ goto out;
++ }
++
++ /* If not enough space, len is updated to be enough.
++ * Try again with a large enough buffer. */
++ if (!_dbus_string_set_length (&buf, len))
++ {
++ oom = TRUE;
++ goto out;
++ }
++
++ _dbus_verbose ("will try again with %lu\n", (unsigned long) len);
++ }
++
++ if (len <= 0)
++ {
++ _dbus_verbose ("getsockopt(SO_PEERSEC) yielded <= 0 bytes: %lu\n",
++ (unsigned long) len);
++ goto out;
++ }
++
++ if (len > _dbus_string_get_length (&buf))
++ {
++ _dbus_verbose ("%lu > %d", (unsigned long) len,
++ _dbus_string_get_length (&buf));
++ _dbus_assert_not_reached ("getsockopt(SO_PEERSEC) overflowed");
++ }
++
++ if (_dbus_string_get_byte (&buf, len - 1) == 0)
++ {
++ /* the kernel included the trailing \0 in its count,
++ * but DBusString always has an extra \0 after the data anyway */
++ _dbus_verbose ("subtracting trailing \\0\n");
++ len--;
++ }
++
++ if (!_dbus_string_set_length (&buf, len))
++ {
++ _dbus_assert_not_reached ("shortening string should not lead to OOM");
++ oom = TRUE;
++ goto out;
++ }
++
++ if (strlen (_dbus_string_get_const_data (&buf)) != len)
++ {
++ /* LSM people on the linux-security-module@ mailing list say this
++ * should never happen: the label should be a bytestring with
++ * an optional trailing \0 */
++ _dbus_verbose ("security label from kernel had an embedded \\0, "
++ "ignoring it\n");
++ goto out;
++ }
++
++ _dbus_verbose ("getsockopt(SO_PEERSEC): %lu bytes excluding \\0: %s\n",
++ (unsigned long) len,
++ _dbus_string_get_const_data (&buf));
++
++ if (!_dbus_credentials_add_linux_security_label (credentials,
++ _dbus_string_get_const_data (&buf)))
++ {
++ oom = TRUE;
++ goto out;
++ }
++
++out:
++ _dbus_string_free (&buf);
++ return !oom;
++#else
++ /* no error */
++ return TRUE;
++#endif
++}
++
+ /**
+ * Reads a single byte which must be nul (an error occurs otherwise),
+ * and reads unix credentials if available. Clears the credentials
+@@ -1922,6 +2021,12 @@ _dbus_read_credentials_socket (int client_fd,
+ }
+ }
+
++ if (!add_linux_security_label_to_credentials (client_fd, credentials))
++ {
++ _DBUS_SET_OOM (error);
++ return FALSE;
++ }
++
+ return TRUE;
+ }
+
+diff --git a/dbus/dbus-transport.c b/dbus/dbus-transport.c
+index e9dcc56..a43e7bb 100644
+--- a/dbus/dbus-transport.c
++++ b/dbus/dbus-transport.c
+@@ -1425,6 +1425,33 @@ _dbus_transport_set_unix_user_function (DBusTransport *transport,
+ transport->free_unix_user_data = free_data_function;
+ }
+
++dbus_bool_t
++_dbus_transport_get_linux_security_label (DBusTransport *transport,
++ char **label_p)
++{
++ DBusCredentials *auth_identity;
++
++ *label_p = NULL;
++
++ if (!transport->authenticated)
++ return FALSE;
++
++ auth_identity = _dbus_auth_get_identity (transport->auth);
++
++ if (_dbus_credentials_include (auth_identity,
++ DBUS_CREDENTIAL_LINUX_SECURITY_LABEL))
++ {
++ /* If no memory, we are supposed to return TRUE and set NULL */
++ *label_p = _dbus_strdup (_dbus_credentials_get_linux_security_label (auth_identity));
++
++ return TRUE;
++ }
++ else
++ {
++ return FALSE;
++ }
++}
++
+ /**
+ * See dbus_connection_get_windows_user().
+ *
+diff --git a/dbus/dbus-transport.h b/dbus/dbus-transport.h
+index 39c74c4..843f231 100644
+--- a/dbus/dbus-transport.h
++++ b/dbus/dbus-transport.h
+@@ -87,6 +87,9 @@ void _dbus_transport_set_unix_user_function (DBusTransport
+ DBusFreeFunction *old_free_data_function);
+ dbus_bool_t _dbus_transport_get_windows_user (DBusTransport *transport,
+ char **windows_sid_p);
++dbus_bool_t _dbus_transport_get_linux_security_label (DBusTransport *transport,
++ char **label_p);
++
+ void _dbus_transport_set_windows_user_function (DBusTransport *transport,
+ DBusAllowWindowsUserFunction function,
+ void *data,
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/dbus/dbus-cynara/0004-Integration-of-Cynara-asynchronous-security-checks.patch b/meta-security/recipes-core/dbus/dbus-cynara/0004-Integration-of-Cynara-asynchronous-security-checks.patch
new file mode 100644
index 000000000..70d5fc9d7
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-cynara/0004-Integration-of-Cynara-asynchronous-security-checks.patch
@@ -0,0 +1,2253 @@
+From 4dcfb02f17247ff9de966b62182cd2e08f301238 Mon Sep 17 00:00:00 2001
+From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
+Date: Thu, 27 Nov 2014 18:11:05 +0100
+Subject: [PATCH 4/8] Integration of Cynara asynchronous security checks
+
+This commit introduces basic framework for asynchronous policy
+checks and Cynara integration code. Functions for checking security
+policy can now return third value - BUS_RESULT_LATER denoting check
+result unavailability. Whenever policy checker cannot decide on the
+result of the check it is supposed to allocate DeferredMessage structure
+that will be passed to the upper layers which can decide what should be
+done in such situation.
+Proper handling of such case will be implemented in subsequent commits.
+Currently such return value results in message denial.
+
+Change-Id: I9bcbce34577e5dc2a3cecf6233a0a2b0e43e1108
+---
+ bus/Makefile.am | 6 +
+ bus/bus.c | 134 +++++---
+ bus/bus.h | 58 ++--
+ bus/check.c | 215 ++++++++++++
+ bus/check.h | 68 ++++
+ bus/config-parser-common.c | 6 +
+ bus/config-parser-common.h | 1 +
+ bus/config-parser.c | 71 +++-
+ bus/connection.c | 56 ++-
+ bus/connection.h | 5 +
+ bus/cynara.c | 374 +++++++++++++++++++++
+ bus/cynara.h | 37 ++
+ bus/dispatch.c | 51 ++-
+ bus/policy.c | 193 +++++++----
+ bus/policy.h | 51 ++-
+ configure.ac | 13 +
+ test/Makefile.am | 1 +
+ test/data/invalid-config-files/badcheck-1.conf | 9 +
+ test/data/invalid-config-files/badcheck-2.conf | 9 +
+ test/data/valid-config-files/check-1.conf | 9 +
+ .../valid-config-files/debug-check-some.conf.in | 18 +
+ 22 files changed, 1211 insertions(+), 180 deletions(-)
+ create mode 100644 bus/check.c
+ create mode 100644 bus/check.h
+ create mode 100644 bus/cynara.c
+ create mode 100644 bus/cynara.h
+ create mode 100644 test/data/invalid-config-files/badcheck-1.conf
+ create mode 100644 test/data/invalid-config-files/badcheck-2.conf
+ create mode 100644 test/data/valid-config-files/check-1.conf
+ create mode 100644 test/data/valid-config-files/debug-check-some.conf.in
+
+diff --git a/bus/Makefile.am b/bus/Makefile.am
+index f335e30..b057d6b 100644
+--- a/bus/Makefile.am
++++ b/bus/Makefile.am
+@@ -7,6 +7,7 @@ DBUS_BUS_LIBS = \
+ $(THREAD_LIBS) \
+ $(ADT_LIBS) \
+ $(NETWORK_libs) \
++ $(CYNARA_LIBS) \
+ $(NULL)
+
+ DBUS_LAUNCHER_LIBS = \
+@@ -21,6 +22,7 @@ AM_CPPFLAGS = \
+ -DDBUS_SYSTEM_CONFIG_FILE=\""$(configdir)/system.conf"\" \
+ -DDBUS_COMPILATION \
+ -DDBUS_STATIC_BUILD \
++ $(CYNARA_CFLAGS) \
+ $(NULL)
+
+ # if assertions are enabled, improve backtraces
+@@ -60,12 +62,16 @@ BUS_SOURCES= \
+ activation-exit-codes.h \
+ bus.c \
+ bus.h \
++ check.c \
++ check.h \
+ config-parser.c \
+ config-parser.h \
+ config-parser-common.c \
+ config-parser-common.h \
+ connection.c \
+ connection.h \
++ cynara.c \
++ cynara.h \
+ desktop-file.c \
+ desktop-file.h \
+ $(DIR_WATCH_SOURCE) \
+diff --git a/bus/bus.c b/bus/bus.c
+index f0d980e..ac9ea8d 100644
+--- a/bus/bus.c
++++ b/bus/bus.c
+@@ -35,6 +35,7 @@
+ #include "signals.h"
+ #include "selinux.h"
+ #include "dir-watch.h"
++#include "check.h"
+ #include <dbus/dbus-list.h>
+ #include <dbus/dbus-hash.h>
+ #include <dbus/dbus-credentials.h>
+@@ -63,6 +64,7 @@ struct BusContext
+ BusRegistry *registry;
+ BusPolicy *policy;
+ BusMatchmaker *matchmaker;
++ BusCheck *check;
+ BusLimits limits;
+ DBusRLimit *initial_fd_limit;
+ unsigned int fork : 1;
+@@ -962,6 +964,10 @@ bus_context_new (const DBusString *config_file,
+ #endif
+ }
+
++ context->check = bus_check_new(context, error);
++ if (context->check == NULL)
++ goto failed;
++
+ dbus_server_free_data_slot (&server_data_slot);
+
+ return context;
+@@ -1086,6 +1092,12 @@ bus_context_unref (BusContext *context)
+
+ bus_context_shutdown (context);
+
++ if (context->check)
++ {
++ bus_check_unref(context->check);
++ context->check = NULL;
++ }
++
+ if (context->connections)
+ {
+ bus_connections_unref (context->connections);
+@@ -1215,6 +1227,12 @@ bus_context_get_loop (BusContext *context)
+ return context->loop;
+ }
+
++BusCheck*
++bus_context_get_check (BusContext *context)
++{
++ return context->check;
++}
++
+ dbus_bool_t
+ bus_context_allow_unix_user (BusContext *context,
+ unsigned long uid)
+@@ -1386,6 +1404,7 @@ complain_about_message (BusContext *context,
+ DBusConnection *proposed_recipient,
+ dbus_bool_t requested_reply,
+ dbus_bool_t log,
++ const char *privilege,
+ DBusError *error)
+ {
+ DBusError stack_error = DBUS_ERROR_INIT;
+@@ -1415,7 +1434,8 @@ complain_about_message (BusContext *context,
+ dbus_set_error (&stack_error, error_name,
+ "%s, %d matched rules; type=\"%s\", sender=\"%s\" (%s) "
+ "interface=\"%s\" member=\"%s\" error name=\"%s\" "
+- "requested_reply=\"%d\" destination=\"%s\" (%s)",
++ "requested_reply=\"%d\" destination=\"%s\" (%s) "
++ "privilege=\"%s\"",
+ complaint,
+ matched_rules,
+ dbus_message_type_to_string (dbus_message_get_type (message)),
+@@ -1426,7 +1446,8 @@ complain_about_message (BusContext *context,
+ nonnull (dbus_message_get_error_name (message), "(unset)"),
+ requested_reply,
+ nonnull (dbus_message_get_destination (message), DBUS_SERVICE_DBUS),
+- proposed_recipient_loginfo);
++ proposed_recipient_loginfo,
++ nonnull (privilege, "(n/a)"));
+
+ /* If we hit OOM while setting the error, this will syslog "out of memory"
+ * which is itself an indication that something is seriously wrong */
+@@ -1450,14 +1471,15 @@ complain_about_message (BusContext *context,
+ * NULL for addressed_recipient may mean the bus driver, or may mean
+ * no destination was specified in the message (e.g. a signal).
+ */
+-dbus_bool_t
+-bus_context_check_security_policy (BusContext *context,
+- BusTransaction *transaction,
+- DBusConnection *sender,
+- DBusConnection *addressed_recipient,
+- DBusConnection *proposed_recipient,
+- DBusMessage *message,
+- DBusError *error)
++BusResult
++bus_context_check_security_policy (BusContext *context,
++ BusTransaction *transaction,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusConnection *proposed_recipient,
++ DBusMessage *message,
++ DBusError *error,
++ BusDeferredMessage **deferred_message)
+ {
+ const char *dest;
+ BusClientPolicy *sender_policy;
+@@ -1466,6 +1488,7 @@ bus_context_check_security_policy (BusContext *context,
+ dbus_bool_t log;
+ int type;
+ dbus_bool_t requested_reply;
++ const char *privilege;
+
+ type = dbus_message_get_type (message);
+ dest = dbus_message_get_destination (message);
+@@ -1493,7 +1516,7 @@ bus_context_check_security_policy (BusContext *context,
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "Message bus will not accept messages of unknown type\n");
+
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ requested_reply = FALSE;
+@@ -1517,11 +1540,11 @@ bus_context_check_security_policy (BusContext *context,
+ complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+ "An SELinux policy prevents this sender from sending this "
+ "message to this recipient",
+- 0, message, sender, proposed_recipient, FALSE, FALSE, error);
++ 0, message, sender, proposed_recipient, FALSE, FALSE, NULL, error);
+ _dbus_verbose ("SELinux security check denying send to service\n");
+ }
+
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ if (bus_connection_is_active (sender))
+@@ -1547,7 +1570,7 @@ bus_context_check_security_policy (BusContext *context,
+ if (dbus_error_is_set (&error2))
+ {
+ dbus_move_error (&error2, error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+ }
+ }
+@@ -1564,7 +1587,7 @@ bus_context_check_security_policy (BusContext *context,
+ {
+ _dbus_verbose ("security check allowing %s message\n",
+ "Hello");
+- return TRUE;
++ return BUS_RESULT_TRUE;
+ }
+ else
+ {
+@@ -1575,7 +1598,7 @@ bus_context_check_security_policy (BusContext *context,
+ "Client tried to send a message other than %s without being registered",
+ "Hello");
+
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+ }
+ }
+@@ -1624,20 +1647,29 @@ bus_context_check_security_policy (BusContext *context,
+ (proposed_recipient == NULL && recipient_policy == NULL));
+
+ log = FALSE;
+- if (sender_policy &&
+- !bus_client_policy_check_can_send (sender_policy,
+- context->registry,
+- requested_reply,
+- proposed_recipient,
+- message, &toggles, &log))
+- {
+- complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+- "Rejected send message", toggles,
+- message, sender, proposed_recipient, requested_reply,
+- (addressed_recipient == proposed_recipient), error);
+- _dbus_verbose ("security policy disallowing message due to sender policy\n");
+- return FALSE;
+- }
++ if (sender_policy)
++ {
++ BusResult res = bus_client_policy_check_can_send (sender,
++ sender_policy,
++ context->registry,
++ requested_reply,
++ addressed_recipient,
++ proposed_recipient,
++ message, &toggles, &log, &privilege,
++ deferred_message);
++ if (res == BUS_RESULT_FALSE)
++ {
++ complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
++ "Rejected send message", toggles,
++ message, sender, proposed_recipient, requested_reply,
++ (addressed_recipient == proposed_recipient), privilege,
++ error);
++ _dbus_verbose ("security policy disallowing message due to sender policy\n");
++ return BUS_RESULT_FALSE;
++ }
++ else if (res == BUS_RESULT_LATER)
++ return BUS_RESULT_LATER;
++ }
+
+ if (log)
+ {
+@@ -1646,23 +1678,29 @@ bus_context_check_security_policy (BusContext *context,
+ complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+ "Would reject message", toggles,
+ message, sender, proposed_recipient, requested_reply,
+- TRUE, NULL);
++ TRUE, privilege, NULL);
+ }
+
+- if (recipient_policy &&
+- !bus_client_policy_check_can_receive (recipient_policy,
+- context->registry,
+- requested_reply,
+- sender,
+- addressed_recipient, proposed_recipient,
+- message, &toggles))
++ if (recipient_policy)
+ {
+- complain_about_message (context, DBUS_ERROR_ACCESS_DENIED,
+- "Rejected receive message", toggles,
+- message, sender, proposed_recipient, requested_reply,
+- (addressed_recipient == proposed_recipient), error);
+- _dbus_verbose ("security policy disallowing message due to recipient policy\n");
+- return FALSE;
++ BusResult res;
++ res = bus_client_policy_check_can_receive (recipient_policy,
++ context->registry,
++ requested_reply,
++ sender,
++ addressed_recipient, proposed_recipient,
++ message, &toggles, &privilege, deferred_message);
++ if (res == BUS_RESULT_FALSE)
++ {
++ complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected receive message",
++ toggles, message, sender, proposed_recipient, requested_reply,
++ (addressed_recipient == proposed_recipient), privilege, error);
++ _dbus_verbose(
++ "security policy disallowing message due to recipient policy\n");
++ return BUS_RESULT_FALSE;
++ }
++ else if (res == BUS_RESULT_LATER)
++ return BUS_RESULT_LATER;
+ }
+
+ /* See if limits on size have been exceeded */
+@@ -1672,10 +1710,10 @@ bus_context_check_security_policy (BusContext *context,
+ {
+ complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
+ "Rejected: destination has a full message queue",
+- 0, message, sender, proposed_recipient, requested_reply, TRUE,
++ 0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
+ error);
+ _dbus_verbose ("security policy disallowing message due to full message queue\n");
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ /* Record that we will allow a reply here in the future (don't
+@@ -1692,11 +1730,11 @@ bus_context_check_security_policy (BusContext *context,
+ message, error))
+ {
+ _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ _dbus_verbose ("security policy allowing message\n");
+- return TRUE;
++ return BUS_RESULT_TRUE;
+ }
+
+ void
+diff --git a/bus/bus.h b/bus/bus.h
+index dac6ea5..78084dd 100644
+--- a/bus/bus.h
++++ b/bus/bus.h
+@@ -30,19 +30,35 @@
+ #include <dbus/dbus-pipe.h>
+ #include <dbus/dbus-sysdeps.h>
+
+-typedef struct BusActivation BusActivation;
+-typedef struct BusConnections BusConnections;
+-typedef struct BusContext BusContext;
+-typedef struct BusPolicy BusPolicy;
+-typedef struct BusClientPolicy BusClientPolicy;
+-typedef struct BusPolicyRule BusPolicyRule;
+-typedef struct BusRegistry BusRegistry;
+-typedef struct BusSELinuxID BusSELinuxID;
+-typedef struct BusService BusService;
+-typedef struct BusOwner BusOwner;
+-typedef struct BusTransaction BusTransaction;
+-typedef struct BusMatchmaker BusMatchmaker;
+-typedef struct BusMatchRule BusMatchRule;
++typedef struct BusActivation BusActivation;
++typedef struct BusConnections BusConnections;
++typedef struct BusContext BusContext;
++typedef struct BusPolicy BusPolicy;
++typedef struct BusClientPolicy BusClientPolicy;
++typedef struct BusPolicyRule BusPolicyRule;
++typedef struct BusRegistry BusRegistry;
++typedef struct BusSELinuxID BusSELinuxID;
++typedef struct BusService BusService;
++typedef struct BusOwner BusOwner;
++typedef struct BusTransaction BusTransaction;
++typedef struct BusMatchmaker BusMatchmaker;
++typedef struct BusMatchRule BusMatchRule;
++typedef struct BusCheck BusCheck;
++typedef struct BusDeferredMessage BusDeferredMessage;
++typedef struct BusCynara BusCynara;
++
++/**
++ * BusResult is defined as a pointer to a dummy structure to allow detection of type mismatches.
++ * The disadvantage of such solution is that now BusResult variables cannot be used in switch
++ * statement.
++ * Additionally, BUS_RESULT_TRUE is defined as 0 instead of 1 to help detect type mismatches
++ * at runtime.
++ */
++typedef const struct BusResultStruct { int dummy; } *BusResult;
++
++static const BusResult BUS_RESULT_TRUE = (BusResult)0x0;
++static const BusResult BUS_RESULT_FALSE = (BusResult)0x1;
++static const BusResult BUS_RESULT_LATER = (BusResult)0x2;
+
+ typedef struct
+ {
+@@ -96,6 +112,7 @@ BusConnections* bus_context_get_connections (BusContext
+ BusActivation* bus_context_get_activation (BusContext *context);
+ BusMatchmaker* bus_context_get_matchmaker (BusContext *context);
+ DBusLoop* bus_context_get_loop (BusContext *context);
++BusCheck * bus_context_get_check (BusContext *context);
+ dbus_bool_t bus_context_allow_unix_user (BusContext *context,
+ unsigned long uid);
+ dbus_bool_t bus_context_allow_windows_user (BusContext *context,
+@@ -121,13 +138,14 @@ void bus_context_log (BusContext
+ DBusSystemLogSeverity severity,
+ const char *msg,
+ ...);
+-dbus_bool_t bus_context_check_security_policy (BusContext *context,
+- BusTransaction *transaction,
+- DBusConnection *sender,
+- DBusConnection *addressed_recipient,
+- DBusConnection *proposed_recipient,
+- DBusMessage *message,
+- DBusError *error);
+ void bus_context_check_all_watches (BusContext *context);
++BusResult bus_context_check_security_policy (BusContext *context,
++ BusTransaction *transaction,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusConnection *proposed_recipient,
++ DBusMessage *message,
++ DBusError *error,
++ BusDeferredMessage **deferred_message);
+
+ #endif /* BUS_BUS_H */
+diff --git a/bus/check.c b/bus/check.c
+new file mode 100644
+index 0000000..d2f418a
+--- /dev/null
++++ b/bus/check.c
+@@ -0,0 +1,215 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++/* check.c Bus security policy runtime check
++ *
++ * Copyright (C) 2014 Intel, Inc.
++ * Copyright (c) 2014 Samsung Electronics, Ltd.
++ *
++ * Licensed under the Academic Free License version 2.1
++ *
++ * 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
++ *
++ */
++
++#include <config.h>
++#include "check.h"
++#include "connection.h"
++#include "dispatch.h"
++#include "cynara.h"
++#include "utils.h"
++#include <dbus/dbus-connection-internal.h>
++#include <dbus/dbus-message-internal.h>
++#include <dbus/dbus-internals.h>
++
++
++typedef struct BusCheck
++{
++ int refcount;
++
++ BusContext *context;
++ BusCynara *cynara;
++} BusCheck;
++
++typedef struct BusDeferredMessage
++{
++ int refcount;
++
++ DBusMessage *message;
++ DBusConnection *sender;
++ DBusConnection *proposed_recipient;
++ DBusConnection *addressed_recipient;
++ dbus_bool_t full_dispatch;
++ BusDeferredMessageStatus status;
++ BusResult response;
++ BusCheckResponseFunc response_callback;
++} BusDeferredMessage;
++
++BusCheck *
++bus_check_new (BusContext *context, DBusError *error)
++{
++ BusCheck *check;
++
++ check = dbus_new(BusCheck, 1);
++ if (check == NULL)
++ {
++ BUS_SET_OOM(error);
++ return NULL;
++ }
++
++ check->refcount = 1;
++ check->context = context;
++ check->cynara = bus_cynara_new(check, error);
++ if (dbus_error_is_set(error))
++ {
++ dbus_free(check);
++ return NULL;
++ }
++
++ return check;
++}
++
++BusCheck *
++bus_check_ref (BusCheck *check)
++{
++ _dbus_assert (check->refcount > 0);
++ check->refcount += 1;
++
++ return check;
++}
++
++void
++bus_check_unref (BusCheck *check)
++{
++ _dbus_assert (check->refcount > 0);
++
++ check->refcount -= 1;
++
++ if (check->refcount == 0)
++ {
++ bus_cynara_unref(check->cynara);
++ dbus_free(check);
++ }
++}
++
++BusContext *
++bus_check_get_context (BusCheck *check)
++{
++ return check->context;
++}
++
++BusCynara *
++bus_check_get_cynara (BusCheck *check)
++{
++ return check->cynara;
++}
++
++BusResult
++bus_check_privilege (BusCheck *check,
++ DBusMessage *message,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusConnection *proposed_recipient,
++ const char *privilege,
++ BusDeferredMessageStatus check_type,
++ BusDeferredMessage **deferred_message)
++{
++ BusResult result = BUS_RESULT_FALSE;
++ BusCynara *cynara;
++ DBusConnection *connection;
++
++ connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
++
++ if (!dbus_connection_get_is_connected(connection))
++ {
++ return BUS_RESULT_FALSE;
++ }
++
++ /* ask policy checkers */
++#ifdef DBUS_ENABLE_CYNARA
++ cynara = bus_check_get_cynara(check);
++ result = bus_cynara_check_privilege(cynara, message, sender, addressed_recipient,
++ proposed_recipient, privilege, check_type, deferred_message);
++#endif
++
++ if (result == BUS_RESULT_LATER && deferred_message != NULL)
++ {
++ (*deferred_message)->status |= check_type;
++ }
++ return result;
++}
++
++BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusConnection *proposed_recipient,
++ BusResult response)
++{
++ BusDeferredMessage *deferred_message;
++
++ deferred_message = dbus_new(BusDeferredMessage, 1);
++ if (deferred_message == NULL)
++ {
++ return NULL;
++ }
++
++ deferred_message->refcount = 1;
++ deferred_message->sender = sender != NULL ? dbus_connection_ref(sender) : NULL;
++ deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
++ deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
++ deferred_message->message = dbus_message_ref(message);
++ deferred_message->response = response;
++ deferred_message->status = 0;
++ deferred_message->full_dispatch = FALSE;
++ deferred_message->response_callback = NULL;
++
++ return deferred_message;
++}
++
++BusDeferredMessage *
++bus_deferred_message_ref (BusDeferredMessage *deferred_message)
++{
++ _dbus_assert (deferred_message->refcount > 0);
++ deferred_message->refcount += 1;
++ return deferred_message;
++}
++
++void
++bus_deferred_message_unref (BusDeferredMessage *deferred_message)
++{
++ _dbus_assert (deferred_message->refcount > 0);
++
++ deferred_message->refcount -= 1;
++
++ if (deferred_message->refcount == 0)
++ {
++ dbus_message_unref(deferred_message->message);
++ if (deferred_message->sender != NULL)
++ dbus_connection_unref(deferred_message->sender);
++ if (deferred_message->addressed_recipient != NULL)
++ dbus_connection_unref(deferred_message->addressed_recipient);
++ if (deferred_message->proposed_recipient != NULL)
++ dbus_connection_unref(deferred_message->proposed_recipient);
++ dbus_free(deferred_message);
++ }
++}
++
++void
++bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
++ BusResult result)
++{
++ if (deferred_message->response_callback != NULL)
++ {
++ deferred_message->response_callback(deferred_message, result);
++ }
++}
+diff --git a/bus/check.h b/bus/check.h
+new file mode 100644
+index 0000000..c3fcaf9
+--- /dev/null
++++ b/bus/check.h
+@@ -0,0 +1,68 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++/* check.h Bus security policy runtime check
++ *
++ * Copyright (C) 2014 Intel, Inc.
++ * Copyright (c) 2014 Samsung Electronics, Ltd.
++ *
++ * Licensed under the Academic Free License version 2.1
++ *
++ * 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
++ *
++ */
++
++#ifndef BUS_CHECK_H
++#define BUS_CHECK_H
++
++#include "bus.h"
++#include "policy.h"
++
++
++typedef void (*BusCheckResponseFunc) (BusDeferredMessage *message,
++ BusResult result);
++
++typedef enum {
++ BUS_DEFERRED_MESSAGE_CHECK_SEND = 1 << 0,
++ BUS_DEFERRED_MESSAGE_CHECK_RECEIVE = 1 << 1,
++ BUS_DEFERRED_MESSAGE_CHECK_OWN = 1 << 2,
++} BusDeferredMessageStatus;
++
++
++BusCheck *bus_check_new (BusContext *context,
++ DBusError *error);
++BusCheck *bus_check_ref (BusCheck *check);
++void bus_check_unref (BusCheck *check);
++
++BusContext *bus_check_get_context (BusCheck *check);
++BusCynara *bus_check_get_cynara (BusCheck *check);
++BusResult bus_check_privilege (BusCheck *check,
++ DBusMessage *message,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusConnection *proposed_recipient,
++ const char *privilege,
++ BusDeferredMessageStatus check_type,
++ BusDeferredMessage **deferred_message);
++
++BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusConnection *proposed_recipient,
++ BusResult response);
++
++BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage *deferred_message);
++void bus_deferred_message_unref (BusDeferredMessage *deferred_message);
++void bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
++ BusResult result);
++#endif /* BUS_CHECK_H */
+diff --git a/bus/config-parser-common.c b/bus/config-parser-common.c
+index c522ff4..1cfe4c8 100644
+--- a/bus/config-parser-common.c
++++ b/bus/config-parser-common.c
+@@ -75,6 +75,10 @@ bus_config_parser_element_name_to_type (const char *name)
+ {
+ return ELEMENT_DENY;
+ }
++ else if (strcmp (name, "check") == 0)
++ {
++ return ELEMENT_CHECK;
++ }
+ else if (strcmp (name, "servicehelper") == 0)
+ {
+ return ELEMENT_SERVICEHELPER;
+@@ -155,6 +159,8 @@ bus_config_parser_element_type_to_name (ElementType type)
+ return "allow";
+ case ELEMENT_DENY:
+ return "deny";
++ case ELEMENT_CHECK:
++ return "check";
+ case ELEMENT_FORK:
+ return "fork";
+ case ELEMENT_PIDFILE:
+diff --git a/bus/config-parser-common.h b/bus/config-parser-common.h
+index 186bf4c..bff6fdb 100644
+--- a/bus/config-parser-common.h
++++ b/bus/config-parser-common.h
+@@ -36,6 +36,7 @@ typedef enum
+ ELEMENT_LIMIT,
+ ELEMENT_ALLOW,
+ ELEMENT_DENY,
++ ELEMENT_CHECK,
+ ELEMENT_FORK,
+ ELEMENT_PIDFILE,
+ ELEMENT_SERVICEDIR,
+diff --git a/bus/config-parser.c b/bus/config-parser.c
+index ee2d4e7..73c9e6f 100644
+--- a/bus/config-parser.c
++++ b/bus/config-parser.c
+@@ -1150,7 +1150,7 @@ append_rule_from_element (BusConfigParser *parser,
+ const char *element_name,
+ const char **attribute_names,
+ const char **attribute_values,
+- dbus_bool_t allow,
++ BusPolicyRuleAccess access,
+ DBusError *error)
+ {
+ const char *log;
+@@ -1173,6 +1173,7 @@ append_rule_from_element (BusConfigParser *parser,
+ const char *own_prefix;
+ const char *user;
+ const char *group;
++ const char *privilege;
+
+ BusPolicyRule *rule;
+
+@@ -1200,6 +1201,7 @@ append_rule_from_element (BusConfigParser *parser,
+ "user", &user,
+ "group", &group,
+ "log", &log,
++ "privilege", &privilege,
+ NULL))
+ return FALSE;
+
+@@ -1208,6 +1210,7 @@ append_rule_from_element (BusConfigParser *parser,
+ receive_interface || receive_member || receive_error || receive_sender ||
+ receive_type || receive_path || eavesdrop ||
+ send_requested_reply || receive_requested_reply ||
++ privilege ||
+ own || own_prefix || user || group))
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+@@ -1224,7 +1227,30 @@ append_rule_from_element (BusConfigParser *parser,
+ element_name);
+ return FALSE;
+ }
+-
++
++ if (access == BUS_POLICY_RULE_ACCESS_CHECK)
++ {
++ if (privilege == NULL || !*privilege)
++ {
++ dbus_set_error (error, DBUS_ERROR_FAILED,
++ "On element <%s>, you must specify the privilege to be checked.",
++ element_name);
++ return FALSE;
++ }
++ }
++ else
++ {
++ if (privilege != NULL && *privilege)
++ {
++ dbus_set_error (error, DBUS_ERROR_FAILED,
++ "On element <%s>, privilege %s is used outside of a check rule.",
++ element_name, privilege);
++ return FALSE;
++ }
++ else
++ privilege = NULL; /* replace (potentially) empty string with NULL pointer, it wouldn't be used anyway */
++ }
++
+ /* Allowed combinations of elements are:
+ *
+ * base, must be all send or all receive:
+@@ -1398,7 +1424,7 @@ append_rule_from_element (BusConfigParser *parser,
+ return FALSE;
+ }
+
+- rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, allow);
++ rule = bus_policy_rule_new (BUS_POLICY_RULE_SEND, access);
+ if (rule == NULL)
+ goto nomem;
+
+@@ -1480,7 +1506,7 @@ append_rule_from_element (BusConfigParser *parser,
+ return FALSE;
+ }
+
+- rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, allow);
++ rule = bus_policy_rule_new (BUS_POLICY_RULE_RECEIVE, access);
+ if (rule == NULL)
+ goto nomem;
+
+@@ -1510,7 +1536,7 @@ append_rule_from_element (BusConfigParser *parser,
+ }
+ else if (own || own_prefix)
+ {
+- rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, allow);
++ rule = bus_policy_rule_new (BUS_POLICY_RULE_OWN, access);
+ if (rule == NULL)
+ goto nomem;
+
+@@ -1536,7 +1562,7 @@ append_rule_from_element (BusConfigParser *parser,
+ {
+ if (IS_WILDCARD (user))
+ {
+- rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
++ rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
+ if (rule == NULL)
+ goto nomem;
+
+@@ -1551,7 +1577,7 @@ append_rule_from_element (BusConfigParser *parser,
+
+ if (_dbus_parse_unix_user_from_config (&username, &uid))
+ {
+- rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, allow);
++ rule = bus_policy_rule_new (BUS_POLICY_RULE_USER, access);
+ if (rule == NULL)
+ goto nomem;
+
+@@ -1568,7 +1594,7 @@ append_rule_from_element (BusConfigParser *parser,
+ {
+ if (IS_WILDCARD (group))
+ {
+- rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
++ rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
+ if (rule == NULL)
+ goto nomem;
+
+@@ -1583,7 +1609,7 @@ append_rule_from_element (BusConfigParser *parser,
+
+ if (_dbus_parse_unix_group_from_config (&groupname, &gid))
+ {
+- rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, allow);
++ rule = bus_policy_rule_new (BUS_POLICY_RULE_GROUP, access);
+ if (rule == NULL)
+ goto nomem;
+
+@@ -1607,6 +1633,10 @@ append_rule_from_element (BusConfigParser *parser,
+ _dbus_assert (pe != NULL);
+ _dbus_assert (pe->type == ELEMENT_POLICY);
+
++ rule->privilege = _dbus_strdup (privilege);
++ if (privilege && !rule->privilege)
++ goto nomem;
++
+ switch (pe->d.policy.type)
+ {
+ case POLICY_IGNORED:
+@@ -1681,7 +1711,7 @@ start_policy_child (BusConfigParser *parser,
+ {
+ if (!append_rule_from_element (parser, element_name,
+ attribute_names, attribute_values,
+- TRUE, error))
++ BUS_POLICY_RULE_ACCESS_ALLOW, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_ALLOW) == NULL)
+@@ -1696,7 +1726,7 @@ start_policy_child (BusConfigParser *parser,
+ {
+ if (!append_rule_from_element (parser, element_name,
+ attribute_names, attribute_values,
+- FALSE, error))
++ BUS_POLICY_RULE_ACCESS_DENY, error))
+ return FALSE;
+
+ if (push_element (parser, ELEMENT_DENY) == NULL)
+@@ -1707,6 +1737,21 @@ start_policy_child (BusConfigParser *parser,
+
+ return TRUE;
+ }
++ else if (strcmp (element_name, "check") == 0)
++ {
++ if (!append_rule_from_element (parser, element_name,
++ attribute_names, attribute_values,
++ BUS_POLICY_RULE_ACCESS_CHECK, error))
++ return FALSE;
++
++ if (push_element (parser, ELEMENT_CHECK) == NULL)
++ {
++ BUS_SET_OOM (error);
++ return FALSE;
++ }
++
++ return TRUE;
++ }
+ else
+ {
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+@@ -2066,6 +2111,7 @@ bus_config_parser_end_element (BusConfigParser *parser,
+ case ELEMENT_POLICY:
+ case ELEMENT_ALLOW:
+ case ELEMENT_DENY:
++ case ELEMENT_CHECK:
+ case ELEMENT_FORK:
+ case ELEMENT_SYSLOG:
+ case ELEMENT_KEEP_UMASK:
+@@ -2365,6 +2411,7 @@ bus_config_parser_content (BusConfigParser *parser,
+ case ELEMENT_POLICY:
+ case ELEMENT_ALLOW:
+ case ELEMENT_DENY:
++ case ELEMENT_CHECK:
+ case ELEMENT_FORK:
+ case ELEMENT_SYSLOG:
+ case ELEMENT_KEEP_UMASK:
+@@ -2829,6 +2876,8 @@ do_load (const DBusString *full_path,
+ dbus_error_init (&error);
+
+ parser = bus_config_load (full_path, TRUE, NULL, &error);
++ if (dbus_error_is_set (&error))
++ _dbus_verbose ("Failed to load file: %s\n", error.message);
+ if (parser == NULL)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (&error);
+diff --git a/bus/connection.c b/bus/connection.c
+index 7107434..a6d87e5 100644
+--- a/bus/connection.c
++++ b/bus/connection.c
+@@ -34,6 +34,10 @@
+ #include <dbus/dbus-hash.h>
+ #include <dbus/dbus-timeout.h>
+ #include <dbus/dbus-connection-internal.h>
++#ifdef DBUS_ENABLE_CYNARA
++#include <stdlib.h>
++#include <cynara-session.h>
++#endif
+
+ /* Trim executed commands to this length; we want to keep logs readable */
+ #define MAX_LOG_COMMAND_LEN 50
+@@ -105,6 +109,9 @@ typedef struct
+ #endif
+ int n_pending_unix_fds;
+ DBusTimeout *pending_unix_fds_timeout;
++#ifdef DBUS_ENABLE_CYNARA
++ char *cynara_session_id;
++#endif
+ } BusConnectionData;
+
+ static dbus_bool_t bus_pending_reply_expired (BusExpireList *list,
+@@ -118,8 +125,8 @@ static dbus_bool_t expire_incomplete_timeout (void *data);
+
+ #define BUS_CONNECTION_DATA(connection) (dbus_connection_get_data ((connection), connection_data_slot))
+
+-static DBusLoop*
+-connection_get_loop (DBusConnection *connection)
++DBusLoop*
++bus_connection_get_loop (DBusConnection *connection)
+ {
+ BusConnectionData *d;
+
+@@ -331,7 +338,7 @@ add_connection_watch (DBusWatch *watch,
+ {
+ DBusConnection *connection = data;
+
+- return _dbus_loop_add_watch (connection_get_loop (connection), watch);
++ return _dbus_loop_add_watch (bus_connection_get_loop (connection), watch);
+ }
+
+ static void
+@@ -340,7 +347,7 @@ remove_connection_watch (DBusWatch *watch,
+ {
+ DBusConnection *connection = data;
+
+- _dbus_loop_remove_watch (connection_get_loop (connection), watch);
++ _dbus_loop_remove_watch (bus_connection_get_loop (connection), watch);
+ }
+
+ static void
+@@ -349,7 +356,7 @@ toggle_connection_watch (DBusWatch *watch,
+ {
+ DBusConnection *connection = data;
+
+- _dbus_loop_toggle_watch (connection_get_loop (connection), watch);
++ _dbus_loop_toggle_watch (bus_connection_get_loop (connection), watch);
+ }
+
+ static dbus_bool_t
+@@ -358,7 +365,7 @@ add_connection_timeout (DBusTimeout *timeout,
+ {
+ DBusConnection *connection = data;
+
+- return _dbus_loop_add_timeout (connection_get_loop (connection), timeout);
++ return _dbus_loop_add_timeout (bus_connection_get_loop (connection), timeout);
+ }
+
+ static void
+@@ -367,7 +374,7 @@ remove_connection_timeout (DBusTimeout *timeout,
+ {
+ DBusConnection *connection = data;
+
+- _dbus_loop_remove_timeout (connection_get_loop (connection), timeout);
++ _dbus_loop_remove_timeout (bus_connection_get_loop (connection), timeout);
+ }
+
+ static void
+@@ -425,6 +432,10 @@ free_connection_data (void *data)
+
+ dbus_free (d->name);
+
++#ifdef DBUS_ENABLE_CYNARA
++ free (d->cynara_session_id);
++#endif
++
+ dbus_free (d);
+ }
+
+@@ -984,6 +995,22 @@ bus_connection_get_policy (DBusConnection *connection)
+ return d->policy;
+ }
+
++#ifdef DBUS_ENABLE_CYNARA
++const char *bus_connection_get_cynara_session_id (DBusConnection *connection)
++{
++ BusConnectionData *d = BUS_CONNECTION_DATA (connection);
++ _dbus_assert (d != NULL);
++
++ if (d->cynara_session_id == NULL)
++ {
++ unsigned long pid;
++ if (dbus_connection_get_unix_process_id(connection, &pid))
++ d->cynara_session_id = cynara_session_from_pid(pid);
++ }
++ return d->cynara_session_id;
++}
++#endif
++
+ static dbus_bool_t
+ foreach_active (BusConnections *connections,
+ BusConnectionForeachFunction function,
+@@ -2104,6 +2131,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
+ DBusConnection *connection,
+ DBusMessage *message)
+ {
++ BusResult res;
+ /* We have to set the sender to the driver, and have
+ * to check security policy since it was not done in
+ * dispatch.c
+@@ -2132,10 +2160,18 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
+ /* If security policy doesn't allow the message, we silently
+ * eat it; the driver doesn't care about getting a reply.
+ */
+- if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
+- transaction,
+- NULL, connection, connection, message, NULL))
++ res = bus_context_check_security_policy (bus_transaction_get_context (transaction),
++ transaction,
++ NULL, connection, connection, message, NULL,
++ NULL);
++
++ if (res == BUS_RESULT_FALSE)
+ return TRUE;
++ else if (res == BUS_RESULT_LATER)
++ {
++ _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
++ return TRUE;
++ }
+
+ return bus_transaction_send (transaction, connection, message);
+ }
+diff --git a/bus/connection.h b/bus/connection.h
+index 6fbcd38..7433746 100644
+--- a/bus/connection.h
++++ b/bus/connection.h
+@@ -31,6 +31,7 @@
+ typedef dbus_bool_t (* BusConnectionForeachFunction) (DBusConnection *connection,
+ void *data);
+
++DBusLoop* bus_connection_get_loop (DBusConnection *connection);
+
+ BusConnections* bus_connections_new (BusContext *context);
+ BusConnections* bus_connections_ref (BusConnections *connections);
+@@ -116,6 +117,10 @@ dbus_bool_t bus_connection_get_unix_groups (DBusConnection *connecti
+ DBusError *error);
+ BusClientPolicy* bus_connection_get_policy (DBusConnection *connection);
+
++#ifdef DBUS_ENABLE_CYNARA
++const char *bus_connection_get_cynara_session_id (DBusConnection *connection);
++#endif
++
+ /* transaction API so we can send or not send a block of messages as a whole */
+
+ typedef void (* BusTransactionCancelFunction) (void *data);
+diff --git a/bus/cynara.c b/bus/cynara.c
+new file mode 100644
+index 0000000..57a4c45
+--- /dev/null
++++ b/bus/cynara.c
+@@ -0,0 +1,374 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++/* cynara.c Cynara runtime privilege checking
++ *
++ * Copyright (c) 2014 Samsung Electronics, Ltd.
++ *
++ * Licensed under the Academic Free License version 2.1
++ *
++ * 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
++ *
++ */
++
++#include <config.h>
++#include "cynara.h"
++#include "check.h"
++#include "utils.h"
++
++#include <stdio.h>
++
++#include <dbus/dbus.h>
++#include <dbus/dbus-watch.h>
++#include <dbus/dbus-connection-internal.h>
++#include <bus/connection.h>
++#ifdef DBUS_ENABLE_CYNARA
++#include <cynara-client-async.h>
++#endif
++
++
++#ifdef DBUS_ENABLE_CYNARA
++typedef struct BusCynara
++{
++ int refcount;
++
++ BusContext *context;
++ BusCheck *check;
++ cynara_async *cynara;
++ DBusWatch *cynara_watch;
++} BusCynara;
++
++#define USE_CYNARA_CACHE 1
++#ifdef USE_CYNARA_CACHE
++#define CYNARA_CACHE_SIZE 1000
++#endif
++
++static dbus_bool_t bus_cynara_watch_callback(DBusWatch *watch,
++ unsigned int flags,
++ void *data);
++
++static void status_callback(int old_fd,
++ int new_fd,
++ cynara_async_status status,
++ void *user_status_data);
++static void bus_cynara_check_response_callback (cynara_check_id check_id,
++ cynara_async_call_cause cause,
++ int response,
++ void *user_response_data);
++#endif
++
++
++BusCynara *
++bus_cynara_new(BusCheck *check, DBusError *error)
++{
++#ifdef DBUS_ENABLE_CYNARA
++ BusContext *context;
++ BusCynara *cynara;
++ cynara_async_configuration *conf = NULL;
++ int ret;
++
++ cynara = dbus_new(BusCynara, 1);
++ if (cynara == NULL)
++ {
++ BUS_SET_OOM(error);
++ return NULL;
++ }
++
++ context = bus_check_get_context(check);
++
++ cynara->refcount = 1;
++ cynara->check = check;
++ cynara->context = context;
++ cynara->cynara_watch = NULL;
++
++ ret = cynara_async_configuration_create(&conf);
++ if (ret != CYNARA_API_SUCCESS)
++ {
++ dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to create Cynara configuration");
++ goto out;
++ }
++
++#ifdef CYNARA_CACHE_SIZE
++ ret = cynara_async_configuration_set_cache_size(conf, CYNARA_CACHE_SIZE);
++ if (ret != CYNARA_API_SUCCESS)
++ {
++ dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to Cynara cache size");
++ goto out;
++ }
++#endif
++
++ ret = cynara_async_initialize(&cynara->cynara, conf, &status_callback, cynara);
++ if (ret != CYNARA_API_SUCCESS)
++ {
++ dbus_set_error (error, DBUS_ERROR_FAILED, "Failed to initialize Cynara client");
++ goto out;
++ }
++
++out:
++ cynara_async_configuration_destroy(conf);
++ if (ret != CYNARA_API_SUCCESS)
++ {
++ dbus_free(cynara);
++ return NULL;
++ }
++
++ return cynara;
++#else
++ return NULL;
++#endif
++}
++
++BusCynara *
++bus_cynara_ref (BusCynara *cynara)
++{
++#ifdef DBUS_ENABLE_CYNARA
++ _dbus_assert (cynara->refcount > 0);
++ cynara->refcount += 1;
++
++ return cynara;
++#else
++ return NULL;
++#endif
++}
++
++void
++bus_cynara_unref (BusCynara *cynara)
++{
++#ifdef DBUS_ENABLE_CYNARA
++ _dbus_assert (cynara->refcount > 0);
++
++ cynara->refcount -= 1;
++
++ if (cynara->refcount == 0)
++ {
++ cynara_async_finish(cynara->cynara);
++ dbus_free(cynara);
++ }
++#endif
++}
++
++BusResult
++bus_cynara_check_privilege (BusCynara *cynara,
++ DBusMessage *message,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusConnection *proposed_recipient,
++ const char *privilege,
++ BusDeferredMessageStatus check_type,
++ BusDeferredMessage **deferred_message_param)
++{
++#ifdef DBUS_ENABLE_CYNARA
++ int result;
++ unsigned long uid;
++ char *label;
++ const char *session_id;
++ char user[32];
++ cynara_check_id check_id;
++ DBusConnection *connection = check_type == BUS_DEFERRED_MESSAGE_CHECK_RECEIVE ? proposed_recipient : sender;
++ BusDeferredMessage *deferred_message;
++ BusResult ret;
++
++ _dbus_assert(connection != NULL);
++
++ if (dbus_connection_get_unix_user(connection, &uid) == FALSE)
++ return BUS_RESULT_FALSE;
++
++ if (_dbus_connection_get_linux_security_label(connection, &label) == FALSE || label == NULL)
++ {
++ _dbus_warn("Failed to obtain security label for connection\n");
++ return BUS_RESULT_FALSE;
++ }
++
++ session_id = bus_connection_get_cynara_session_id (connection);
++ if (session_id == NULL)
++ {
++ ret = BUS_RESULT_FALSE;
++ goto out;
++ }
++
++ snprintf(user, sizeof(user), "%lu", uid);
++
++#if USE_CYNARA_CACHE
++ result = cynara_async_check_cache(cynara->cynara, label, session_id, user, privilege);
++#else
++ result = CYNARA_API_CACHE_MISS;
++#endif
++
++ switch (result)
++ {
++ case CYNARA_API_ACCESS_ALLOWED:
++ _dbus_verbose("Cynara: got ALLOWED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n",
++ label, session_id, user, privilege);
++ ret = BUS_RESULT_TRUE;
++ break;
++
++ case CYNARA_API_ACCESS_DENIED:
++ _dbus_verbose("Cynara: got DENIED answer from cache (client=%s session_id=%s user=%s privilege=%s)\n",
++ label, session_id, user, privilege);
++ ret = BUS_RESULT_FALSE;
++ break;
++
++ case CYNARA_API_CACHE_MISS:
++ deferred_message = bus_deferred_message_new(message, sender, addressed_recipient,
++ proposed_recipient, BUS_RESULT_LATER);
++ if (deferred_message == NULL)
++ {
++ _dbus_verbose("Failed to allocate memory for deferred message\n");
++ ret = BUS_RESULT_FALSE;
++ goto out;
++ }
++
++ /* callback is supposed to unref deferred_message*/
++ result = cynara_async_create_request(cynara->cynara, label, session_id, user, privilege, &check_id,
++ &bus_cynara_check_response_callback, deferred_message);
++ if (result == CYNARA_API_SUCCESS)
++ {
++ _dbus_verbose("Created Cynara request: client=%s session_id=%s user=%s privilege=%s check_id=%u "
++ "deferred_message=%p\n", label, session_id, user, privilege, (unsigned int)check_id, deferred_message);
++ if (deferred_message_param != NULL)
++ *deferred_message_param = deferred_message;
++ ret = BUS_RESULT_LATER;
++ }
++ else
++ {
++ _dbus_verbose("Error on cynara request create: %i\n", result);
++ bus_deferred_message_unref(deferred_message);
++ ret = BUS_RESULT_FALSE;
++ }
++ break;
++ default:
++ _dbus_verbose("Error when accessing Cynara cache: %i\n", result);
++ ret = BUS_RESULT_FALSE;
++ }
++out:
++ dbus_free(label);
++ return ret;
++
++#else
++ return BUS_RESULT_FALSE;
++#endif
++}
++
++
++
++#ifdef DBUS_ENABLE_CYNARA
++static void
++status_callback(int old_fd, int new_fd, cynara_async_status status,
++ void *user_status_data)
++{
++ BusCynara *cynara = (BusCynara *)user_status_data;
++ DBusLoop *loop = bus_context_get_loop(cynara->context);
++
++ if (cynara->cynara_watch != NULL)
++ {
++ _dbus_loop_remove_watch(loop, cynara->cynara_watch);
++ _dbus_watch_invalidate(cynara->cynara_watch);
++ _dbus_watch_unref(cynara->cynara_watch);
++ cynara->cynara_watch = NULL;
++ }
++
++ if (new_fd != -1)
++ {
++ unsigned int flags;
++ DBusWatch *watch;
++
++ switch (status)
++ {
++ case CYNARA_STATUS_FOR_READ:
++ flags = DBUS_WATCH_READABLE;
++ break;
++ case CYNARA_STATUS_FOR_RW:
++ flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
++ break;
++ default:
++ /* Cynara passed unknown status - warn and add RW watch */
++ _dbus_verbose("Cynara passed unknown status value: 0x%08X\n", (unsigned int)status);
++ flags = DBUS_WATCH_READABLE | DBUS_WATCH_WRITABLE;
++ break;
++ }
++
++ watch = _dbus_watch_new(new_fd, flags, TRUE, &bus_cynara_watch_callback, cynara, NULL);
++ if (watch != NULL)
++ {
++ if (_dbus_loop_add_watch(loop, watch) == TRUE)
++ {
++ cynara->cynara_watch = watch;
++ return;
++ }
++
++ _dbus_watch_invalidate(watch);
++ _dbus_watch_unref(watch);
++ }
++
++ /* It seems like not much can be done at this point. Cynara events won't be processed
++ * until next Cynara function call triggering status callback */
++ _dbus_verbose("Failed to add dbus watch\n");
++ }
++}
++
++static dbus_bool_t
++bus_cynara_watch_callback(DBusWatch *watch,
++ unsigned int flags,
++ void *data)
++{
++ BusCynara *cynara = (BusCynara *)data;
++ int result = cynara_async_process(cynara->cynara);
++ if (result != CYNARA_API_SUCCESS)
++ _dbus_verbose("cynara_async_process returned %d\n", result);
++
++ return result != CYNARA_API_OUT_OF_MEMORY ? TRUE : FALSE;
++}
++
++static inline const char *
++call_cause_to_string(cynara_async_call_cause cause)
++{
++ switch (cause)
++ {
++ case CYNARA_CALL_CAUSE_ANSWER:
++ return "ANSWER";
++ case CYNARA_CALL_CAUSE_CANCEL:
++ return "CANCEL";
++ case CYNARA_CALL_CAUSE_FINISH:
++ return "FINSIH";
++ case CYNARA_CALL_CAUSE_SERVICE_NOT_AVAILABLE:
++ return "SERVICE NOT AVAILABLE";
++ default:
++ return "INVALID";
++ }
++}
++
++static void
++bus_cynara_check_response_callback (cynara_check_id check_id,
++ cynara_async_call_cause cause,
++ int response,
++ void *user_response_data)
++{
++ BusDeferredMessage *deferred_message = user_response_data;
++ BusResult result;
++
++ _dbus_verbose("Cynara callback: check_id=%u, cause=%s response=%i response_data=%p\n",
++ (unsigned int)check_id, call_cause_to_string(cause), response, user_response_data);
++
++ if (deferred_message == NULL)
++ return;
++
++ if (cause == CYNARA_CALL_CAUSE_ANSWER && response == CYNARA_API_ACCESS_ALLOWED)
++ result = BUS_RESULT_TRUE;
++ else
++ result = BUS_RESULT_FALSE;
++
++ bus_deferred_message_response_received(deferred_message, result);
++ bus_deferred_message_unref(deferred_message);
++}
++
++#endif /* DBUS_ENABLE_CYNARA */
+diff --git a/bus/cynara.h b/bus/cynara.h
+new file mode 100644
+index 0000000..c4728bb
+--- /dev/null
++++ b/bus/cynara.h
+@@ -0,0 +1,37 @@
++/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
++/* cynara.h Cynara runtime privilege checking
++ *
++ * Copyright (c) 2014 Samsung Electronics, Ltd.
++ *
++ * Licensed under the Academic Free License version 2.1
++ *
++ * 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
++ *
++ */
++
++#include "bus.h"
++#include "check.h"
++
++BusCynara *bus_cynara_new (BusCheck *check, DBusError *error);
++BusCynara *bus_cynara_ref (BusCynara *cynara);
++void bus_cynara_unref (BusCynara *cynara);
++BusResult bus_cynara_check_privilege (BusCynara *cynara,
++ DBusMessage *message,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusConnection *proposed_recipient,
++ const char *privilege,
++ BusDeferredMessageStatus check_type,
++ BusDeferredMessage **deferred_message);
+diff --git a/bus/dispatch.c b/bus/dispatch.c
+index 7a61953..ce4076d 100644
+--- a/bus/dispatch.c
++++ b/bus/dispatch.c
+@@ -25,6 +25,7 @@
+
+ #include <config.h>
+ #include "dispatch.h"
++#include "check.h"
+ #include "connection.h"
+ #include "driver.h"
+ #include "services.h"
+@@ -56,13 +57,14 @@ send_one_message (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusError *error)
+ {
+- if (!bus_context_check_security_policy (context, transaction,
+- sender,
+- addressed_recipient,
+- connection,
+- message,
+- NULL))
+- return TRUE; /* silently don't send it */
++ BusDeferredMessage *deferred_message;
++ BusResult result;
++
++ result = bus_context_check_security_policy (context, transaction, sender, addressed_recipient,
++ connection, message, NULL, &deferred_message);
++
++ if (result != BUS_RESULT_TRUE)
++ return TRUE; /* silently don't send it */
+
+ if (dbus_message_contains_unix_fds(message) &&
+ !dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD))
+@@ -92,6 +94,7 @@ bus_dispatch_matches (BusTransaction *transaction,
+ BusMatchmaker *matchmaker;
+ DBusList *link;
+ BusContext *context;
++ BusDeferredMessage *deferred_message;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+@@ -107,11 +110,21 @@ bus_dispatch_matches (BusTransaction *transaction,
+ /* First, send the message to the addressed_recipient, if there is one. */
+ if (addressed_recipient != NULL)
+ {
+- if (!bus_context_check_security_policy (context, transaction,
+- sender, addressed_recipient,
+- addressed_recipient,
+- message, error))
++ BusResult res;
++ res = bus_context_check_security_policy (context, transaction,
++ sender, addressed_recipient,
++ addressed_recipient,
++ message, error,
++ &deferred_message);
++ if (res == BUS_RESULT_FALSE)
+ return FALSE;
++ else if (res == BUS_RESULT_LATER)
++ {
++ dbus_set_error (error,
++ DBUS_ERROR_ACCESS_DENIED,
++ "Rejecting message because time is needed to check security policy");
++ return FALSE;
++ }
+
+ if (dbus_message_contains_unix_fds (message) &&
+ !dbus_connection_can_send_type (addressed_recipient,
+@@ -273,12 +286,24 @@ bus_dispatch (DBusConnection *connection,
+ if (service_name &&
+ strcmp (service_name, DBUS_SERVICE_DBUS) == 0) /* to bus driver */
+ {
+- if (!bus_context_check_security_policy (context, transaction,
+- connection, NULL, NULL, message, &error))
++ BusDeferredMessage *deferred_message;
++ BusResult res;
++ res = bus_context_check_security_policy (context, transaction,
++ connection, NULL, NULL, message, &error,
++ &deferred_message);
++ if (res == BUS_RESULT_FALSE)
+ {
+ _dbus_verbose ("Security policy rejected message\n");
+ goto out;
+ }
++ else if (res == BUS_RESULT_LATER)
++ {
++ dbus_set_error (&error,
++ DBUS_ERROR_ACCESS_DENIED,
++ "Rejecting message because time is needed to check security policy");
++ _dbus_verbose ("Security policy needs time to check policy. Dropping message\n");
++ goto out;
++ }
+
+ _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS);
+ if (!bus_driver_handle_message (connection, transaction, message, &error))
+diff --git a/bus/policy.c b/bus/policy.c
+index 082f385..ec888df 100644
+--- a/bus/policy.c
++++ b/bus/policy.c
+@@ -22,6 +22,7 @@
+ */
+
+ #include <config.h>
++#include "check.h"
+ #include "policy.h"
+ #include "services.h"
+ #include "test.h"
+@@ -32,7 +33,7 @@
+
+ BusPolicyRule*
+ bus_policy_rule_new (BusPolicyRuleType type,
+- dbus_bool_t allow)
++ BusPolicyRuleAccess access)
+ {
+ BusPolicyRule *rule;
+
+@@ -42,7 +43,7 @@ bus_policy_rule_new (BusPolicyRuleType type,
+
+ rule->type = type;
+ rule->refcount = 1;
+- rule->allow = allow;
++ rule->access = access;
+
+ switch (rule->type)
+ {
+@@ -54,18 +55,19 @@ bus_policy_rule_new (BusPolicyRuleType type,
+ break;
+ case BUS_POLICY_RULE_SEND:
+ rule->d.send.message_type = DBUS_MESSAGE_TYPE_INVALID;
+-
+ /* allow rules default to TRUE (only requested replies allowed)
++ * check rules default to TRUE (only requested replies are checked)
+ * deny rules default to FALSE (only unrequested replies denied)
+ */
+- rule->d.send.requested_reply = rule->allow;
++ rule->d.send.requested_reply = rule->access != BUS_POLICY_RULE_ACCESS_DENY;
+ break;
+ case BUS_POLICY_RULE_RECEIVE:
+ rule->d.receive.message_type = DBUS_MESSAGE_TYPE_INVALID;
+ /* allow rules default to TRUE (only requested replies allowed)
++ * check rules default to TRUE (only requested replies are checked)
+ * deny rules default to FALSE (only unrequested replies denied)
+ */
+- rule->d.receive.requested_reply = rule->allow;
++ rule->d.receive.requested_reply = rule->access != BUS_POLICY_RULE_ACCESS_DENY;
+ break;
+ case BUS_POLICY_RULE_OWN:
+ break;
+@@ -117,7 +119,8 @@ bus_policy_rule_unref (BusPolicyRule *rule)
+ case BUS_POLICY_RULE_GROUP:
+ break;
+ }
+-
++
++ dbus_free (rule->privilege);
+ dbus_free (rule);
+ }
+ }
+@@ -427,7 +430,10 @@ list_allows_user (dbus_bool_t def,
+ else
+ continue;
+
+- allowed = rule->allow;
++ /* We don't intend to support <check user="..." /> and <check group="..." />
++ rules. They are treated like deny.
++ */
++ allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
+ }
+
+ return allowed;
+@@ -862,18 +868,23 @@ bus_client_policy_append_rule (BusClientPolicy *policy,
+ return TRUE;
+ }
+
+-dbus_bool_t
+-bus_client_policy_check_can_send (BusClientPolicy *policy,
+- BusRegistry *registry,
+- dbus_bool_t requested_reply,
+- DBusConnection *receiver,
+- DBusMessage *message,
+- dbus_int32_t *toggles,
+- dbus_bool_t *log)
++BusResult
++bus_client_policy_check_can_send (DBusConnection *sender,
++ BusClientPolicy *policy,
++ BusRegistry *registry,
++ dbus_bool_t requested_reply,
++ DBusConnection *addressed_recipient,
++ DBusConnection *receiver,
++ DBusMessage *message,
++ dbus_int32_t *toggles,
++ dbus_bool_t *log,
++ const char **privilege_param,
++ BusDeferredMessage **deferred_message)
+ {
+ DBusList *link;
+- dbus_bool_t allowed;
+-
++ BusResult result;
++ const char *privilege;
++
+ /* policy->rules is in the order the rules appeared
+ * in the config file, i.e. last rule that applies wins
+ */
+@@ -881,7 +892,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
+ _dbus_verbose (" (policy) checking send rules\n");
+ *toggles = 0;
+
+- allowed = FALSE;
++ result = BUS_RESULT_FALSE;
+ link = _dbus_list_get_first_link (&policy->rules);
+ while (link != NULL)
+ {
+@@ -912,13 +923,14 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
+ /* If it's a reply, the requested_reply flag kicks in */
+ if (dbus_message_get_reply_serial (message) != 0)
+ {
+- /* for allow, requested_reply=true means the rule applies
+- * only when reply was requested. requested_reply=false means
+- * always allow.
++ /* for allow or check requested_reply=true means the rule applies
++ * only when reply was requested. requested_reply=false means the
++ * rule always applies
+ */
+- if (!requested_reply && rule->allow && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
++ if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
+ {
+- _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n");
++ _dbus_verbose (" (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n",
++ rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
+ continue;
+ }
+
+@@ -926,7 +938,7 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
+ * when the reply was not requested. requested_reply=true means the
+ * rule always applies.
+ */
+- if (requested_reply && !rule->allow && !rule->d.send.requested_reply)
++ if (requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.send.requested_reply)
+ {
+ _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n");
+ continue;
+@@ -949,13 +961,15 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
+ /* The interface is optional in messages. For allow rules, if the message
+ * has no interface we want to skip the rule (and thus not allow);
+ * for deny rules, if the message has no interface we want to use the
+- * rule (and thus deny).
++ * rule (and thus deny). Check rules are meant to be used like allow
++ * rules (they can grant access, but not remove it), so we treat it like
++ * allow here.
+ */
+ dbus_bool_t no_interface;
+
+ no_interface = dbus_message_get_interface (message) == NULL;
+
+- if ((no_interface && rule->allow) ||
++ if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
+ (!no_interface &&
+ strcmp (dbus_message_get_interface (message),
+ rule->d.send.interface) != 0))
+@@ -1029,33 +1043,63 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
+ }
+
+ /* Use this rule */
+- allowed = rule->allow;
++ switch (rule->access)
++ {
++ case BUS_POLICY_RULE_ACCESS_ALLOW:
++ result = BUS_RESULT_TRUE;
++ break;
++ case BUS_POLICY_RULE_ACCESS_DENY:
++ result = BUS_RESULT_FALSE;
++ break;
++ case BUS_POLICY_RULE_ACCESS_CHECK:
++ result = BUS_RESULT_LATER;
++ privilege = rule->privilege;
++ break;
++ }
++
+ *log = rule->d.send.log;
+ (*toggles)++;
+
+- _dbus_verbose (" (policy) used rule, allow now = %d\n",
+- allowed);
++ _dbus_verbose (" (policy) used rule, result now = %d\n",
++ result);
+ }
+
+- return allowed;
++ if (result == BUS_RESULT_LATER)
++ {
++ BusContext *context = bus_connection_get_context(sender);
++ BusCheck *check = bus_context_get_check(context);
++
++ result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
++ privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
++ }
++ else
++ privilege = NULL;
++
++ if (privilege_param != NULL)
++ *privilege_param = privilege;
++
++ return result;
+ }
+
+ /* See docs on what the args mean on bus_context_check_security_policy()
+ * comment
+ */
+-dbus_bool_t
+-bus_client_policy_check_can_receive (BusClientPolicy *policy,
+- BusRegistry *registry,
+- dbus_bool_t requested_reply,
+- DBusConnection *sender,
+- DBusConnection *addressed_recipient,
+- DBusConnection *proposed_recipient,
+- DBusMessage *message,
+- dbus_int32_t *toggles)
++BusResult
++bus_client_policy_check_can_receive (BusClientPolicy *policy,
++ BusRegistry *registry,
++ dbus_bool_t requested_reply,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusConnection *proposed_recipient,
++ DBusMessage *message,
++ dbus_int32_t *toggles,
++ const char **privilege_param,
++ BusDeferredMessage **deferred_message)
+ {
+ DBusList *link;
+- dbus_bool_t allowed;
+ dbus_bool_t eavesdropping;
++ BusResult result;
++ const char *privilege;
+
+ eavesdropping =
+ addressed_recipient != proposed_recipient &&
+@@ -1068,7 +1112,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
+ _dbus_verbose (" (policy) checking receive rules, eavesdropping = %d\n", eavesdropping);
+ *toggles = 0;
+
+- allowed = FALSE;
++ result = BUS_RESULT_FALSE;
+ link = _dbus_list_get_first_link (&policy->rules);
+ while (link != NULL)
+ {
+@@ -1091,19 +1135,21 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
+ }
+ }
+
+- /* for allow, eavesdrop=false means the rule doesn't apply when
+- * eavesdropping. eavesdrop=true means always allow.
++
++ /* for allow or check, eavesdrop=false means the rule doesn't apply when
++ * eavesdropping. eavesdrop=true means the rule always applies
+ */
+- if (eavesdropping && rule->allow && !rule->d.receive.eavesdrop)
++ if (eavesdropping && rule->access != BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.eavesdrop)
+ {
+- _dbus_verbose (" (policy) skipping allow rule since it doesn't apply to eavesdropping\n");
++ _dbus_verbose (" (policy) skipping %s rule since it doesn't apply to eavesdropping\n",
++ rule->access == BUS_POLICY_RULE_ACCESS_ALLOW ? "allow" : "check");
+ continue;
+ }
+
+ /* for deny, eavesdrop=true means the rule applies only when
+ * eavesdropping; eavesdrop=false means always deny.
+ */
+- if (!eavesdropping && !rule->allow && rule->d.receive.eavesdrop)
++ if (!eavesdropping && rule->access == BUS_POLICY_RULE_ACCESS_DENY && rule->d.receive.eavesdrop)
+ {
+ _dbus_verbose (" (policy) skipping deny rule since it only applies to eavesdropping\n");
+ continue;
+@@ -1112,13 +1158,14 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
+ /* If it's a reply, the requested_reply flag kicks in */
+ if (dbus_message_get_reply_serial (message) != 0)
+ {
+- /* for allow, requested_reply=true means the rule applies
+- * only when reply was requested. requested_reply=false means
+- * always allow.
++ /* for allow or check requested_reply=true means the rule applies
++ * only when reply was requested. requested_reply=false means the
++ * rule always applies
+ */
+- if (!requested_reply && rule->allow && rule->d.receive.requested_reply && !rule->d.receive.eavesdrop)
++ if (!requested_reply && rule->access != BUS_POLICY_RULE_ACCESS_DENY && rule->d.send.requested_reply && !rule->d.send.eavesdrop)
+ {
+- _dbus_verbose (" (policy) skipping allow rule since it only applies to requested replies and does not allow eavesdropping\n");
++ _dbus_verbose (" (policy) skipping %s rule since it only applies to requested replies and does not allow eavesdropping\n",
++ rule->access == BUS_POLICY_RULE_ACCESS_DENY ? "allow" : "deny");
+ continue;
+ }
+
+@@ -1126,7 +1173,7 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
+ * when the reply was not requested. requested_reply=true means the
+ * rule always applies.
+ */
+- if (requested_reply && !rule->allow && !rule->d.receive.requested_reply)
++ if (requested_reply && rule->access == BUS_POLICY_RULE_ACCESS_DENY && !rule->d.receive.requested_reply)
+ {
+ _dbus_verbose (" (policy) skipping deny rule since it only applies to unrequested replies\n");
+ continue;
+@@ -1149,13 +1196,13 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
+ /* The interface is optional in messages. For allow rules, if the message
+ * has no interface we want to skip the rule (and thus not allow);
+ * for deny rules, if the message has no interface we want to use the
+- * rule (and thus deny).
++ * rule (and thus deny). Check rules are treated like allow rules.
+ */
+ dbus_bool_t no_interface;
+
+ no_interface = dbus_message_get_interface (message) == NULL;
+
+- if ((no_interface && rule->allow) ||
++ if ((no_interface && rule->access != BUS_POLICY_RULE_ACCESS_DENY) ||
+ (!no_interface &&
+ strcmp (dbus_message_get_interface (message),
+ rule->d.receive.interface) != 0))
+@@ -1230,14 +1277,42 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
+ }
+
+ /* Use this rule */
+- allowed = rule->allow;
++ switch (rule->access)
++ {
++ case BUS_POLICY_RULE_ACCESS_ALLOW:
++ result = BUS_RESULT_TRUE;
++ break;
++ case BUS_POLICY_RULE_ACCESS_DENY:
++ result = BUS_RESULT_FALSE;
++ break;
++ case BUS_POLICY_RULE_ACCESS_CHECK:
++ result = BUS_RESULT_LATER;
++ privilege = rule->privilege;
++ break;
++ }
++
+ (*toggles)++;
+
+- _dbus_verbose (" (policy) used rule, allow now = %d\n",
+- allowed);
++ _dbus_verbose (" (policy) used rule, result now = %d\n",
++ result);
+ }
+
+- return allowed;
++
++ if (result == BUS_RESULT_LATER)
++ {
++ BusContext *context = bus_connection_get_context(proposed_recipient);
++ BusCheck *check = bus_context_get_check(context);
++
++ result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
++ privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, deferred_message);
++ }
++ else
++ privilege = NULL;
++
++ if (privilege_param != NULL)
++ *privilege_param = privilege;
++
++ return result;
+ }
+
+
+@@ -1289,7 +1364,7 @@ bus_rules_check_can_own (DBusList *rules,
+ }
+
+ /* Use this rule */
+- allowed = rule->allow;
++ allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
+ }
+
+ return allowed;
+diff --git a/bus/policy.h b/bus/policy.h
+index d1d3e72..e9f193a 100644
+--- a/bus/policy.h
++++ b/bus/policy.h
+@@ -39,6 +39,14 @@ typedef enum
+ BUS_POLICY_RULE_GROUP
+ } BusPolicyRuleType;
+
++typedef enum
++{
++ BUS_POLICY_RULE_ACCESS_DENY,
++ BUS_POLICY_RULE_ACCESS_ALLOW,
++ /** runtime check resulting in allow or deny */
++ BUS_POLICY_RULE_ACCESS_CHECK
++} BusPolicyRuleAccess;
++
+ /** determines whether the rule affects a connection, or some global item */
+ #define BUS_POLICY_RULE_IS_PER_CLIENT(rule) (!((rule)->type == BUS_POLICY_RULE_USER || \
+ (rule)->type == BUS_POLICY_RULE_GROUP))
+@@ -49,8 +57,9 @@ struct BusPolicyRule
+
+ BusPolicyRuleType type;
+
+- unsigned int allow : 1; /**< #TRUE if this allows, #FALSE if it denies */
+-
++ unsigned int access : 2; /**< BusPolicyRuleAccess */
++ char *privilege; /**< for BUS_POLICY_RULE_ACCESS_CHECK */
++
+ union
+ {
+ struct
+@@ -106,7 +115,7 @@ struct BusPolicyRule
+ };
+
+ BusPolicyRule* bus_policy_rule_new (BusPolicyRuleType type,
+- dbus_bool_t allow);
++ BusPolicyRuleAccess access);
+ BusPolicyRule* bus_policy_rule_ref (BusPolicyRule *rule);
+ void bus_policy_rule_unref (BusPolicyRule *rule);
+
+@@ -140,21 +149,27 @@ dbus_bool_t bus_policy_merge (BusPolicy *policy,
+ BusClientPolicy* bus_client_policy_new (void);
+ BusClientPolicy* bus_client_policy_ref (BusClientPolicy *policy);
+ void bus_client_policy_unref (BusClientPolicy *policy);
+-dbus_bool_t bus_client_policy_check_can_send (BusClientPolicy *policy,
+- BusRegistry *registry,
+- dbus_bool_t requested_reply,
+- DBusConnection *receiver,
+- DBusMessage *message,
+- dbus_int32_t *toggles,
+- dbus_bool_t *log);
+-dbus_bool_t bus_client_policy_check_can_receive (BusClientPolicy *policy,
+- BusRegistry *registry,
+- dbus_bool_t requested_reply,
+- DBusConnection *sender,
+- DBusConnection *addressed_recipient,
+- DBusConnection *proposed_recipient,
+- DBusMessage *message,
+- dbus_int32_t *toggles);
++BusResult bus_client_policy_check_can_send (DBusConnection *sender,
++ BusClientPolicy *policy,
++ BusRegistry *registry,
++ dbus_bool_t requested_reply,
++ DBusConnection *addressed_recipient,
++ DBusConnection *receiver,
++ DBusMessage *message,
++ dbus_int32_t *toggles,
++ dbus_bool_t *log,
++ const char **privilege_param,
++ BusDeferredMessage **deferred_message);
++BusResult bus_client_policy_check_can_receive (BusClientPolicy *policy,
++ BusRegistry *registry,
++ dbus_bool_t requested_reply,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusConnection *proposed_recipient,
++ DBusMessage *message,
++ dbus_int32_t *toggles,
++ const char **privilege_param,
++ BusDeferredMessage **deferred_message);
+ dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy,
+ const DBusString *service_name);
+ dbus_bool_t bus_client_policy_append_rule (BusClientPolicy *policy,
+diff --git a/configure.ac b/configure.ac
+index eb803af..b131f30 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1748,6 +1748,18 @@ if test "x$enable_stats" = xyes; then
+ [Define to enable bus daemon usage statistics])
+ fi
+
++#enable cynara integration
++AC_ARG_ENABLE([cynara], [AS_HELP_STRING([--enable-cynara], [enable Cynara integration])], [], [enable_cynara=no])
++if test "x$enable_cynara" = xyes; then
++ PKG_CHECK_MODULES([CYNARA], [cynara-client-async >= 0.6.0 cynara-session >= 0.6.0],
++ [AC_DEFINE([DBUS_ENABLE_CYNARA], [1], [Define to enable Cynara privilege checks in dbus-daemon])],
++ [AC_MSG_ERROR([libcynara-client-async and cynara-session are required to enable Cynara integration])])
++fi
++
++AC_SUBST([CYNARA_CFLAGS])
++AC_SUBST([CYNARA_LIBS])
++
++
+ AC_CONFIG_FILES([
+ Doxyfile
+ dbus/versioninfo.rc
+@@ -1778,6 +1790,7 @@ dbus-1.pc
+ dbus-1-uninstalled.pc
+ test/data/valid-config-files/debug-allow-all.conf
+ test/data/valid-config-files/debug-allow-all-sha1.conf
++test/data/valid-config-files/debug-check-some.conf
+ test/data/valid-config-files/incoming-limit.conf
+ test/data/valid-config-files-system/debug-allow-all-pass.conf
+ test/data/valid-config-files-system/debug-allow-all-fail.conf
+diff --git a/test/Makefile.am b/test/Makefile.am
+index e0ed3c8..ab63edc 100644
+--- a/test/Makefile.am
++++ b/test/Makefile.am
+@@ -254,6 +254,7 @@ in_data = \
+ data/valid-config-files-system/debug-allow-all-pass.conf.in \
+ data/valid-config-files/debug-allow-all-sha1.conf.in \
+ data/valid-config-files/debug-allow-all.conf.in \
++ data/valid-config-files/debug-check-some.conf.in \
+ data/valid-config-files/incoming-limit.conf.in \
+ data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoExec.service.in \
+ data/invalid-service-files-system/org.freedesktop.DBus.TestSuiteNoService.service.in \
+diff --git a/test/data/invalid-config-files/badcheck-1.conf b/test/data/invalid-config-files/badcheck-1.conf
+new file mode 100644
+index 0000000..fad9f50
+--- /dev/null
++++ b/test/data/invalid-config-files/badcheck-1.conf
+@@ -0,0 +1,9 @@
++<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
++ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
++<busconfig>
++ <user>mybususer</user>
++ <listen>unix:path=/foo/bar</listen>
++ <policy context="default">
++ <allow privilege="foo" send_destination="*"/> <!-- extra privilege="foo" -->
++ </policy>
++</busconfig>
+diff --git a/test/data/invalid-config-files/badcheck-2.conf b/test/data/invalid-config-files/badcheck-2.conf
+new file mode 100644
+index 0000000..63c7ef2
+--- /dev/null
++++ b/test/data/invalid-config-files/badcheck-2.conf
+@@ -0,0 +1,9 @@
++<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
++ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
++<busconfig>
++ <user>mybususer</user>
++ <listen>unix:path=/foo/bar</listen>
++ <policy context="default">
++ <check send_destination="*"/> <!-- missing privilege="foo" -->
++ </policy>
++</busconfig>
+diff --git a/test/data/valid-config-files/check-1.conf b/test/data/valid-config-files/check-1.conf
+new file mode 100644
+index 0000000..ad71473
+--- /dev/null
++++ b/test/data/valid-config-files/check-1.conf
+@@ -0,0 +1,9 @@
++<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
++ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
++<busconfig>
++ <user>mybususer</user>
++ <listen>unix:path=/foo/bar</listen>
++ <policy context="default">
++ <check privilege="foo" send_destination="*"/>
++ </policy>
++</busconfig>
+diff --git a/test/data/valid-config-files/debug-check-some.conf.in b/test/data/valid-config-files/debug-check-some.conf.in
+new file mode 100644
+index 0000000..47ee854
+--- /dev/null
++++ b/test/data/valid-config-files/debug-check-some.conf.in
+@@ -0,0 +1,18 @@
++<!-- Bus that listens on a debug pipe and doesn't create any restrictions -->
++
++<!DOCTYPE busconfig PUBLIC "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
++ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
++<busconfig>
++ <listen>debug-pipe:name=test-server</listen>
++ <listen>@TEST_LISTEN@</listen>
++ <servicedir>@DBUS_TEST_DATA@/valid-service-files</servicedir>
++ <policy context="default">
++ <allow send_interface="*"/>
++ <allow receive_interface="*"/>
++ <allow own="*"/>
++ <allow user="*"/>
++
++ <deny send_interface="org.freedesktop.TestSuite" send_member="Echo"/>
++ <check privilege="foo" send_interface="org.freedesktop.TestSuite" send_member="Echo"/>
++ </policy>
++</busconfig>
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/dbus/dbus-cynara/0005-Disable-message-dispatching-when-send-rule-result-is.patch b/meta-security/recipes-core/dbus/dbus-cynara/0005-Disable-message-dispatching-when-send-rule-result-is.patch
new file mode 100644
index 000000000..ca787149e
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-cynara/0005-Disable-message-dispatching-when-send-rule-result-is.patch
@@ -0,0 +1,941 @@
+From b1b87ad9f20b2052c28431b48e81073078a745ce Mon Sep 17 00:00:00 2001
+From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
+Date: Fri, 28 Nov 2014 12:07:39 +0100
+Subject: [PATCH 5/8] Disable message dispatching when send rule result is not
+ known
+
+When unicast message is sent to addressed recipient and policy result
+is not available message dispatch from the sender is disabled.
+This also means that any further messages from the given connection are
+put into the incoming queue without being processed. If response is received
+message dispatching is resumed. This time answer is attached to the message
+which is now processed synchronously.
+Receive rule result unavailability is not yet handled - such messages are
+rejected. Also, if message is sent to non-addressed recipient and policy result
+is unknown, message is silently dropped.
+
+Change-Id: I57eccbf973525fd51369c7d4e58908292f44da80
+---
+ bus/activation.c | 79 +++++++++++++++--
+ bus/check.c | 109 ++++++++++++++++++++++--
+ bus/check.h | 10 +++
+ bus/cynara.c | 1 -
+ bus/dispatch.c | 183 ++++++++++++++++++++++++++++++++++++----
+ bus/dispatch.h | 2 +-
+ bus/driver.c | 13 ++-
+ dbus/dbus-connection-internal.h | 9 ++
+ dbus/dbus-connection.c | 125 +++++++++++++++++++++++++--
+ dbus/dbus-list.c | 29 +++++++
+ dbus/dbus-list.h | 2 +
+ dbus/dbus-shared.h | 3 +-
+ 12 files changed, 522 insertions(+), 43 deletions(-)
+
+diff --git a/bus/activation.c b/bus/activation.c
+index ecd19bb..8c43941 100644
+--- a/bus/activation.c
++++ b/bus/activation.c
+@@ -31,6 +31,7 @@
+ #include "services.h"
+ #include "test.h"
+ #include "utils.h"
++#include <dbus/dbus-connection-internal.h>
+ #include <dbus/dbus-internals.h>
+ #include <dbus/dbus-hash.h>
+ #include <dbus/dbus-list.h>
+@@ -91,6 +92,8 @@ struct BusPendingActivationEntry
+ DBusConnection *connection;
+
+ dbus_bool_t auto_activation;
++
++ dbus_bool_t is_put_back;
+ };
+
+ typedef struct
+@@ -1180,20 +1183,23 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation
+ BusPendingActivationEntry *entry = link->data;
+ DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
+
+- if (entry->auto_activation && (entry->connection == NULL || dbus_connection_get_is_connected (entry->connection)))
++ if (entry->auto_activation && !entry->is_put_back &&
++ (entry->connection == NULL || dbus_connection_get_is_connected (entry->connection)))
+ {
+ DBusConnection *addressed_recipient;
+ DBusError error;
++ BusResult res;
+
+ dbus_error_init (&error);
+
+ addressed_recipient = bus_service_get_primary_owners_connection (service);
+
+ /* Resume dispatching where we left off in bus_dispatch() */
+- if (!bus_dispatch_matches (transaction,
+- entry->connection,
+- addressed_recipient,
+- entry->activation_message, &error))
++ res = bus_dispatch_matches (transaction,
++ entry->connection,
++ addressed_recipient,
++ entry->activation_message, &error);
++ if (res == BUS_RESULT_FALSE)
+ {
+ /* If permission is denied, we just want to return the error
+ * to the original method invoker; in particular, we don't
+@@ -1205,9 +1211,40 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation
+ bus_connection_send_oom_error (entry->connection,
+ entry->activation_message);
+ }
++ }
++ else if (res == BUS_RESULT_LATER)
++ {
++ DBusList *putback_message_link = link;
++ DBusMessage *last_inserted_message = NULL;
++
++ /* NULL entry->connection implies sending pending ActivationRequest message to systemd */
++ if (entry->connection == NULL)
++ {
++ _dbus_assert_not_reached ("bus_dispatch_matches returned BUS_RESULT_LATER unexpectedly when sender is NULL");
++ link = next;
++ continue;
++ }
+
+- link = next;
+- continue;
++ /**
++ * Getting here means that policy check result is not yet available and dispatching
++ * messages from entry->connection has been disabled.
++ * Let's put back all messages for the given connection in the incoming queue and mark
++ * this entry as put back so they are not handled twice.
++ */
++ while (putback_message_link != NULL)
++ {
++ BusPendingActivationEntry *putback_message = putback_message_link->data;
++ if (putback_message->connection == entry->connection)
++ {
++ if (!_dbus_connection_putback_message (putback_message->connection, last_inserted_message,
++ putback_message->activation_message, &error))
++ goto error;
++ last_inserted_message = putback_message->activation_message;
++ putback_message->is_put_back = TRUE;
++ }
++
++ putback_message_link = _dbus_list_get_next_link(&pending_activation->entries, putback_message_link);
++ }
+ }
+ }
+
+@@ -1225,6 +1262,19 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation
+ return TRUE;
+
+ error:
++ /* remove all messages that have been put to connections' incoming queues */
++ link = _dbus_list_get_first_link (&pending_activation->entries);
++ while (link != NULL)
++ {
++ BusPendingActivationEntry *entry = link->data;
++ if (entry->is_put_back)
++ {
++ _dbus_connection_remove_message(entry->connection, entry->activation_message);
++ entry->is_put_back = FALSE;
++ }
++ link = _dbus_list_get_next_link(&pending_activation->entries, link);
++ }
++
+ return FALSE;
+ }
+
+@@ -2009,13 +2059,24 @@ bus_activation_activate_service (BusActivation *activation,
+
+ if (service != NULL)
+ {
++ BusResult res;
+ bus_context_log (activation->context,
+ DBUS_SYSTEM_LOG_INFO, "Activating via systemd: service name='%s' unit='%s'",
+ service_name,
+ entry->systemd_service);
+ /* Wonderful, systemd is connected, let's just send the msg */
+- retval = bus_dispatch_matches (activation_transaction, NULL, bus_service_get_primary_owners_connection (service),
+- message, error);
++ res = bus_dispatch_matches (activation_transaction, NULL, bus_service_get_primary_owners_connection (service),
++ message, error);
++
++ if (res == BUS_RESULT_TRUE)
++ retval = TRUE;
++ else if (res == BUS_RESULT_FALSE)
++ retval = FALSE;
++ else if (res == BUS_RESULT_LATER)
++ {
++ _dbus_verbose("Unexpectedly need time to check message from bus driver to systemd - dropping the message.\n");
++ retval = FALSE;
++ }
+ }
+ else
+ {
+diff --git a/bus/check.c b/bus/check.c
+index d2f418a..cd6a74b 100644
+--- a/bus/check.c
++++ b/bus/check.c
+@@ -55,6 +55,8 @@ typedef struct BusDeferredMessage
+ BusCheckResponseFunc response_callback;
+ } BusDeferredMessage;
+
++static dbus_int32_t deferred_message_data_slot = -1;
++
+ BusCheck *
+ bus_check_new (BusContext *context, DBusError *error)
+ {
+@@ -67,11 +69,19 @@ bus_check_new (BusContext *context, DBusError *error)
+ return NULL;
+ }
+
++ if (!dbus_message_allocate_data_slot(&deferred_message_data_slot))
++ {
++ dbus_free(check);
++ BUS_SET_OOM(error);
++ return NULL;
++ }
++
+ check->refcount = 1;
+ check->context = context;
+ check->cynara = bus_cynara_new(check, error);
+ if (dbus_error_is_set(error))
+ {
++ dbus_message_free_data_slot(&deferred_message_data_slot);
+ dbus_free(check);
+ return NULL;
+ }
+@@ -98,6 +108,7 @@ bus_check_unref (BusCheck *check)
+ if (check->refcount == 0)
+ {
+ bus_cynara_unref(check->cynara);
++ dbus_message_free_data_slot(&deferred_message_data_slot);
+ dbus_free(check);
+ }
+ }
+@@ -114,6 +125,45 @@ bus_check_get_cynara (BusCheck *check)
+ return check->cynara;
+ }
+
++static void
++bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
++ BusResult result)
++{
++ _dbus_verbose("bus_check_enable_dispatch_callback called deferred_message=%p\n", deferred_message);
++
++ deferred_message->response = result;
++ _dbus_connection_enable_dispatch(deferred_message->sender);
++}
++
++static void
++deferred_message_free_function(void *data)
++{
++ BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
++ bus_deferred_message_unref(deferred_message);
++}
++
++void
++bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
++{
++ _dbus_assert(deferred_message != NULL);
++ _dbus_assert(deferred_message->sender != NULL);
++
++ if (dbus_message_get_data(deferred_message->message, deferred_message_data_slot) == NULL)
++ {
++ if (dbus_message_set_data(deferred_message->message, deferred_message_data_slot, deferred_message,
++ deferred_message_free_function))
++ bus_deferred_message_ref(deferred_message);
++ }
++
++ _dbus_connection_disable_dispatch(deferred_message->sender);
++ deferred_message->response_callback = bus_check_enable_dispatch_callback;
++}
++
++#ifdef DBUS_ENABLE_EMBEDDED_TESTS
++dbus_bool_t (*bus_check_test_override) (DBusConnection *connection,
++ const char *privilege);
++#endif
++
+ BusResult
+ bus_check_privilege (BusCheck *check,
+ DBusMessage *message,
+@@ -124,6 +174,7 @@ bus_check_privilege (BusCheck *check,
+ BusDeferredMessageStatus check_type,
+ BusDeferredMessage **deferred_message)
+ {
++ BusDeferredMessage *previous_deferred_message;
+ BusResult result = BUS_RESULT_FALSE;
+ BusCynara *cynara;
+ DBusConnection *connection;
+@@ -135,16 +186,54 @@ bus_check_privilege (BusCheck *check,
+ return BUS_RESULT_FALSE;
+ }
+
+- /* ask policy checkers */
+-#ifdef DBUS_ENABLE_CYNARA
+- cynara = bus_check_get_cynara(check);
+- result = bus_cynara_check_privilege(cynara, message, sender, addressed_recipient,
+- proposed_recipient, privilege, check_type, deferred_message);
++#ifdef DBUS_ENABLE_EMBEDDED_TESTS
++ if (bus_check_test_override)
++ return bus_check_test_override (connection, privilege);
+ #endif
+
+- if (result == BUS_RESULT_LATER && deferred_message != NULL)
++ previous_deferred_message = dbus_message_get_data(message, deferred_message_data_slot);
++ /* check if message blocked at sender's queue is being processed */
++ if (previous_deferred_message != NULL)
++ {
++ if ((check_type & BUS_DEFERRED_MESSAGE_CHECK_SEND) &&
++ !(previous_deferred_message->status & BUS_DEFERRED_MESSAGE_CHECK_SEND))
++ {
++ /**
++ * Message has been deferred due to receive or own rule which means that sending this message
++ * is allowed - it must have been checked previously.
++ * This might happen when client calls RequestName method which depending on security
++ * policy might result in both "can_send" and "can_own" Cynara checks.
++ */
++ result = BUS_RESULT_TRUE;
++ }
++ else
++ {
++ result = previous_deferred_message->response;
++ if (result == BUS_RESULT_LATER)
++ {
++ /* result is still not known - reuse deferred message object */
++ if (deferred_message != NULL)
++ *deferred_message = previous_deferred_message;
++ }
++ else
++ {
++ /* result is available - we can remove deferred message from the processed message */
++ dbus_message_set_data(message, deferred_message_data_slot, NULL, NULL);
++ }
++ }
++ }
++ else
+ {
+- (*deferred_message)->status |= check_type;
++ /* ask policy checkers */
++#ifdef DBUS_ENABLE_CYNARA
++ cynara = bus_check_get_cynara(check);
++ result = bus_cynara_check_privilege(cynara, message, sender, addressed_recipient,
++ proposed_recipient, privilege, check_type, deferred_message);
++#endif
++ if (result == BUS_RESULT_LATER && deferred_message != NULL)
++ {
++ (*deferred_message)->status |= check_type;
++ }
+ }
+ return result;
+ }
+@@ -204,6 +293,12 @@ bus_deferred_message_unref (BusDeferredMessage *deferred_message)
+ }
+ }
+
++BusDeferredMessageStatus
++bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
++{
++ return deferred_message->status;
++}
++
+ void
+ bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
+ BusResult result)
+diff --git a/bus/check.h b/bus/check.h
+index c3fcaf9..f381789 100644
+--- a/bus/check.h
++++ b/bus/check.h
+@@ -55,6 +55,7 @@ BusResult bus_check_privilege (BusCheck *check,
+ BusDeferredMessageStatus check_type,
+ BusDeferredMessage **deferred_message);
+
++
+ BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+@@ -65,4 +66,13 @@ BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage
+ void bus_deferred_message_unref (BusDeferredMessage *deferred_message);
+ void bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
+ BusResult result);
++void bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message);
++
++BusDeferredMessageStatus bus_deferred_message_get_status (BusDeferredMessage *deferred_message);
++
++#ifdef DBUS_ENABLE_EMBEDDED_TESTS
++extern dbus_bool_t (*bus_check_test_override) (DBusConnection *connection,
++ const char *privilege);
++#endif
++
+ #endif /* BUS_CHECK_H */
+diff --git a/bus/cynara.c b/bus/cynara.c
+index 57a4c45..77aed62 100644
+--- a/bus/cynara.c
++++ b/bus/cynara.c
+@@ -36,7 +36,6 @@
+ #include <cynara-client-async.h>
+ #endif
+
+-
+ #ifdef DBUS_ENABLE_CYNARA
+ typedef struct BusCynara
+ {
+diff --git a/bus/dispatch.c b/bus/dispatch.c
+index ce4076d..6b0eadc 100644
+--- a/bus/dispatch.c
++++ b/bus/dispatch.c
+@@ -81,7 +81,7 @@ send_one_message (DBusConnection *connection,
+ return TRUE;
+ }
+
+-dbus_bool_t
++BusResult
+ bus_dispatch_matches (BusTransaction *transaction,
+ DBusConnection *sender,
+ DBusConnection *addressed_recipient,
+@@ -117,13 +117,29 @@ bus_dispatch_matches (BusTransaction *transaction,
+ message, error,
+ &deferred_message);
+ if (res == BUS_RESULT_FALSE)
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ else if (res == BUS_RESULT_LATER)
+ {
+- dbus_set_error (error,
+- DBUS_ERROR_ACCESS_DENIED,
+- "Rejecting message because time is needed to check security policy");
+- return FALSE;
++ BusDeferredMessageStatus status;
++ status = bus_deferred_message_get_status(deferred_message);
++
++ if (status & BUS_DEFERRED_MESSAGE_CHECK_SEND)
++ {
++ /* send rule result not available - disable dispatching messages from the sender */
++ bus_deferred_message_disable_sender(deferred_message);
++ return BUS_RESULT_LATER;
++ }
++ else if (status & BUS_DEFERRED_MESSAGE_CHECK_RECEIVE)
++ {
++ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
++ "Rejecting message because time is needed to check security policy");
++ return BUS_RESULT_FALSE;
++ }
++ else
++ {
++ _dbus_verbose("deferred message has no status field set to send or receive unexpectedly\n");
++ return BUS_RESULT_FALSE;
++ }
+ }
+
+ if (dbus_message_contains_unix_fds (message) &&
+@@ -134,14 +150,14 @@ bus_dispatch_matches (BusTransaction *transaction,
+ DBUS_ERROR_NOT_SUPPORTED,
+ "Tried to send message with Unix file descriptors"
+ "to a client that doesn't support that.");
+- return FALSE;
+- }
++ return BUS_RESULT_FALSE;
++ }
+
+ /* Dispatch the message */
+ if (!bus_transaction_send (transaction, addressed_recipient, message))
+ {
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+ }
+
+@@ -156,7 +172,7 @@ bus_dispatch_matches (BusTransaction *transaction,
+ &recipients))
+ {
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ link = _dbus_list_get_first_link (&recipients);
+@@ -178,10 +194,10 @@ bus_dispatch_matches (BusTransaction *transaction,
+ if (dbus_error_is_set (&tmp_error))
+ {
+ dbus_move_error (&tmp_error, error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+ else
+- return TRUE;
++ return BUS_RESULT_TRUE;
+ }
+
+ static DBusHandlerResult
+@@ -298,10 +314,12 @@ bus_dispatch (DBusConnection *connection,
+ }
+ else if (res == BUS_RESULT_LATER)
+ {
+- dbus_set_error (&error,
+- DBUS_ERROR_ACCESS_DENIED,
+- "Rejecting message because time is needed to check security policy");
+- _dbus_verbose ("Security policy needs time to check policy. Dropping message\n");
++ /* Disable dispatching messages from the sender,
++ * roll back and dispatch the message once the policy result is available */
++ bus_deferred_message_disable_sender(deferred_message);
++ bus_transaction_cancel_and_free (transaction);
++ transaction = NULL;
++ result = DBUS_HANDLER_RESULT_LATER;
+ goto out;
+ }
+
+@@ -366,8 +384,14 @@ bus_dispatch (DBusConnection *connection,
+ * addressed_recipient == NULL), and match it against other connections'
+ * match rules.
+ */
+- if (!bus_dispatch_matches (transaction, connection, addressed_recipient, message, &error))
+- goto out;
++ if (BUS_RESULT_LATER == bus_dispatch_matches (transaction, connection, addressed_recipient,
++ message, &error))
++ {
++ /* Roll back and dispatch the message once the policy result is available */
++ bus_transaction_cancel_and_free (transaction);
++ transaction = NULL;
++ result = DBUS_HANDLER_RESULT_LATER;
++ }
+
+ out:
+ if (dbus_error_is_set (&error))
+@@ -4714,9 +4738,132 @@ bus_dispatch_test_conf_fail (const DBusString *test_data_dir,
+ return TRUE;
+ }
+
++typedef struct {
++ DBusTimeout *timeout;
++ DBusConnection *connection;
++ dbus_bool_t timedout;
++ int check_counter;
++} BusTestCheckData;
++
++static BusTestCheckData *cdata;
++
++static dbus_bool_t
++bus_dispatch_test_check_timeout (void *data)
++{
++ _dbus_verbose ("timeout triggered - pretend that privilege check result is available\n");
++
++ /* should only happen once during the test */
++ _dbus_assert (!cdata->timedout);
++ cdata->timedout = TRUE;
++ _dbus_connection_enable_dispatch (cdata->connection);
++
++ /* don't call this again */
++ _dbus_loop_remove_timeout (bus_connection_get_loop (cdata->connection),
++ cdata->timeout);
++ dbus_connection_unref (cdata->connection);
++ cdata->connection = NULL;
++ return TRUE;
++}
++
++static dbus_bool_t
++bus_dispatch_test_check_override (DBusConnection *connection,
++ const char *privilege)
++{
++ _dbus_verbose ("overriding privilege check %s #%d\n", privilege, cdata->check_counter);
++ cdata->check_counter++;
++ if (!cdata->timedout)
++ {
++ dbus_bool_t added;
++
++ /* Should be the first privilege check for the "Echo" method. */
++ _dbus_assert (cdata->check_counter == 1);
++ cdata->timeout = _dbus_timeout_new (1, bus_dispatch_test_check_timeout,
++ NULL, NULL);
++ _dbus_assert (cdata->timeout);
++ added = _dbus_loop_add_timeout (bus_connection_get_loop (connection),
++ cdata->timeout);
++ _dbus_assert (added);
++ cdata->connection = connection;
++ dbus_connection_ref (connection);
++ _dbus_connection_disable_dispatch (connection);
++ return BUS_RESULT_LATER;
++ }
++ else
++ {
++ /* Should only be checked one more time, and this time succeeds. */
++ _dbus_assert (cdata->check_counter == 2);
++ return BUS_RESULT_TRUE;
++ }
++}
++
++static dbus_bool_t
++bus_dispatch_test_check (const DBusString *test_data_dir)
++{
++ const char *filename = "valid-config-files/debug-check-some.conf";
++ BusContext *context;
++ DBusConnection *foo;
++ DBusError error;
++ dbus_bool_t result = TRUE;
++ BusTestCheckData data;
++
++ /* save the config name for the activation helper */
++ if (!setenv_TEST_LAUNCH_HELPER_CONFIG (test_data_dir, filename))
++ _dbus_assert_not_reached ("no memory setting TEST_LAUNCH_HELPER_CONFIG");
++
++ dbus_error_init (&error);
++
++ context = bus_context_new_test (test_data_dir, filename);
++ if (context == NULL)
++ return FALSE;
++
++ foo = dbus_connection_open_private (TEST_DEBUG_PIPE, &error);
++ if (foo == NULL)
++ _dbus_assert_not_reached ("could not alloc connection");
++
++ if (!bus_setup_debug_client (foo))
++ _dbus_assert_not_reached ("could not set up connection");
++
++ spin_connection_until_authenticated (context, foo);
++
++ if (!check_hello_message (context, foo))
++ _dbus_assert_not_reached ("hello message failed");
++
++ if (!check_double_hello_message (context, foo))
++ _dbus_assert_not_reached ("double hello message failed");
++
++ if (!check_add_match_all (context, foo))
++ _dbus_assert_not_reached ("AddMatch message failed");
++
++ /*
++ * Cause bus_check_send_privilege() to return BUS_RESULT_LATER in the
++ * first call, then BUS_RESULT_TRUE.
++ */
++ cdata = &data;
++ memset (cdata, 0, sizeof(*cdata));
++ bus_check_test_override = bus_dispatch_test_check_override;
++
++ result = check_existent_service_auto_start (context, foo);
++
++ _dbus_assert (cdata->check_counter == 2);
++ _dbus_assert (cdata->timedout);
++ _dbus_assert (cdata->timeout);
++ _dbus_assert (!cdata->connection);
++ _dbus_timeout_unref (cdata->timeout);
++
++ kill_client_connection_unchecked (foo);
++
++ bus_context_unref (context);
++
++ return result;
++}
++
+ dbus_bool_t
+ bus_dispatch_test (const DBusString *test_data_dir)
+ {
++ _dbus_verbose ("<check> tests\n");
++ if (!bus_dispatch_test_check (test_data_dir))
++ return FALSE;
++
+ /* run normal activation tests */
+ _dbus_verbose ("Normal activation tests\n");
+ if (!bus_dispatch_test_conf (test_data_dir,
+diff --git a/bus/dispatch.h b/bus/dispatch.h
+index fb5ba7a..afba6a2 100644
+--- a/bus/dispatch.h
++++ b/bus/dispatch.h
+@@ -29,7 +29,7 @@
+
+ dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection);
+ void bus_dispatch_remove_connection (DBusConnection *connection);
+-dbus_bool_t bus_dispatch_matches (BusTransaction *transaction,
++BusResult bus_dispatch_matches (BusTransaction *transaction,
+ DBusConnection *sender,
+ DBusConnection *recipient,
+ DBusMessage *message,
+diff --git a/bus/driver.c b/bus/driver.c
+index 11706f8..4dbce3d 100644
+--- a/bus/driver.c
++++ b/bus/driver.c
+@@ -97,6 +97,7 @@ bus_driver_send_service_owner_changed (const char *service_name,
+ {
+ DBusMessage *message;
+ dbus_bool_t retval;
++ BusResult res;
+ const char *null_service;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+@@ -129,7 +130,17 @@ bus_driver_send_service_owner_changed (const char *service_name,
+
+ _dbus_assert (dbus_message_has_signature (message, "sss"));
+
+- retval = bus_dispatch_matches (transaction, NULL, NULL, message, error);
++ res = bus_dispatch_matches (transaction, NULL, NULL, message, error);
++ if (res == BUS_RESULT_TRUE)
++ retval = TRUE;
++ else if (res == BUS_RESULT_FALSE)
++ retval = FALSE;
++ else if (res == BUS_RESULT_LATER)
++ {
++ /* should never happen */
++ _dbus_assert_not_reached ("bus_dispatch_matches returned BUS_RESULT_LATER unexpectedly");
++ retval = FALSE;
++ }
+ dbus_message_unref (message);
+
+ return retval;
+diff --git a/dbus/dbus-connection-internal.h b/dbus/dbus-connection-internal.h
+index 64ef336..4fcd118 100644
+--- a/dbus/dbus-connection-internal.h
++++ b/dbus/dbus-connection-internal.h
+@@ -109,6 +109,15 @@ void _dbus_connection_set_pending_fds_function (DBusConnectio
+
+ dbus_bool_t _dbus_connection_get_linux_security_label (DBusConnection *connection,
+ char **label_p);
++void _dbus_connection_enable_dispatch (DBusConnection *connection);
++void _dbus_connection_disable_dispatch (DBusConnection *connection);
++dbus_bool_t _dbus_connection_putback_message (DBusConnection *connection,
++ DBusMessage *after_message,
++ DBusMessage *message,
++ DBusError *error);
++
++dbus_bool_t _dbus_connection_remove_message (DBusConnection *connection,
++ DBusMessage *message);
+
+ /* if DBUS_ENABLE_STATS */
+ void _dbus_connection_get_stats (DBusConnection *connection,
+diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c
+index 8952b75..5d8d943 100644
+--- a/dbus/dbus-connection.c
++++ b/dbus/dbus-connection.c
+@@ -311,7 +311,8 @@ struct DBusConnection
+ */
+ dbus_bool_t dispatch_acquired; /**< Someone has dispatch path (can drain incoming queue) */
+ dbus_bool_t io_path_acquired; /**< Someone has transport io path (can use the transport to read/write messages) */
+-
++
++ unsigned int dispatch_disabled : 1; /**< if true, then dispatching incoming messages is stopped until enabled again */
+ unsigned int shareable : 1; /**< #TRUE if libdbus owns a reference to the connection and can return it from dbus_connection_open() more than once */
+
+ unsigned int exit_on_disconnect : 1; /**< If #TRUE, exit after handling disconnect signal */
+@@ -439,6 +440,39 @@ _dbus_connection_wakeup_mainloop (DBusConnection *connection)
+ (*connection->wakeup_main_function) (connection->wakeup_main_data);
+ }
+
++static void
++_dbus_connection_set_dispatch(DBusConnection *connection,
++ dbus_bool_t disabled)
++{
++ CONNECTION_LOCK (connection);
++ if (connection->dispatch_disabled != disabled)
++ {
++ DBusDispatchStatus status;
++
++ connection->dispatch_disabled = disabled;
++ status = _dbus_connection_get_dispatch_status_unlocked (connection);
++ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
++ }
++ else
++ {
++ CONNECTION_UNLOCK (connection);
++ }
++}
++
++
++void
++_dbus_connection_enable_dispatch (DBusConnection *connection)
++{
++ _dbus_connection_set_dispatch (connection, FALSE);
++}
++
++void
++ _dbus_connection_disable_dispatch (DBusConnection *connection)
++{
++ _dbus_connection_set_dispatch (connection, TRUE);
++}
++
++
+ #ifdef DBUS_ENABLE_EMBEDDED_TESTS
+ /**
+ * Gets the locks so we can examine them
+@@ -4068,6 +4102,82 @@ _dbus_connection_putback_message_link_unlocked (DBusConnection *connection,
+ "_dbus_connection_putback_message_link_unlocked");
+ }
+
++dbus_bool_t
++_dbus_connection_putback_message (DBusConnection *connection,
++ DBusMessage *after_message,
++ DBusMessage *message,
++ DBusError *error)
++{
++ DBusDispatchStatus status;
++ DBusList *message_link = _dbus_list_alloc_link (message);
++ DBusList *after_link;
++ if (message_link == NULL)
++ {
++ _DBUS_SET_OOM (error);
++ return FALSE;
++ }
++ dbus_message_ref (message);
++
++ CONNECTION_LOCK (connection);
++ _dbus_connection_acquire_dispatch (connection);
++ HAVE_LOCK_CHECK (connection);
++
++ after_link = _dbus_list_find_first(&connection->incoming_messages, after_message);
++ _dbus_list_insert_after_link (&connection->incoming_messages, after_link, message_link);
++ connection->n_incoming += 1;
++
++ _dbus_verbose ("Message %p (%s %s %s '%s') put back into queue %p, %d incoming\n",
++ message_link->data,
++ dbus_message_type_to_string (dbus_message_get_type (message_link->data)),
++ dbus_message_get_interface (message_link->data) ?
++ dbus_message_get_interface (message_link->data) :
++ "no interface",
++ dbus_message_get_member (message_link->data) ?
++ dbus_message_get_member (message_link->data) :
++ "no member",
++ dbus_message_get_signature (message_link->data),
++ connection, connection->n_incoming);
++
++ _dbus_message_trace_ref (message_link->data, -1, -1,
++ "_dbus_connection_putback_message");
++
++ _dbus_connection_release_dispatch (connection);
++
++ status = _dbus_connection_get_dispatch_status_unlocked (connection);
++ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
++
++ return TRUE;
++}
++
++dbus_bool_t
++_dbus_connection_remove_message (DBusConnection *connection,
++ DBusMessage *message)
++{
++ DBusDispatchStatus status;
++ dbus_bool_t removed;
++
++ CONNECTION_LOCK (connection);
++ _dbus_connection_acquire_dispatch (connection);
++ HAVE_LOCK_CHECK (connection);
++
++ removed = _dbus_list_remove(&connection->incoming_messages, message);
++
++ if (removed)
++ {
++ connection->n_incoming -= 1;
++ dbus_message_unref(message);
++ _dbus_verbose ("Message %p removed from incoming queue\n", message);
++ }
++ else
++ _dbus_verbose ("Message %p not found in the incoming queue\n", message);
++
++ _dbus_connection_release_dispatch (connection);
++
++ status = _dbus_connection_get_dispatch_status_unlocked (connection);
++ _dbus_connection_update_dispatch_status_and_unlock (connection, status);
++ return removed;
++}
++
+ /**
+ * Returns the first-received message from the incoming message queue,
+ * removing it from the queue. The caller owns a reference to the
+@@ -4251,8 +4361,9 @@ static DBusDispatchStatus
+ _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection)
+ {
+ HAVE_LOCK_CHECK (connection);
+-
+- if (connection->n_incoming > 0)
++ if (connection->dispatch_disabled && dbus_connection_get_is_connected(connection))
++ return DBUS_DISPATCH_COMPLETE;
++ else if (connection->n_incoming > 0)
+ return DBUS_DISPATCH_DATA_REMAINS;
+ else if (!_dbus_transport_queue_messages (connection->transport))
+ return DBUS_DISPATCH_NEED_MEMORY;
+@@ -4689,6 +4800,8 @@ dbus_connection_dispatch (DBusConnection *connection)
+
+ CONNECTION_LOCK (connection);
+
++ if (result == DBUS_HANDLER_RESULT_LATER)
++ goto out;
+ if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
+ {
+ _dbus_verbose ("No memory\n");
+@@ -4811,9 +4924,11 @@ dbus_connection_dispatch (DBusConnection *connection)
+ connection);
+
+ out:
+- if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
++ if (result == DBUS_HANDLER_RESULT_LATER ||
++ result == DBUS_HANDLER_RESULT_NEED_MEMORY)
+ {
+- _dbus_verbose ("out of memory\n");
++ if (result == DBUS_HANDLER_RESULT_NEED_MEMORY)
++ _dbus_verbose ("out of memory\n");
+
+ /* Put message back, and we'll start over.
+ * Yes this means handlers must be idempotent if they
+diff --git a/dbus/dbus-list.c b/dbus/dbus-list.c
+index c4c1856..f84918b 100644
+--- a/dbus/dbus-list.c
++++ b/dbus/dbus-list.c
+@@ -459,6 +459,35 @@ _dbus_list_remove_last (DBusList **list,
+ }
+
+ /**
++ * Finds a value in the list. Returns the first link
++ * with value equal to the given data pointer.
++ * This is a linear-time operation.
++ * Returns #NULL if no value found that matches.
++ *
++ * @param list address of the list head.
++ * @param data the value to find.
++ * @returns the link if found
++ */
++DBusList*
++_dbus_list_find_first (DBusList **list,
++ void *data)
++{
++ DBusList *link;
++
++ link = _dbus_list_get_first_link (list);
++
++ while (link != NULL)
++ {
++ if (link->data == data)
++ return link;
++
++ link = _dbus_list_get_next_link (list, link);
++ }
++
++ return NULL;
++}
++
++/**
+ * Finds a value in the list. Returns the last link
+ * with value equal to the given data pointer.
+ * This is a linear-time operation.
+diff --git a/dbus/dbus-list.h b/dbus/dbus-list.h
+index 910d738..abe8331 100644
+--- a/dbus/dbus-list.h
++++ b/dbus/dbus-list.h
+@@ -59,6 +59,8 @@ dbus_bool_t _dbus_list_remove_last (DBusList **list,
+ void *data);
+ void _dbus_list_remove_link (DBusList **list,
+ DBusList *link);
++DBusList* _dbus_list_find_first (DBusList **list,
++ void *data);
+ DBusList* _dbus_list_find_last (DBusList **list,
+ void *data);
+ void _dbus_list_clear (DBusList **list);
+diff --git a/dbus/dbus-shared.h b/dbus/dbus-shared.h
+index 6a57670..5371d88 100644
+--- a/dbus/dbus-shared.h
++++ b/dbus/dbus-shared.h
+@@ -67,7 +67,8 @@ typedef enum
+ {
+ DBUS_HANDLER_RESULT_HANDLED, /**< Message has had its effect - no need to run more handlers. */
+ DBUS_HANDLER_RESULT_NOT_YET_HANDLED, /**< Message has not had any effect - see if other handlers want it. */
+- DBUS_HANDLER_RESULT_NEED_MEMORY /**< Need more memory in order to return #DBUS_HANDLER_RESULT_HANDLED or #DBUS_HANDLER_RESULT_NOT_YET_HANDLED. Please try again later with more memory. */
++ DBUS_HANDLER_RESULT_NEED_MEMORY, /**< Need more memory in order to return #DBUS_HANDLER_RESULT_HANDLED or #DBUS_HANDLER_RESULT_NOT_YET_HANDLED. Please try again later with more memory. */
++ DBUS_HANDLER_RESULT_LATER /**< Message dispatch deferred due to pending policy check */
+ } DBusHandlerResult;
+
+ /* Bus names */
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/dbus/dbus-cynara/0006-Handle-unavailability-of-policy-results-for-broadcas.patch b/meta-security/recipes-core/dbus/dbus-cynara/0006-Handle-unavailability-of-policy-results-for-broadcas.patch
new file mode 100644
index 000000000..66f4e14e5
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-cynara/0006-Handle-unavailability-of-policy-results-for-broadcas.patch
@@ -0,0 +1,1071 @@
+From 1e231194610892dd4360224998d91336097b05a1 Mon Sep 17 00:00:00 2001
+From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
+Date: Fri, 28 Nov 2014 12:39:33 +0100
+Subject: [PATCH 6/8] Handle unavailability of policy results for broadcasts
+ and receive rules
+
+When message is sent to the addressed recipient and receive rule
+result is unavailable we don't want to block the sender
+as it most likely will be the privileged service, so instead we queue
+it at the recipient. Any further messages sent to it will be queued to
+maintain message order. Once the answer from Cynara arrives messages are
+dispatched from the recipient queue. In such case full dispatch is
+performed - messages are sent to addressed recipient and other
+interested connections.
+Messages sent to non-addressed recipients (eavesdroppers or broadcast
+message recipients) are handled in a similar way. The difference is
+that it is not full dispatch meaning message is sent to a single recipient.
+
+Change-Id: Iecd5395f75a4c7811fa97247a37d8fc4d42e8814
+---
+ bus/activation.c | 4 +-
+ bus/bus.c | 50 +++++++--
+ bus/bus.h | 19 ++++
+ bus/check.c | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ bus/check.h | 25 +++++
+ bus/connection.c | 166 ++++++++++++++++++++++++++++--
+ bus/connection.h | 19 +++-
+ bus/dispatch.c | 122 ++++++++++++++++++----
+ bus/dispatch.h | 11 +-
+ bus/driver.c | 2 +-
+ bus/policy.c | 6 ++
+ 11 files changed, 685 insertions(+), 46 deletions(-)
+
+diff --git a/bus/activation.c b/bus/activation.c
+index 8c43941..308bf41 100644
+--- a/bus/activation.c
++++ b/bus/activation.c
+@@ -1198,7 +1198,7 @@ bus_activation_send_pending_auto_activation_messages (BusActivation *activation
+ res = bus_dispatch_matches (transaction,
+ entry->connection,
+ addressed_recipient,
+- entry->activation_message, &error);
++ entry->activation_message, NULL, &error);
+ if (res == BUS_RESULT_FALSE)
+ {
+ /* If permission is denied, we just want to return the error
+@@ -2066,7 +2066,7 @@ bus_activation_activate_service (BusActivation *activation,
+ entry->systemd_service);
+ /* Wonderful, systemd is connected, let's just send the msg */
+ res = bus_dispatch_matches (activation_transaction, NULL, bus_service_get_primary_owners_connection (service),
+- message, error);
++ message, NULL, error);
+
+ if (res == BUS_RESULT_TRUE)
+ retval = TRUE;
+diff --git a/bus/bus.c b/bus/bus.c
+index ac9ea8d..b478b8e 100644
+--- a/bus/bus.c
++++ b/bus/bus.c
+@@ -1704,17 +1704,9 @@ bus_context_check_security_policy (BusContext *context,
+ }
+
+ /* See if limits on size have been exceeded */
+- if (proposed_recipient &&
+- ((dbus_connection_get_outgoing_size (proposed_recipient) > context->limits.max_outgoing_bytes) ||
+- (dbus_connection_get_outgoing_unix_fds (proposed_recipient) > context->limits.max_outgoing_unix_fds)))
+- {
+- complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
+- "Rejected: destination has a full message queue",
+- 0, message, sender, proposed_recipient, requested_reply, TRUE, NULL,
+- error);
+- _dbus_verbose ("security policy disallowing message due to full message queue\n");
++ if (!bus_context_check_recipient_message_limits(context, proposed_recipient, sender, message,
++ requested_reply, error))
+ return BUS_RESULT_FALSE;
+- }
+
+ /* Record that we will allow a reply here in the future (don't
+ * bother if the recipient is the bus or this is an eavesdropping
+@@ -1769,3 +1761,41 @@ bus_context_check_all_watches (BusContext *context)
+ _dbus_server_toggle_all_watches (server, enabled);
+ }
+ }
++
++void
++bus_context_complain_about_message (BusContext *context,
++ const char *error_name,
++ const char *complaint,
++ int matched_rules,
++ DBusMessage *message,
++ DBusConnection *sender,
++ DBusConnection *proposed_recipient,
++ dbus_bool_t requested_reply,
++ dbus_bool_t log,
++ const char *privilege,
++ DBusError *error)
++{
++ complain_about_message(context, error_name, complaint, matched_rules, message, sender,
++ proposed_recipient, requested_reply, log, privilege, error);
++}
++
++dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
++ DBusConnection *recipient,
++ DBusConnection *sender,
++ DBusMessage *message,
++ dbus_bool_t requested_reply,
++ DBusError *error)
++{
++ if (recipient &&
++ ((dbus_connection_get_outgoing_size (recipient) > context->limits.max_outgoing_bytes) ||
++ (dbus_connection_get_outgoing_unix_fds (recipient) > context->limits.max_outgoing_unix_fds)))
++ {
++ complain_about_message (context, DBUS_ERROR_LIMITS_EXCEEDED,
++ "Rejected: destination has a full message queue",
++ 0, message, sender, recipient, requested_reply, TRUE, NULL,
++ error);
++ _dbus_verbose ("security policy disallowing message due to full message queue\n");
++ return FALSE;
++ }
++ return TRUE;
++}
+diff --git a/bus/bus.h b/bus/bus.h
+index 78084dd..27a5e49 100644
+--- a/bus/bus.h
++++ b/bus/bus.h
+@@ -148,4 +148,23 @@ BusResult bus_context_check_security_policy (BusContext
+ DBusError *error,
+ BusDeferredMessage **deferred_message);
+
++dbus_bool_t bus_context_check_recipient_message_limits (BusContext *context,
++ DBusConnection *recipient,
++ DBusConnection *sender,
++ DBusMessage *message,
++ dbus_bool_t requested_reply,
++ DBusError *error);
++void bus_context_complain_about_message (BusContext *context,
++ const char *error_name,
++ const char *complaint,
++ int matched_rules,
++ DBusMessage *message,
++ DBusConnection *sender,
++ DBusConnection *proposed_recipient,
++ dbus_bool_t requested_reply,
++ dbus_bool_t log,
++ const char *privilege,
++ DBusError *error);
++
++
+ #endif /* BUS_BUS_H */
+diff --git a/bus/check.c b/bus/check.c
+index cd6a74b..733763a 100644
+--- a/bus/check.c
++++ b/bus/check.c
+@@ -49,6 +49,9 @@ typedef struct BusDeferredMessage
+ DBusConnection *sender;
+ DBusConnection *proposed_recipient;
+ DBusConnection *addressed_recipient;
++ dbus_bool_t requested_reply;
++ int matched_rules;
++ const char *privilege;
+ dbus_bool_t full_dispatch;
+ BusDeferredMessageStatus status;
+ BusResult response;
+@@ -136,6 +139,89 @@ bus_check_enable_dispatch_callback (BusDeferredMessage *deferred_message,
+ }
+
+ static void
++bus_check_queued_message_reply_callback (BusDeferredMessage *deferred_message,
++ BusResult result)
++{
++ int status;
++
++ _dbus_verbose("bus_check_queued_message_reply_callback called message=%p\n", deferred_message);
++
++ if (!bus_connection_is_active(deferred_message->proposed_recipient))
++ return;
++
++ status = deferred_message->status;
++
++ deferred_message->status = 0; /* mark message as not waiting for response */
++ deferred_message->response = result;
++
++ /*
++ * If send rule allows us to send message we still need to check receive rules.
++ */
++ if ((status & BUS_DEFERRED_MESSAGE_CHECK_SEND) && (result == BUS_RESULT_TRUE))
++ {
++ int toggles;
++ BusContext *context;
++ BusRegistry *registry;
++ BusClientPolicy *recipient_policy;
++ BusDeferredMessage *deferred_message_receive;
++
++ context = bus_connection_get_context(deferred_message->proposed_recipient);
++ registry = bus_context_get_registry(context);
++ recipient_policy = bus_connection_get_policy(deferred_message->proposed_recipient);
++
++ deferred_message->response = bus_client_policy_check_can_receive(recipient_policy, registry,
++ deferred_message->requested_reply, deferred_message->sender,
++ deferred_message->addressed_recipient, deferred_message->proposed_recipient, deferred_message->message,
++ &toggles, NULL, &deferred_message_receive);
++ if (deferred_message->response == BUS_RESULT_LATER)
++ {
++ /* replace deferred message associated with send check with the one associated with
++ * receive check */
++ if (!bus_deferred_message_replace(deferred_message, deferred_message_receive))
++ {
++ /* failed to replace deferred message (due to oom). Set it to rejected */
++ deferred_message->response = BUS_RESULT_FALSE;
++ }
++ }
++ }
++
++ bus_connection_dispatch_deferred(deferred_message->proposed_recipient);
++}
++
++static void
++queue_deferred_message_cancel_transaction_hook (void *data)
++{
++ BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
++ bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
++}
++
++
++dbus_bool_t
++bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
++ BusTransaction *transaction,
++ dbus_bool_t full_dispatch,
++ dbus_bool_t prepend)
++{
++ _dbus_assert(deferred_message != NULL);
++ _dbus_assert(deferred_message->proposed_recipient != NULL);
++
++ if (!bus_connection_queue_deferred_message(deferred_message->proposed_recipient,
++ deferred_message, prepend))
++ return FALSE;
++
++ if (!bus_transaction_add_cancel_hook(transaction, queue_deferred_message_cancel_transaction_hook,
++ deferred_message, NULL))
++ {
++ bus_connection_remove_deferred_message(deferred_message->proposed_recipient, deferred_message);
++ return FALSE;
++ }
++ deferred_message->response_callback = bus_check_queued_message_reply_callback;
++ deferred_message->full_dispatch = full_dispatch;
++
++ return TRUE;
++}
++
++static void
+ deferred_message_free_function(void *data)
+ {
+ BusDeferredMessage *deferred_message = (BusDeferredMessage *)data;
+@@ -159,6 +245,20 @@ bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message)
+ deferred_message->response_callback = bus_check_enable_dispatch_callback;
+ }
+
++void
++bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
++ dbus_bool_t requested_reply,
++ int matched_rules,
++ const char *privilege)
++{
++ _dbus_assert(deferred_message != NULL);
++
++ deferred_message->requested_reply = requested_reply;
++ deferred_message->matched_rules = matched_rules;
++ deferred_message->privilege = privilege;
++}
++
++
+ #ifdef DBUS_ENABLE_EMBEDDED_TESTS
+ dbus_bool_t (*bus_check_test_override) (DBusConnection *connection,
+ const char *privilege);
+@@ -257,6 +357,9 @@ BusDeferredMessage *bus_deferred_message_new (DBusMessage *message,
+ deferred_message->addressed_recipient = addressed_recipient != NULL ? dbus_connection_ref(addressed_recipient) : NULL;
+ deferred_message->proposed_recipient = proposed_recipient != NULL ? dbus_connection_ref(proposed_recipient) : NULL;
+ deferred_message->message = dbus_message_ref(message);
++ deferred_message->requested_reply = FALSE;
++ deferred_message->matched_rules = 0;
++ deferred_message->privilege = NULL;
+ deferred_message->response = response;
+ deferred_message->status = 0;
+ deferred_message->full_dispatch = FALSE;
+@@ -293,12 +396,215 @@ bus_deferred_message_unref (BusDeferredMessage *deferred_message)
+ }
+ }
+
++dbus_bool_t
++bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message, DBusError *error)
++{
++ BusContext *context = bus_connection_get_context(deferred_message->proposed_recipient);
++
++ return bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
++ deferred_message->sender, deferred_message->message, deferred_message->requested_reply,
++ error);
++}
++
++dbus_bool_t
++bus_deferred_message_expect_method_reply(BusDeferredMessage *deferred_message, BusTransaction *transaction, DBusError *error)
++{
++ int type = dbus_message_get_type(deferred_message->message);
++ if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
++ deferred_message->sender &&
++ deferred_message->addressed_recipient &&
++ deferred_message->addressed_recipient == deferred_message->proposed_recipient && /* not eavesdropping */
++ !bus_connections_expect_reply (bus_connection_get_connections (deferred_message->sender),
++ transaction,
++ deferred_message->sender, deferred_message->addressed_recipient,
++ deferred_message->message, error))
++ {
++ _dbus_verbose ("Failed to record reply expectation or problem with the message expecting a reply\n");
++ return FALSE;
++ }
++ return TRUE;
++}
++
++void
++bus_deferred_message_create_error(BusDeferredMessage *deferred_message,
++ const char *error_message, DBusError *error)
++{
++ BusContext *context;
++ _dbus_assert (deferred_message->status == 0 && deferred_message->response == BUS_RESULT_FALSE);
++
++ if (deferred_message->sender == NULL)
++ return; /* error won't be sent to bus driver anyway */
++
++ context = bus_connection_get_context(deferred_message->sender);
++ bus_context_complain_about_message(context, DBUS_ERROR_ACCESS_DENIED, "Rejected message",
++ deferred_message->matched_rules, deferred_message->message, deferred_message->sender,
++ deferred_message->proposed_recipient, deferred_message->requested_reply, FALSE,
++ deferred_message->privilege, error);
++}
++
++BusResult
++bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
++{
++ BusContext *context = bus_connection_get_context (deferred_message->proposed_recipient);
++ BusTransaction *transaction = bus_transaction_new (context);
++ BusResult result = BUS_RESULT_TRUE;
++ DBusError error;
++
++ if (transaction == NULL)
++ {
++ return BUS_RESULT_FALSE;
++ }
++
++ dbus_error_init(&error);
++
++ if (!deferred_message->full_dispatch)
++ {
++ result = deferred_message->response;
++ if (result == BUS_RESULT_TRUE)
++ {
++ if (!bus_context_check_recipient_message_limits(context, deferred_message->proposed_recipient,
++ deferred_message->sender, deferred_message->message, deferred_message->requested_reply, &error))
++ result = BUS_RESULT_FALSE;
++ }
++ else if (result == BUS_RESULT_LATER)
++ {
++ BusDeferredMessage *deferred_message2;
++ result = bus_context_check_security_policy (context, transaction,
++ deferred_message->sender,
++ deferred_message->addressed_recipient,
++ deferred_message->proposed_recipient,
++ deferred_message->message, NULL,
++ &deferred_message2);
++
++ if (result == BUS_RESULT_LATER)
++ {
++ /* prepend at recipient */
++ if (!bus_deferred_message_queue_at_recipient(deferred_message2, transaction,
++ FALSE, TRUE))
++ result = BUS_RESULT_FALSE;
++ }
++ }
++
++ /* silently drop messages on access denial */
++ if (result == BUS_RESULT_TRUE)
++ {
++ if (!bus_transaction_send (transaction, deferred_message->proposed_recipient, deferred_message->message, TRUE))
++ result = BUS_RESULT_FALSE;
++ }
++
++ bus_transaction_execute_and_free(transaction);
++
++ goto out;
++ }
++
++ /* do not attempt to send message if sender has disconnected */
++ if (deferred_message->sender != NULL && !bus_connection_is_active(deferred_message->sender))
++ {
++ bus_transaction_cancel_and_free(transaction);
++ result = BUS_RESULT_FALSE;
++ goto out;
++ }
++
++ result = bus_dispatch_matches(transaction, deferred_message->sender,
++ deferred_message->addressed_recipient, deferred_message->message, deferred_message, &error);
++
++ if (result == BUS_RESULT_LATER)
++ {
++ /* Message deferring was already done in bus_dispatch_matches */
++ bus_transaction_cancel_and_free(transaction);
++ goto out;
++ }
++
++ /* this part is a copy & paste from bus_dispatch function. Probably can be moved to a function */
++ if (dbus_error_is_set (&error))
++ {
++ if (!dbus_connection_get_is_connected (deferred_message->sender))
++ {
++ /* If we disconnected it, we won't bother to send it any error
++ * messages.
++ */
++ _dbus_verbose ("Not sending error to connection we disconnected\n");
++ }
++ else if (dbus_error_has_name (&error, DBUS_ERROR_NO_MEMORY))
++ {
++ bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
++
++ /* cancel transaction due to OOM */
++ if (transaction != NULL)
++ {
++ bus_transaction_cancel_and_free (transaction);
++ transaction = NULL;
++ }
++ }
++ else
++ {
++ /* Try to send the real error, if no mem to do that, send
++ * the OOM error
++ */
++ _dbus_assert (transaction != NULL);
++ if (!bus_transaction_send_error_reply (transaction, deferred_message->sender,
++ &error, deferred_message->message))
++ {
++ bus_connection_send_oom_error (deferred_message->sender, deferred_message->message);
++
++ /* cancel transaction due to OOM */
++ if (transaction != NULL)
++ {
++ bus_transaction_cancel_and_free (transaction);
++ transaction = NULL;
++ }
++ }
++ }
++ }
++
++ if (transaction != NULL)
++ {
++ bus_transaction_execute_and_free (transaction);
++ }
++
++out:
++ dbus_error_free(&error);
++
++ return result;
++}
++
++dbus_bool_t
++bus_deferred_message_replace (BusDeferredMessage *old_message, BusDeferredMessage *new_message)
++{
++ if (bus_connection_replace_deferred_message(old_message->proposed_recipient,
++ old_message, new_message))
++ {
++ new_message->response_callback = old_message->response_callback;
++ new_message->full_dispatch = old_message->full_dispatch;
++ return TRUE;
++ }
++ return FALSE;
++}
++
++dbus_bool_t
++bus_deferred_message_waits_for_check(BusDeferredMessage *deferred_message)
++{
++ return deferred_message->status != 0;
++}
++
++DBusConnection *
++bus_deferred_message_get_recipient(BusDeferredMessage *deferred_message)
++{
++ return deferred_message->proposed_recipient;
++}
++
+ BusDeferredMessageStatus
+ bus_deferred_message_get_status (BusDeferredMessage *deferred_message)
+ {
+ return deferred_message->status;
+ }
+
++BusResult
++bus_deferred_message_get_response (BusDeferredMessage *deferred_message)
++{
++ return deferred_message->response;
++}
++
+ void
+ bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
+ BusResult result)
+@@ -308,3 +614,4 @@ bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
+ deferred_message->response_callback(deferred_message, result);
+ }
+ }
++
+diff --git a/bus/check.h b/bus/check.h
+index f381789..3c6b2a1 100644
+--- a/bus/check.h
++++ b/bus/check.h
+@@ -64,12 +64,37 @@ BusDeferredMessage *bus_deferred_message_new (DBusMessage *messag
+
+ BusDeferredMessage *bus_deferred_message_ref (BusDeferredMessage *deferred_message);
+ void bus_deferred_message_unref (BusDeferredMessage *deferred_message);
++BusResult bus_deferred_message_dispatch (BusDeferredMessage *deferred_message);
++dbus_bool_t bus_deferred_message_waits_for_check (BusDeferredMessage *deferred_message);
++DBusConnection *bus_deferred_message_get_recipient (BusDeferredMessage *deferred_message);
+ void bus_deferred_message_response_received (BusDeferredMessage *deferred_message,
+ BusResult result);
++dbus_bool_t bus_deferred_message_queue_at_recipient (BusDeferredMessage *deferred_message,
++ BusTransaction *transaction,
++ dbus_bool_t full_dispatch,
++ dbus_bool_t prepend);
++dbus_bool_t bus_deferred_message_replace (BusDeferredMessage *old_message,
++ BusDeferredMessage *new_message);
+ void bus_deferred_message_disable_sender (BusDeferredMessage *deferred_message);
++BusResult bus_deferred_message_get_response (BusDeferredMessage *deferred_message);
+
+ BusDeferredMessageStatus bus_deferred_message_get_status (BusDeferredMessage *deferred_message);
+
++
++dbus_bool_t bus_deferred_message_expect_method_reply (BusDeferredMessage *deferred_message,
++ BusTransaction *transaction,
++ DBusError *error);
++void bus_deferred_message_create_error (BusDeferredMessage *deferred_message,
++ const char *error_message,
++ DBusError *error);
++void bus_deferred_message_set_policy_check_info (BusDeferredMessage *deferred_message,
++ dbus_bool_t requested_reply,
++ int matched_rules,
++ const char *privilege);
++dbus_bool_t bus_deferred_message_check_message_limits (BusDeferredMessage *deferred_message,
++ DBusError *error);
++
++
+ #ifdef DBUS_ENABLE_EMBEDDED_TESTS
+ extern dbus_bool_t (*bus_check_test_override) (DBusConnection *connection,
+ const char *privilege);
+diff --git a/bus/connection.c b/bus/connection.c
+index a6d87e5..d2ebe82 100644
+--- a/bus/connection.c
++++ b/bus/connection.c
+@@ -30,10 +30,12 @@
+ #include "signals.h"
+ #include "expirelist.h"
+ #include "selinux.h"
++#include "check.h"
+ #include <dbus/dbus-list.h>
+ #include <dbus/dbus-hash.h>
+ #include <dbus/dbus-timeout.h>
+ #include <dbus/dbus-connection-internal.h>
++#include <dbus/dbus-message-internal.h>
+ #ifdef DBUS_ENABLE_CYNARA
+ #include <stdlib.h>
+ #include <cynara-session.h>
+@@ -95,6 +97,7 @@ typedef struct
+ DBusMessage *oom_message;
+ DBusPreallocatedSend *oom_preallocated;
+ BusClientPolicy *policy;
++ DBusList *deferred_messages; /**< Queue of messages deferred due to pending policy check */
+
+ char *cached_loginfo_string;
+ BusSELinuxID *selinux_id;
+@@ -256,6 +259,8 @@ bus_connection_disconnected (DBusConnection *connection)
+ bus_transaction_execute_and_free (transaction);
+ }
+
++ bus_connection_clear_deferred_messages(connection);
++
+ bus_dispatch_remove_connection (connection);
+
+ /* no more watching */
+@@ -2132,6 +2137,7 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
+ DBusMessage *message)
+ {
+ BusResult res;
++ BusDeferredMessage *deferred_message;
+ /* We have to set the sender to the driver, and have
+ * to check security policy since it was not done in
+ * dispatch.c
+@@ -2163,23 +2169,25 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
+ res = bus_context_check_security_policy (bus_transaction_get_context (transaction),
+ transaction,
+ NULL, connection, connection, message, NULL,
+- NULL);
++ &deferred_message);
+
+ if (res == BUS_RESULT_FALSE)
+ return TRUE;
+ else if (res == BUS_RESULT_LATER)
+ {
+- _dbus_verbose ("Cannot delay sending message from bus driver, dropping it\n");
+- return TRUE;
++ if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
++ return FALSE;
++ return TRUE; /* pretend to have sent it */
+ }
+
+- return bus_transaction_send (transaction, connection, message);
++ return bus_transaction_send (transaction, connection, message, FALSE);
+ }
+
+ dbus_bool_t
+ bus_transaction_send (BusTransaction *transaction,
+ DBusConnection *connection,
+- DBusMessage *message)
++ DBusMessage *message,
++ dbus_bool_t deferred_dispatch)
+ {
+ MessageToSend *to_send;
+ BusConnectionData *d;
+@@ -2205,7 +2213,28 @@ bus_transaction_send (BusTransaction *transaction,
+
+ d = BUS_CONNECTION_DATA (connection);
+ _dbus_assert (d != NULL);
+-
++
++ if (!deferred_dispatch && d->deferred_messages != NULL)
++ {
++ BusDeferredMessage *deferred_message;
++ dbus_bool_t success;
++ /* sender and addressed recipient are not required at this point as we only need to send message
++ * to a single recipient without performing policy check. */
++ deferred_message = bus_deferred_message_new (message,
++ NULL,
++ NULL,
++ connection,
++ BUS_RESULT_TRUE);
++ if (deferred_message == NULL)
++ return FALSE;
++
++ success = bus_deferred_message_queue_at_recipient(deferred_message, transaction,
++ FALSE, FALSE);
++ bus_deferred_message_unref(deferred_message);
++
++ return success;
++ }
++
+ to_send = dbus_new (MessageToSend, 1);
+ if (to_send == NULL)
+ {
+@@ -2457,6 +2486,131 @@ bus_transaction_add_cancel_hook (BusTransaction *transaction,
+ return TRUE;
+ }
+
++void
++bus_connection_dispatch_deferred (DBusConnection *connection)
++{
++ BusDeferredMessage *message;
++
++ _dbus_return_if_fail (connection != NULL);
++
++ while ((message = bus_connection_pop_deferred_message(connection)) != NULL)
++ {
++ bus_deferred_message_dispatch(message);
++ bus_deferred_message_unref(message);
++ }
++}
++
++dbus_bool_t
++bus_connection_has_deferred_messages (DBusConnection *connection)
++{
++ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
++ return d->deferred_messages != NULL ? TRUE : FALSE;
++}
++
++dbus_bool_t
++bus_connection_queue_deferred_message (DBusConnection *connection,
++ BusDeferredMessage *message,
++ dbus_bool_t prepend)
++{
++ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
++ dbus_bool_t success;
++ if (prepend)
++ success = _dbus_list_prepend(&d->deferred_messages, message);
++ else
++ success = _dbus_list_append(&d->deferred_messages, message);
++
++ if (success)
++ {
++ bus_deferred_message_ref(message);
++ return TRUE;
++ }
++
++ return FALSE;
++}
++
++dbus_bool_t
++bus_connection_replace_deferred_message (DBusConnection *connection,
++ BusDeferredMessage *oldMessage,
++ BusDeferredMessage *newMessage)
++{
++ DBusList *link;
++ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
++
++ link = _dbus_list_find_first(&d->deferred_messages, oldMessage);
++ if (link == NULL)
++ return FALSE;
++
++ if (!_dbus_list_insert_after(&d->deferred_messages, link, newMessage))
++ return FALSE;
++
++ bus_deferred_message_ref(newMessage);
++ _dbus_list_remove_link(&d->deferred_messages, link);
++ bus_deferred_message_unref(oldMessage);
++ return TRUE;
++}
++
++BusDeferredMessage *
++bus_connection_pop_deferred_message (DBusConnection *connection)
++{
++ DBusList *link;
++ BusDeferredMessage *message;
++ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
++
++ link =_dbus_list_get_first_link(&d->deferred_messages);
++ if (link != NULL)
++ {
++ message = link->data;
++ if (!bus_deferred_message_waits_for_check(message))
++ {
++ _dbus_list_remove_link(&d->deferred_messages, link);
++ return message;
++ }
++ }
++
++ return NULL;
++}
++
++dbus_bool_t
++bus_connection_putback_deferred_message (DBusConnection *connection, BusDeferredMessage *message)
++{
++ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
++ if (_dbus_list_prepend(&d->deferred_messages, message))
++ {
++ return TRUE;
++ }
++ return FALSE;
++}
++
++void
++bus_connection_clear_deferred_messages (DBusConnection *connection)
++{
++ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
++ DBusList *link;
++ DBusList *next;
++ BusDeferredMessage *message;
++
++ link =_dbus_list_get_first_link(&d->deferred_messages);
++ while (link != NULL)
++ {
++ next = _dbus_list_get_next_link (&d->deferred_messages, link);
++ message = link->data;
++
++ bus_deferred_message_unref(message);
++ _dbus_list_remove_link(&d->deferred_messages, link);
++
++ link = next;
++ }
++}
++
++void
++bus_connection_remove_deferred_message (DBusConnection *connection,
++ BusDeferredMessage *message)
++{
++ BusConnectionData *d = BUS_CONNECTION_DATA(connection);
++ if (_dbus_list_remove(&d->deferred_messages, message))
++ bus_deferred_message_unref(message);
++}
++
+ int
+ bus_connections_get_n_active (BusConnections *connections)
+ {
+diff --git a/bus/connection.h b/bus/connection.h
+index 7433746..8d49b25 100644
+--- a/bus/connection.h
++++ b/bus/connection.h
+@@ -82,6 +82,22 @@ dbus_bool_t bus_connection_preallocate_oom_error (DBusConnection *connection);
+ void bus_connection_send_oom_error (DBusConnection *connection,
+ DBusMessage *in_reply_to);
+
++dbus_bool_t bus_connection_has_deferred_messages (DBusConnection *connection);
++dbus_bool_t bus_connection_queue_deferred_message (DBusConnection *connection,
++ BusDeferredMessage *message,
++ dbus_bool_t prepend);
++BusDeferredMessage *bus_connection_pop_deferred_message (DBusConnection *connection);
++dbus_bool_t bus_connection_putback_deferred_message (DBusConnection *connection,
++ BusDeferredMessage *message);
++void bus_connection_remove_deferred_message (DBusConnection *connection,
++ BusDeferredMessage *message);
++dbus_bool_t bus_connection_replace_deferred_message (DBusConnection *connection,
++ BusDeferredMessage *oldMessage,
++ BusDeferredMessage *newMessage);
++void bus_connection_dispatch_deferred (DBusConnection *connection);
++void bus_connection_clear_deferred_messages (DBusConnection *connection);
++
++
+ /* called by signals.c */
+ dbus_bool_t bus_connection_add_match_rule (DBusConnection *connection,
+ BusMatchRule *rule);
+@@ -129,7 +145,8 @@ BusTransaction* bus_transaction_new (BusContext *
+ BusContext* bus_transaction_get_context (BusTransaction *transaction);
+ dbus_bool_t bus_transaction_send (BusTransaction *transaction,
+ DBusConnection *connection,
+- DBusMessage *message);
++ DBusMessage *message,
++ dbus_bool_t deferred_dispatch);
+ dbus_bool_t bus_transaction_send_from_driver (BusTransaction *transaction,
+ DBusConnection *connection,
+ DBusMessage *message);
+diff --git a/bus/dispatch.c b/bus/dispatch.c
+index 6b0eadc..9972e76 100644
+--- a/bus/dispatch.c
++++ b/bus/dispatch.c
+@@ -33,8 +33,10 @@
+ #include "utils.h"
+ #include "bus.h"
+ #include "signals.h"
++#include "dispatch.h"
+ #include "test.h"
+ #include <dbus/dbus-internals.h>
++#include <dbus/dbus-connection-internal.h>
+ #include <dbus/dbus-misc.h>
+ #include <string.h>
+
+@@ -63,16 +65,26 @@ send_one_message (DBusConnection *connection,
+ result = bus_context_check_security_policy (context, transaction, sender, addressed_recipient,
+ connection, message, NULL, &deferred_message);
+
+- if (result != BUS_RESULT_TRUE)
++ if (result == BUS_RESULT_FALSE)
+ return TRUE; /* silently don't send it */
+
+ if (dbus_message_contains_unix_fds(message) &&
+ !dbus_connection_can_send_type(connection, DBUS_TYPE_UNIX_FD))
+ return TRUE; /* silently don't send it */
+
++ if (result == BUS_RESULT_LATER)
++ {
++ if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, FALSE, FALSE))
++ {
++ BUS_SET_OOM (error);
++ return FALSE;
++ }
++ return TRUE; /* pretend to have sent it */
++ }
++
+ if (!bus_transaction_send (transaction,
+ connection,
+- message))
++ message, FALSE))
+ {
+ BUS_SET_OOM (error);
+ return FALSE;
+@@ -82,11 +94,12 @@ send_one_message (DBusConnection *connection,
+ }
+
+ BusResult
+-bus_dispatch_matches (BusTransaction *transaction,
+- DBusConnection *sender,
+- DBusConnection *addressed_recipient,
+- DBusMessage *message,
+- DBusError *error)
++bus_dispatch_matches (BusTransaction *transaction,
++ DBusConnection *sender,
++ DBusConnection *addressed_recipient,
++ DBusMessage *message,
++ BusDeferredMessage *dispatched_deferred_message,
++ DBusError *error)
+ {
+ DBusError tmp_error;
+ BusConnections *connections;
+@@ -110,17 +123,78 @@ bus_dispatch_matches (BusTransaction *transaction,
+ /* First, send the message to the addressed_recipient, if there is one. */
+ if (addressed_recipient != NULL)
+ {
+- BusResult res;
+- res = bus_context_check_security_policy (context, transaction,
+- sender, addressed_recipient,
+- addressed_recipient,
+- message, error,
+- &deferred_message);
+- if (res == BUS_RESULT_FALSE)
++ BusResult result;
++ /* To maintain message order message needs to be appended at the recipient if there are already
++ * deferred messages and we are not doing deferred dispatch
++ */
++ if (dispatched_deferred_message == NULL && bus_connection_has_deferred_messages(addressed_recipient))
++ {
++ deferred_message = bus_deferred_message_new(message, sender,
++ addressed_recipient, addressed_recipient, BUS_RESULT_LATER);
++
++ if (deferred_message == NULL)
++ {
++ BUS_SET_OOM(error);
++ return BUS_RESULT_FALSE;
++ }
++
++ if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
++ {
++ bus_deferred_message_unref(deferred_message);
++ BUS_SET_OOM(error);
++ return BUS_RESULT_FALSE;
++ }
++
++ bus_deferred_message_unref(deferred_message);
++ return BUS_RESULT_TRUE; /* pretend to have sent it */
++ }
++
++ if (dispatched_deferred_message != NULL)
++ {
++ result = bus_deferred_message_get_response(dispatched_deferred_message);
++ if (result == BUS_RESULT_TRUE)
++ {
++ /* if we know the result of policy check we still need to check if message limits
++ * are not exceeded. It is also required to add entry in expected replies list if
++ * this is a method call
++ */
++ if (!bus_deferred_message_check_message_limits(dispatched_deferred_message, error))
++ return BUS_RESULT_FALSE;
++
++ if (!bus_deferred_message_expect_method_reply(dispatched_deferred_message, transaction, error))
++ return BUS_RESULT_FALSE;
++ }
++ else if (result == BUS_RESULT_FALSE)
++ {
++ bus_deferred_message_create_error(dispatched_deferred_message, "Rejected message", error);
++ return BUS_RESULT_FALSE;
++ }
++ }
++ else
++ result = BUS_RESULT_LATER;
++
++ if (result == BUS_RESULT_LATER)
++ result = bus_context_check_security_policy(context, transaction,
++ sender, addressed_recipient, addressed_recipient, message, error,
++ &deferred_message);
++
++ if (result == BUS_RESULT_FALSE)
+ return BUS_RESULT_FALSE;
+- else if (res == BUS_RESULT_LATER)
++ else if (result == BUS_RESULT_LATER)
+ {
+ BusDeferredMessageStatus status;
++
++ if (dispatched_deferred_message != NULL)
++ {
++ /* for deferred dispatch prepend message at the recipient */
++ if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, TRUE))
++ {
++ BUS_SET_OOM(error);
++ return BUS_RESULT_FALSE;
++ }
++ return BUS_RESULT_TRUE; /* pretend to have sent it */
++ }
++
+ status = bus_deferred_message_get_status(deferred_message);
+
+ if (status & BUS_DEFERRED_MESSAGE_CHECK_SEND)
+@@ -131,13 +205,18 @@ bus_dispatch_matches (BusTransaction *transaction,
+ }
+ else if (status & BUS_DEFERRED_MESSAGE_CHECK_RECEIVE)
+ {
+- dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+- "Rejecting message because time is needed to check security policy");
+- return BUS_RESULT_FALSE;
++ /* receive rule result not available - queue message at the recipient */
++ if (!bus_deferred_message_queue_at_recipient(deferred_message, transaction, TRUE, FALSE))
++ {
++ BUS_SET_OOM(error);
++ return BUS_RESULT_FALSE;
++ }
++
++ return BUS_RESULT_TRUE; /* pretend to have sent it */
+ }
+ else
+ {
+- _dbus_verbose("deferred message has no status field set to send or receive unexpectedly\n");
++ _dbus_verbose("deferred message has no status field set unexpectedly\n");
+ return BUS_RESULT_FALSE;
+ }
+ }
+@@ -154,7 +233,8 @@ bus_dispatch_matches (BusTransaction *transaction,
+ }
+
+ /* Dispatch the message */
+- if (!bus_transaction_send (transaction, addressed_recipient, message))
++ if (!bus_transaction_send(transaction, addressed_recipient, message,
++ dispatched_deferred_message != NULL ? TRUE : FALSE))
+ {
+ BUS_SET_OOM (error);
+ return BUS_RESULT_FALSE;
+@@ -385,7 +465,7 @@ bus_dispatch (DBusConnection *connection,
+ * match rules.
+ */
+ if (BUS_RESULT_LATER == bus_dispatch_matches (transaction, connection, addressed_recipient,
+- message, &error))
++ message, NULL, &error))
+ {
+ /* Roll back and dispatch the message once the policy result is available */
+ bus_transaction_cancel_and_free (transaction);
+diff --git a/bus/dispatch.h b/bus/dispatch.h
+index afba6a2..f6102e8 100644
+--- a/bus/dispatch.h
++++ b/bus/dispatch.h
+@@ -29,10 +29,11 @@
+
+ dbus_bool_t bus_dispatch_add_connection (DBusConnection *connection);
+ void bus_dispatch_remove_connection (DBusConnection *connection);
+-BusResult bus_dispatch_matches (BusTransaction *transaction,
+- DBusConnection *sender,
+- DBusConnection *recipient,
+- DBusMessage *message,
+- DBusError *error);
++BusResult bus_dispatch_matches (BusTransaction *transaction,
++ DBusConnection *sender,
++ DBusConnection *recipient,
++ DBusMessage *message,
++ BusDeferredMessage *dispatched_deferred_message,
++ DBusError *error);
+
+ #endif /* BUS_DISPATCH_H */
+diff --git a/bus/driver.c b/bus/driver.c
+index 4dbce3d..2fb1385 100644
+--- a/bus/driver.c
++++ b/bus/driver.c
+@@ -130,7 +130,7 @@ bus_driver_send_service_owner_changed (const char *service_name,
+
+ _dbus_assert (dbus_message_has_signature (message, "sss"));
+
+- res = bus_dispatch_matches (transaction, NULL, NULL, message, error);
++ res = bus_dispatch_matches (transaction, NULL, NULL, message, NULL, error);
+ if (res == BUS_RESULT_TRUE)
+ retval = TRUE;
+ else if (res == BUS_RESULT_FALSE)
+diff --git a/bus/policy.c b/bus/policy.c
+index ec888df..448147f 100644
+--- a/bus/policy.c
++++ b/bus/policy.c
+@@ -1071,6 +1071,9 @@ bus_client_policy_check_can_send (DBusConnection *sender,
+
+ result = bus_check_privilege(check, message, sender, addressed_recipient, receiver,
+ privilege, BUS_DEFERRED_MESSAGE_CHECK_SEND, deferred_message);
++ if (result == BUS_RESULT_LATER && deferred_message != NULL)
++ bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
++ *toggles, privilege);
+ }
+ else
+ privilege = NULL;
+@@ -1305,6 +1308,9 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
+
+ result = bus_check_privilege(check, message, sender, addressed_recipient, proposed_recipient,
+ privilege, BUS_DEFERRED_MESSAGE_CHECK_RECEIVE, deferred_message);
++ if (result == BUS_RESULT_LATER && deferred_message != NULL)
++ bus_deferred_message_set_policy_check_info(*deferred_message, requested_reply,
++ *toggles, privilege);
+ }
+ else
+ privilege = NULL;
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/dbus/dbus-cynara/0007-Add-own-rule-result-unavailability-handling.patch b/meta-security/recipes-core/dbus/dbus-cynara/0007-Add-own-rule-result-unavailability-handling.patch
new file mode 100644
index 000000000..e1b1e62f1
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-cynara/0007-Add-own-rule-result-unavailability-handling.patch
@@ -0,0 +1,1142 @@
+From 35ef89cd6777ea2430077fc621d21bd01df92349 Mon Sep 17 00:00:00 2001
+From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
+Date: Thu, 27 Nov 2014 11:26:21 +0100
+Subject: [PATCH 7/8] Add own rule result unavailability handling
+
+Own rule result unavailability is handled like send rules - dispatching
+messages from the sender is blocked and resumed when result becomes
+available.
+
+Handler of "RequestName" method needs to return BUS_RESULT_LATER when
+policy result is not known therefore its return type is modified.
+Since bus message handlers are put into function pointer array other
+message handler function singatures are also affected.
+
+Change-Id: I4c2cbd4585e41fccd8a30f825a8f0d342ab56755
+---
+ bus/dispatch.c | 11 ++-
+ bus/driver.c | 227 ++++++++++++++++++++++++++++++---------------------------
+ bus/driver.h | 2 +-
+ bus/policy.c | 51 ++++++++++---
+ bus/policy.h | 6 +-
+ bus/services.c | 26 +++++--
+ bus/services.h | 3 +-
+ bus/stats.c | 16 ++--
+ 8 files changed, 204 insertions(+), 138 deletions(-)
+
+diff --git a/bus/dispatch.c b/bus/dispatch.c
+index 9972e76..d3b970f 100644
+--- a/bus/dispatch.c
++++ b/bus/dispatch.c
+@@ -404,8 +404,17 @@ bus_dispatch (DBusConnection *connection,
+ }
+
+ _dbus_verbose ("Giving message to %s\n", DBUS_SERVICE_DBUS);
+- if (!bus_driver_handle_message (connection, transaction, message, &error))
++ res = bus_driver_handle_message (connection, transaction, message, &error);
++ if (res == BUS_RESULT_FALSE)
+ goto out;
++ else if (res == BUS_RESULT_LATER)
++ {
++ /* connection has been disabled in message handler */
++ bus_transaction_cancel_and_free (transaction);
++ transaction = NULL;
++ result = DBUS_HANDLER_RESULT_LATER;
++ goto out;
++ }
+ }
+ else if (!bus_connection_is_active (connection)) /* clients must talk to bus driver first */
+ {
+diff --git a/bus/driver.c b/bus/driver.c
+index 2fb1385..9708f49 100644
+--- a/bus/driver.c
++++ b/bus/driver.c
+@@ -297,7 +297,7 @@ create_unique_client_name (BusRegistry *registry,
+ return TRUE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_hello (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -305,7 +305,7 @@ bus_driver_handle_hello (DBusConnection *connection,
+ {
+ DBusString unique_name;
+ BusService *service;
+- dbus_bool_t retval;
++ BusResult retval;
+ BusRegistry *registry;
+ BusConnections *connections;
+
+@@ -316,7 +316,7 @@ bus_driver_handle_hello (DBusConnection *connection,
+ /* We already handled an Hello message for this connection. */
+ dbus_set_error (error, DBUS_ERROR_FAILED,
+ "Already handled an Hello message");
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ /* Note that when these limits are exceeded we don't disconnect the
+@@ -330,16 +330,16 @@ bus_driver_handle_hello (DBusConnection *connection,
+ error))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ if (!_dbus_string_init (&unique_name))
+ {
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+- retval = FALSE;
++ retval = BUS_RESULT_FALSE;
+
+ registry = bus_connection_get_registry (connection);
+
+@@ -372,7 +372,7 @@ bus_driver_handle_hello (DBusConnection *connection,
+ goto out_0;
+
+ _dbus_assert (bus_connection_is_active (connection));
+- retval = TRUE;
++ retval = BUS_RESULT_TRUE;
+
+ out_0:
+ _dbus_string_free (&unique_name);
+@@ -424,7 +424,7 @@ bus_driver_send_welcome_message (DBusConnection *connection,
+ }
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_list_services (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -446,14 +446,14 @@ bus_driver_handle_list_services (DBusConnection *connection,
+ if (reply == NULL)
+ {
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ if (!bus_registry_list_services (registry, &services, &len))
+ {
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ dbus_message_iter_init_append (reply, &iter);
+@@ -465,7 +465,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
+ dbus_free_string_array (services);
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ {
+@@ -477,7 +477,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
+ dbus_free_string_array (services);
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+ }
+
+@@ -490,7 +490,7 @@ bus_driver_handle_list_services (DBusConnection *connection,
+ dbus_free_string_array (services);
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+ ++i;
+ }
+@@ -501,23 +501,23 @@ bus_driver_handle_list_services (DBusConnection *connection,
+ {
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
+ {
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+ else
+ {
+ dbus_message_unref (reply);
+- return TRUE;
++ return BUS_RESULT_TRUE;
+ }
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_list_activatable_services (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -539,14 +539,14 @@ bus_driver_handle_list_activatable_services (DBusConnection *connection,
+ if (reply == NULL)
+ {
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ if (!bus_activation_list_services (activation, &services, &len))
+ {
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ dbus_message_iter_init_append (reply, &iter);
+@@ -558,7 +558,7 @@ bus_driver_handle_list_activatable_services (DBusConnection *connection,
+ dbus_free_string_array (services);
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ {
+@@ -570,7 +570,7 @@ bus_driver_handle_list_activatable_services (DBusConnection *connection,
+ dbus_free_string_array (services);
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+ }
+
+@@ -583,7 +583,7 @@ bus_driver_handle_list_activatable_services (DBusConnection *connection,
+ dbus_free_string_array (services);
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+ ++i;
+ }
+@@ -594,23 +594,23 @@ bus_driver_handle_list_activatable_services (DBusConnection *connection,
+ {
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ if (!bus_transaction_send_from_driver (transaction, connection, reply))
+ {
+ dbus_message_unref (reply);
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+ else
+ {
+ dbus_message_unref (reply);
+- return TRUE;
++ return BUS_RESULT_TRUE;
+ }
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_acquire_service (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -621,7 +621,8 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
+ const char *name;
+ dbus_uint32_t service_reply;
+ dbus_uint32_t flags;
+- dbus_bool_t retval;
++ BusResult retval;
++ BusResult res;
+ BusRegistry *registry;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+@@ -632,20 +633,24 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_UINT32, &flags,
+ DBUS_TYPE_INVALID))
+- return FALSE;
++ return BUS_RESULT_FALSE;
+
+ _dbus_verbose ("Trying to own name %s with flags 0x%x\n", name, flags);
+
+- retval = FALSE;
++ retval = BUS_RESULT_FALSE;
+ reply = NULL;
+
+ _dbus_string_init_const (&service_name, name);
+
+- if (!bus_registry_acquire_service (registry, connection,
+- &service_name, flags,
+- &service_reply, transaction,
+- error))
+- goto out;
++ res = bus_registry_acquire_service (registry, connection, message,
++ &service_name, flags,
++ &service_reply, transaction,
++ error);
++ if (res != BUS_RESULT_TRUE)
++ {
++ retval = res;
++ goto out;
++ }
+
+ reply = dbus_message_new_method_return (message);
+ if (reply == NULL)
+@@ -666,7 +671,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
+ goto out;
+ }
+
+- retval = TRUE;
++ retval = BUS_RESULT_TRUE;
+
+ out:
+ if (reply)
+@@ -674,7 +679,7 @@ bus_driver_handle_acquire_service (DBusConnection *connection,
+ return retval;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_release_service (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -684,7 +689,7 @@ bus_driver_handle_release_service (DBusConnection *connection,
+ DBusString service_name;
+ const char *name;
+ dbus_uint32_t service_reply;
+- dbus_bool_t retval;
++ BusResult retval;
+ BusRegistry *registry;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+@@ -694,11 +699,11 @@ bus_driver_handle_release_service (DBusConnection *connection,
+ if (!dbus_message_get_args (message, error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+- return FALSE;
++ return BUS_RESULT_FALSE;
+
+ _dbus_verbose ("Trying to release name %s\n", name);
+
+- retval = FALSE;
++ retval = BUS_RESULT_FALSE;
+ reply = NULL;
+
+ _dbus_string_init_const (&service_name, name);
+@@ -727,7 +732,7 @@ bus_driver_handle_release_service (DBusConnection *connection,
+ goto out;
+ }
+
+- retval = TRUE;
++ retval = BUS_RESULT_TRUE;
+
+ out:
+ if (reply)
+@@ -735,7 +740,7 @@ bus_driver_handle_release_service (DBusConnection *connection,
+ return retval;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_service_exists (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -746,7 +751,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
+ BusService *service;
+ dbus_bool_t service_exists;
+ const char *name;
+- dbus_bool_t retval;
++ BusResult retval;
+ BusRegistry *registry;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+@@ -756,9 +761,9 @@ bus_driver_handle_service_exists (DBusConnection *connection,
+ if (!dbus_message_get_args (message, error,
+ DBUS_TYPE_STRING, &name,
+ DBUS_TYPE_INVALID))
+- return FALSE;
++ return BUS_RESULT_FALSE;
+
+- retval = FALSE;
++ retval = BUS_RESULT_FALSE;
+
+ if (strcmp (name, DBUS_SERVICE_DBUS) == 0)
+ {
+@@ -792,7 +797,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
+ goto out;
+ }
+
+- retval = TRUE;
++ retval = BUS_RESULT_TRUE;
+
+ out:
+ if (reply)
+@@ -801,7 +806,7 @@ bus_driver_handle_service_exists (DBusConnection *connection,
+ return retval;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_activate_service (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -809,7 +814,7 @@ bus_driver_handle_activate_service (DBusConnection *connection,
+ {
+ dbus_uint32_t flags;
+ const char *name;
+- dbus_bool_t retval;
++ BusResult retval;
+ BusActivation *activation;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+@@ -823,10 +828,10 @@ bus_driver_handle_activate_service (DBusConnection *connection,
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ _dbus_verbose ("No memory to get arguments to StartServiceByName\n");
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+- retval = FALSE;
++ retval = BUS_RESULT_FALSE;
+
+ if (!bus_activation_activate_service (activation, connection, transaction, FALSE,
+ message, name, error))
+@@ -836,7 +841,7 @@ bus_driver_handle_activate_service (DBusConnection *connection,
+ goto out;
+ }
+
+- retval = TRUE;
++ retval = BUS_RESULT_TRUE;
+
+ out:
+ return retval;
+@@ -872,13 +877,13 @@ send_ack_reply (DBusConnection *connection,
+ return TRUE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_update_activation_environment (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error)
+ {
+- dbus_bool_t retval;
++ BusResult retval;
+ BusActivation *activation;
+ DBusMessageIter iter;
+ DBusMessageIter dict_iter;
+@@ -939,7 +944,7 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
+
+ dbus_message_iter_recurse (&iter, &dict_iter);
+
+- retval = FALSE;
++ retval = BUS_RESULT_FALSE;
+
+ /* Then loop through the sent dictionary, add the location of
+ * the environment keys and values to lists. The result will
+@@ -1026,7 +1031,7 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
+ message, error))
+ goto out;
+
+- retval = TRUE;
++ retval = BUS_RESULT_TRUE;
+
+ out:
+ _dbus_list_clear (&keys);
+@@ -1034,7 +1039,7 @@ bus_driver_handle_update_activation_environment (DBusConnection *connection,
+ return retval;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_add_match (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1093,16 +1098,16 @@ bus_driver_handle_add_match (DBusConnection *connection,
+
+ bus_match_rule_unref (rule);
+
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ failed:
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ if (rule)
+ bus_match_rule_unref (rule);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_remove_match (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1146,16 +1151,16 @@ bus_driver_handle_remove_match (DBusConnection *connection,
+
+ bus_match_rule_unref (rule);
+
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ failed:
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ if (rule)
+ bus_match_rule_unref (rule);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_get_service_owner (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1225,7 +1230,7 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,
+
+ dbus_message_unref (reply);
+
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ BUS_SET_OOM (error);
+@@ -1234,10 +1239,10 @@ bus_driver_handle_get_service_owner (DBusConnection *connection,
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ if (reply)
+ dbus_message_unref (reply);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_list_queued_owners (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1328,7 +1333,7 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
+
+ dbus_message_unref (reply);
+
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ BUS_SET_OOM (error);
+@@ -1341,10 +1346,10 @@ bus_driver_handle_list_queued_owners (DBusConnection *connection,
+ if (base_names)
+ _dbus_list_clear (&base_names);
+
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1389,7 +1394,7 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
+
+ dbus_message_unref (reply);
+
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ BUS_SET_OOM (error);
+@@ -1398,10 +1403,10 @@ bus_driver_handle_get_connection_unix_user (DBusConnection *connection,
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ if (reply)
+ dbus_message_unref (reply);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1446,7 +1451,7 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
+
+ dbus_message_unref (reply);
+
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ BUS_SET_OOM (error);
+@@ -1455,10 +1460,10 @@ bus_driver_handle_get_connection_unix_process_id (DBusConnection *connection,
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ if (reply)
+ dbus_message_unref (reply);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1502,7 +1507,7 @@ bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection,
+
+ dbus_message_unref (reply);
+
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ BUS_SET_OOM (error);
+@@ -1511,10 +1516,10 @@ bus_driver_handle_get_adt_audit_session_data (DBusConnection *connection,
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ if (reply)
+ dbus_message_unref (reply);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1556,7 +1561,7 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne
+
+ dbus_message_unref (reply);
+
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ BUS_SET_OOM (error);
+@@ -1565,10 +1570,10 @@ bus_driver_handle_get_connection_selinux_security_context (DBusConnection *conne
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ if (reply)
+ dbus_message_unref (reply);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1645,7 +1650,7 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
+
+ dbus_message_unref (reply);
+
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ BUS_SET_OOM (error);
+@@ -1659,10 +1664,10 @@ bus_driver_handle_get_connection_credentials (DBusConnection *connection,
+ dbus_message_unref (reply);
+ }
+
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_reload_config (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1687,7 +1692,7 @@ bus_driver_handle_reload_config (DBusConnection *connection,
+ goto oom;
+
+ dbus_message_unref (reply);
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ BUS_SET_OOM (error);
+@@ -1696,10 +1701,10 @@ bus_driver_handle_reload_config (DBusConnection *connection,
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ if (reply)
+ dbus_message_unref (reply);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_get_id (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1715,7 +1720,7 @@ bus_driver_handle_get_id (DBusConnection *connection,
+ if (!_dbus_string_init (&uuid))
+ {
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ reply = NULL;
+@@ -1741,7 +1746,7 @@ bus_driver_handle_get_id (DBusConnection *connection,
+
+ _dbus_string_free (&uuid);
+ dbus_message_unref (reply);
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+@@ -1751,7 +1756,7 @@ bus_driver_handle_get_id (DBusConnection *connection,
+ if (reply)
+ dbus_message_unref (reply);
+ _dbus_string_free (&uuid);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ typedef struct
+@@ -1759,10 +1764,10 @@ typedef struct
+ const char *name;
+ const char *in_args;
+ const char *out_args;
+- dbus_bool_t (* handler) (DBusConnection *connection,
+- BusTransaction *transaction,
+- DBusMessage *message,
+- DBusError *error);
++ BusResult (* handler) (DBusConnection *connection,
++ BusTransaction *transaction,
++ DBusMessage *message,
++ DBusError *error);
+ } MessageHandler;
+
+ /* For speed it might be useful to sort this in order of
+@@ -1847,7 +1852,7 @@ static const MessageHandler dbus_message_handlers[] = {
+ { NULL, NULL, NULL, NULL }
+ };
+
+-static dbus_bool_t bus_driver_handle_introspect (DBusConnection *,
++static BusResult bus_driver_handle_introspect (DBusConnection *,
+ BusTransaction *, DBusMessage *, DBusError *);
+
+ static const MessageHandler introspectable_message_handlers[] = {
+@@ -1973,7 +1978,7 @@ bus_driver_generate_introspect_string (DBusString *xml)
+ return TRUE;
+ }
+
+-static dbus_bool_t
++static BusResult
+ bus_driver_handle_introspect (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -1993,13 +1998,13 @@ bus_driver_handle_introspect (DBusConnection *connection,
+ DBUS_TYPE_INVALID))
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ if (!_dbus_string_init (&xml))
+ {
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ if (!bus_driver_generate_introspect_string (&xml))
+@@ -2022,7 +2027,7 @@ bus_driver_handle_introspect (DBusConnection *connection,
+ dbus_message_unref (reply);
+ _dbus_string_free (&xml);
+
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ BUS_SET_OOM (error);
+@@ -2032,7 +2037,7 @@ bus_driver_handle_introspect (DBusConnection *connection,
+
+ _dbus_string_free (&xml);
+
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ /*
+@@ -2067,7 +2072,7 @@ bus_driver_check_message_is_for_us (DBusMessage *message,
+ return TRUE;
+ }
+
+-dbus_bool_t
++BusResult
+ bus_driver_handle_message (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -2077,6 +2082,7 @@ bus_driver_handle_message (DBusConnection *connection,
+ const InterfaceHandler *ih;
+ const MessageHandler *mh;
+ dbus_bool_t found_interface = FALSE;
++ BusResult res;
+
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+
+@@ -2085,13 +2091,13 @@ bus_driver_handle_message (DBusConnection *connection,
+ BusContext *context;
+
+ context = bus_connection_get_context (connection);
+- return dbus_activation_systemd_failure(bus_context_get_activation(context), message);
++ return dbus_activation_systemd_failure(bus_context_get_activation(context), message) == TRUE ? BUS_RESULT_TRUE : BUS_RESULT_FALSE;
+ }
+
+ if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+ {
+ _dbus_verbose ("Driver got a non-method-call message, ignoring\n");
+- return TRUE; /* we just ignore this */
++ return BUS_RESULT_TRUE; /* we just ignore this */
+ }
+
+ /* may be NULL, which means "any interface will do" */
+@@ -2133,20 +2139,27 @@ bus_driver_handle_message (DBusConnection *connection,
+ name, dbus_message_get_signature (message),
+ mh->in_args);
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+- if ((* mh->handler) (connection, transaction, message, error))
++ res = (* mh->handler) (connection, transaction, message, error);
++ if (res == BUS_RESULT_TRUE)
+ {
+ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
+ _dbus_verbose ("Driver handler succeeded\n");
+- return TRUE;
++ return BUS_RESULT_TRUE;
+ }
+- else
++ else if (res == BUS_RESULT_FALSE)
+ {
+ _DBUS_ASSERT_ERROR_IS_SET (error);
+ _dbus_verbose ("Driver handler returned failure\n");
+- return FALSE;
++ return BUS_RESULT_FALSE;
++ }
++ else if (res == BUS_RESULT_LATER)
++ {
++ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
++ _dbus_verbose ("Driver handler delayed message processing due to policy check\n");
++ return BUS_RESULT_LATER;
+ }
+ }
+ }
+@@ -2158,7 +2171,7 @@ bus_driver_handle_message (DBusConnection *connection,
+ "%s does not understand message %s",
+ DBUS_SERVICE_DBUS, name);
+
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ void
+diff --git a/bus/driver.h b/bus/driver.h
+index 201709c..3ff4ff1 100644
+--- a/bus/driver.h
++++ b/bus/driver.h
+@@ -28,7 +28,7 @@
+ #include "connection.h"
+
+ void bus_driver_remove_connection (DBusConnection *connection);
+-dbus_bool_t bus_driver_handle_message (DBusConnection *connection,
++BusResult bus_driver_handle_message (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+ DBusError *error);
+diff --git a/bus/policy.c b/bus/policy.c
+index 448147f..3672ff9 100644
+--- a/bus/policy.c
++++ b/bus/policy.c
+@@ -1323,18 +1323,21 @@ bus_client_policy_check_can_receive (BusClientPolicy *policy,
+
+
+
+-static dbus_bool_t
++static BusResult
+ bus_rules_check_can_own (DBusList *rules,
+- const DBusString *service_name)
++ const DBusString *service_name,
++ DBusConnection *connection,
++ DBusMessage *message)
+ {
+ DBusList *link;
+- dbus_bool_t allowed;
++ BusResult result;
++ const char *privilege;
+
+ /* rules is in the order the rules appeared
+ * in the config file, i.e. last rule that applies wins
+ */
+
+- allowed = FALSE;
++ result = BUS_RESULT_FALSE;
+ link = _dbus_list_get_first_link (&rules);
+ while (link != NULL)
+ {
+@@ -1370,17 +1373,45 @@ bus_rules_check_can_own (DBusList *rules,
+ }
+
+ /* Use this rule */
+- allowed = rule->access == BUS_POLICY_RULE_ACCESS_ALLOW;
++ switch (rule->access)
++ {
++ case BUS_POLICY_RULE_ACCESS_ALLOW:
++ result = BUS_RESULT_TRUE;
++ break;
++ case BUS_POLICY_RULE_ACCESS_DENY:
++ result = BUS_RESULT_FALSE;
++ break;
++ case BUS_POLICY_RULE_ACCESS_CHECK:
++ result = BUS_RESULT_LATER;
++ privilege = rule->privilege;
++ break;
++ }
+ }
+
+- return allowed;
++ if (result == BUS_RESULT_LATER)
++ {
++ BusContext *context = bus_connection_get_context(connection);
++ BusCheck *check = bus_context_get_check(context);
++ BusDeferredMessage *deferred_message;
++
++ result = bus_check_privilege(check, message, connection, NULL, NULL,
++ privilege, BUS_DEFERRED_MESSAGE_CHECK_OWN, &deferred_message);
++ if (result == BUS_RESULT_LATER)
++ {
++ bus_deferred_message_disable_sender(deferred_message);
++ }
++ }
++
++ return result;
+ }
+
+-dbus_bool_t
++BusResult
+ bus_client_policy_check_can_own (BusClientPolicy *policy,
+- const DBusString *service_name)
++ const DBusString *service_name,
++ DBusConnection *connection,
++ DBusMessage *message)
+ {
+- return bus_rules_check_can_own (policy->rules, service_name);
++ return bus_rules_check_can_own (policy->rules, service_name, connection, message);
+ }
+
+ #ifdef DBUS_ENABLE_EMBEDDED_TESTS
+@@ -1388,7 +1419,7 @@ dbus_bool_t
+ bus_policy_check_can_own (BusPolicy *policy,
+ const DBusString *service_name)
+ {
+- return bus_rules_check_can_own (policy->default_rules, service_name);
++ return bus_rules_check_can_own (policy->default_rules, service_name, NULL, NULL);
+ }
+ #endif /* DBUS_ENABLE_EMBEDDED_TESTS */
+
+diff --git a/bus/policy.h b/bus/policy.h
+index e9f193a..1f23431 100644
+--- a/bus/policy.h
++++ b/bus/policy.h
+@@ -170,8 +170,10 @@ BusResult bus_client_policy_check_can_receive (BusClientPolicy *polic
+ dbus_int32_t *toggles,
+ const char **privilege_param,
+ BusDeferredMessage **deferred_message);
+-dbus_bool_t bus_client_policy_check_can_own (BusClientPolicy *policy,
+- const DBusString *service_name);
++BusResult bus_client_policy_check_can_own (BusClientPolicy *policy,
++ const DBusString *service_name,
++ DBusConnection *connection,
++ DBusMessage *message);
+ dbus_bool_t bus_client_policy_append_rule (BusClientPolicy *policy,
+ BusPolicyRule *rule);
+ void bus_client_policy_optimize (BusClientPolicy *policy);
+diff --git a/bus/services.c b/bus/services.c
+index 584485b..f25fdf3 100644
+--- a/bus/services.c
++++ b/bus/services.c
+@@ -374,24 +374,26 @@ bus_registry_list_services (BusRegistry *registry,
+ return FALSE;
+ }
+
+-dbus_bool_t
++BusResult
+ bus_registry_acquire_service (BusRegistry *registry,
+ DBusConnection *connection,
++ DBusMessage *message,
+ const DBusString *service_name,
+ dbus_uint32_t flags,
+ dbus_uint32_t *result,
+ BusTransaction *transaction,
+ DBusError *error)
+ {
+- dbus_bool_t retval;
++ BusResult retval;
+ DBusConnection *old_owner_conn;
+ BusClientPolicy *policy;
+ BusService *service;
+ BusActivation *activation;
+ BusSELinuxID *sid;
+ BusOwner *primary_owner;
++ BusResult res;
+
+- retval = FALSE;
++ retval = BUS_RESULT_FALSE;
+
+ if (!_dbus_validate_bus_name (service_name, 0,
+ _dbus_string_get_length (service_name)))
+@@ -459,7 +461,8 @@ bus_registry_acquire_service (BusRegistry *registry,
+ goto out;
+ }
+
+- if (!bus_client_policy_check_can_own (policy, service_name))
++ res = bus_client_policy_check_can_own (policy, service_name, connection, message);
++ if (res == BUS_RESULT_FALSE)
+ {
+ dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+ "Connection \"%s\" is not allowed to own the service \"%s\" due "
+@@ -470,6 +473,11 @@ bus_registry_acquire_service (BusRegistry *registry,
+ _dbus_string_get_const_data (service_name));
+ goto out;
+ }
++ else if (res == BUS_RESULT_LATER)
++ {
++ retval = BUS_RESULT_LATER;
++ goto out;
++ }
+
+ if (bus_connection_get_n_services_owned (connection) >=
+ bus_context_get_max_services_per_connection (registry->context))
+@@ -586,11 +594,13 @@ bus_registry_acquire_service (BusRegistry *registry,
+ }
+
+ activation = bus_context_get_activation (registry->context);
+- retval = bus_activation_send_pending_auto_activation_messages (activation,
++
++ if (bus_activation_send_pending_auto_activation_messages (activation,
+ service,
+- transaction);
+- if (!retval)
+- BUS_SET_OOM (error);
++ transaction))
++ retval = BUS_RESULT_TRUE;
++ else
++ BUS_SET_OOM (error);
+
+ out:
+ return retval;
+diff --git a/bus/services.h b/bus/services.h
+index 056dd9f..3df3dd7 100644
+--- a/bus/services.h
++++ b/bus/services.h
+@@ -50,8 +50,9 @@ void bus_registry_foreach (BusRegistry *registry
+ dbus_bool_t bus_registry_list_services (BusRegistry *registry,
+ char ***listp,
+ int *array_len);
+-dbus_bool_t bus_registry_acquire_service (BusRegistry *registry,
++BusResult bus_registry_acquire_service (BusRegistry *registry,
+ DBusConnection *connection,
++ DBusMessage *message,
+ const DBusString *service_name,
+ dbus_uint32_t flags,
+ dbus_uint32_t *result,
+diff --git a/bus/stats.c b/bus/stats.c
+index 20321e5..61dc428 100644
+--- a/bus/stats.c
++++ b/bus/stats.c
+@@ -35,7 +35,7 @@
+
+ #ifdef DBUS_ENABLE_STATS
+
+-dbus_bool_t
++BusResult
+ bus_stats_handle_get_stats (DBusConnection *connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -106,17 +106,17 @@ bus_stats_handle_get_stats (DBusConnection *connection,
+ goto oom;
+
+ dbus_message_unref (reply);
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ if (reply != NULL)
+ dbus_message_unref (reply);
+
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+-dbus_bool_t
++BusResult
+ bus_stats_handle_get_connection_stats (DBusConnection *caller_connection,
+ BusTransaction *transaction,
+ DBusMessage *message,
+@@ -143,7 +143,7 @@ bus_stats_handle_get_connection_stats (DBusConnection *caller_connection,
+ if (! dbus_message_get_args (message, error,
+ DBUS_TYPE_STRING, &bus_name,
+ DBUS_TYPE_INVALID))
+- return FALSE;
++ return BUS_RESULT_FALSE;
+
+ _dbus_string_init_const (&bus_name_str, bus_name);
+ service = bus_registry_lookup (registry, &bus_name_str);
+@@ -152,7 +152,7 @@ bus_stats_handle_get_connection_stats (DBusConnection *caller_connection,
+ {
+ dbus_set_error (error, DBUS_ERROR_NAME_HAS_NO_OWNER,
+ "Bus name '%s' has no owner", bus_name);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ stats_connection = bus_service_get_primary_owners_connection (service);
+@@ -214,14 +214,14 @@ bus_stats_handle_get_connection_stats (DBusConnection *caller_connection,
+ goto oom;
+
+ dbus_message_unref (reply);
+- return TRUE;
++ return BUS_RESULT_TRUE;
+
+ oom:
+ if (reply != NULL)
+ dbus_message_unref (reply);
+
+ BUS_SET_OOM (error);
+- return FALSE;
++ return BUS_RESULT_FALSE;
+ }
+
+ #endif
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/dbus/dbus-cynara/0008-Add-GetConnectionSmackContext-D-Bus-daemon-method.patch b/meta-security/recipes-core/dbus/dbus-cynara/0008-Add-GetConnectionSmackContext-D-Bus-daemon-method.patch
new file mode 100644
index 000000000..43a1ef658
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-cynara/0008-Add-GetConnectionSmackContext-D-Bus-daemon-method.patch
@@ -0,0 +1,99 @@
+From 6c9997fb1cdff4281166e8c2fb8276018b1025dd Mon Sep 17 00:00:00 2001
+From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
+Date: Mon, 15 Jun 2015 11:46:47 +0200
+Subject: [PATCH 8/8] Add "GetConnectionSmackContext" D-Bus daemon method
+
+This method is used to obtain smack label of given D-Bus client.
+Note that it is deprecated and is included only for compatilibity with
+existing D-Bus users. GetConnectionCredentials should be used to obtain
+client's credentials.
+
+Change-Id: Idf9648032ca5cbd9605ffab055e6384baa4eb9b4
+---
+ bus/driver.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 63 insertions(+)
+
+diff --git a/bus/driver.c b/bus/driver.c
+index 9708f49..4e76224 100644
+--- a/bus/driver.c
++++ b/bus/driver.c
+@@ -1759,6 +1759,65 @@ bus_driver_handle_get_id (DBusConnection *connection,
+ return BUS_RESULT_FALSE;
+ }
+
++static BusResult
++bus_driver_handle_get_connection_smack_context (DBusConnection *connection,
++ BusTransaction *transaction,
++ DBusMessage *message,
++ DBusError *error)
++{
++ DBusConnection *conn;
++ DBusMessage *reply = NULL;
++ char *label = NULL;
++ const char *service;
++
++ _DBUS_ASSERT_ERROR_IS_CLEAR (error);
++
++ conn = bus_driver_get_conn_helper (connection, message, "credentials",
++ &service, error);
++ if (conn == NULL)
++ goto err;
++
++ reply = dbus_message_new_method_return (message);
++ if (reply == NULL)
++ goto oom;
++
++ if (!_dbus_connection_get_linux_security_label (conn, &label))
++ {
++ dbus_set_error (error, DBUS_ERROR_FAILED,
++ "Failed to get smack label of connection",
++ conn);
++ goto err;
++ }
++
++ if (label == NULL)
++ goto oom;
++
++ if (!dbus_message_append_args (reply,
++ DBUS_TYPE_STRING, &label,
++ DBUS_TYPE_INVALID))
++ goto oom;
++
++ if (!bus_transaction_send_from_driver (transaction, connection, reply))
++ goto oom;
++
++ dbus_message_unref (reply);
++ dbus_free(label);
++
++ return BUS_RESULT_TRUE;
++
++oom:
++ BUS_SET_OOM (error);
++
++err:
++ if (reply != NULL)
++ dbus_message_unref (reply);
++
++ dbus_free(label);
++
++ return BUS_RESULT_FALSE;
++}
++
++
+ typedef struct
+ {
+ const char *name;
+@@ -1849,6 +1908,10 @@ static const MessageHandler dbus_message_handlers[] = {
+ bus_driver_handle_get_id },
+ { "GetConnectionCredentials", "s", "a{sv}",
+ bus_driver_handle_get_connection_credentials },
++ { "GetConnectionSmackContext", /* deprecated - you should use GetConnectionCredentials instead */
++ DBUS_TYPE_STRING_AS_STRING,
++ DBUS_TYPE_STRING_AS_STRING,
++ bus_driver_handle_get_connection_smack_context },
+ { NULL, NULL, NULL, NULL }
+ };
+
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/dbus/dbus-cynara/Perform-Cynara-runtime-policy-checks-by-default.patch b/meta-security/recipes-core/dbus/dbus-cynara/Perform-Cynara-runtime-policy-checks-by-default.patch
new file mode 100644
index 000000000..e573fb3b3
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-cynara/Perform-Cynara-runtime-policy-checks-by-default.patch
@@ -0,0 +1,116 @@
+From e8610297cf7031e94eb314a2e8c11246f4405403 Mon Sep 17 00:00:00 2001
+From: Jacek Bukarewicz <j.bukarewicz@samsung.com>
+Date: Tue, 23 Jun 2015 11:08:48 +0200
+Subject: [PATCH] Perform Cynara runtime policy checks by default
+
+This change introduces http://tizen.org/privilege/internal/dbus privilege
+which is supposed to be available only to trusted system resources.
+Checks for this privilege are used in place of certain allow rules to
+make security policy more strict.
+
+For system bus sending and receiving signals now requires
+http://tizen.org/privilege/internal/dbus privilege. Requesting name
+ownership and sending methods is still denied by default.
+
+For session bus http://tizen.org/privilege/internal/dbus privilege
+is now required for requesting name, calling methods, sending and receiving
+signals.
+
+Services are supposed to override these default settings to implement their
+own security policy.
+
+Change-Id: Ifb4a160bf6e0638404e0295a2e4fa3077efd881c
+Signed-off-by: Jacek Bukarewicz <j.bukarewicz@samsung.com>
+---
+ bus/session.conf.in | 32 ++++++++++++++++++++++++++------
+ bus/system.conf.in | 22 ++++++++++++++++------
+ 2 files changed, 42 insertions(+), 12 deletions(-)
+
+diff --git a/bus/session.conf.in b/bus/session.conf.in
+index 74d9d1f..fa5c232 100644
+--- a/bus/session.conf.in
++++ b/bus/session.conf.in
+@@ -17,12 +17,32 @@
+ <standard_session_servicedirs />
+
+ <policy context="default">
+- <!-- Allow everything to be sent -->
+- <allow send_destination="*" eavesdrop="true"/>
+- <!-- Allow everything to be received -->
+- <allow eavesdrop="true"/>
+- <!-- Allow anyone to own anything -->
+- <allow own="*"/>
++ <!-- By default clients require internal/dbus privilege to communicate
++ with D-Bus services and to claim name ownership. This is internal privilege that
++ is only accessible to trusted system services -->
++ <check own="*" privilege="http://tizen.org/privilege/internal/dbus" />
++ <check send_type="method_call" privilege="http://tizen.org/privilege/internal/dbus" />
++ <check send_type="signal" privilege="http://tizen.org/privilege/internal/dbus" />
++ <check receive_type="signal" privilege="http://tizen.org/privilege/internal/dbus" />
++
++ <!-- Reply messages (method returns, errors) are allowed
++ by default -->
++ <allow send_requested_reply="true" send_type="method_return"/>
++ <allow send_requested_reply="true" send_type="error"/>
++
++ <!-- All messages but signals may be received by default -->
++ <allow receive_type="method_call"/>
++ <allow receive_type="method_return"/>
++ <allow receive_type="error"/>
++
++ <!-- Allow anyone to talk to the message bus -->
++ <allow send_destination="org.freedesktop.DBus"/>
++ <allow receive_sender="org.freedesktop.DBus"/>
++
++ <!-- But disallow some specific bus services -->
++ <deny send_destination="org.freedesktop.DBus"
++ send_interface="org.freedesktop.DBus"
++ send_member="UpdateActivationEnvironment"/>
+ </policy>
+
+ <!-- Config files are placed here that among other things,
+diff --git a/bus/system.conf.in b/bus/system.conf.in
+index 92f4cc4..dd16947 100644
+--- a/bus/system.conf.in
++++ b/bus/system.conf.in
+@@ -50,21 +50,31 @@
+ <deny own="*"/>
+ <deny send_type="method_call"/>
+
+- <!-- Signals and reply messages (method returns, errors) are allowed
++ <!-- By default clients require internal/dbus privilege to send and receive signaks.
++ This is internal privilege that is only accessible to trusted system services -->
++ <check send_type="signal" privilege="http://tizen.org/privilege/internal/dbus" />
++ <check receive_type="signal" privilege="http://tizen.org/privilege/internal/dbus" />
++
++ <!-- Reply messages (method returns, errors) are allowed
+ by default -->
+- <allow send_type="signal"/>
+ <allow send_requested_reply="true" send_type="method_return"/>
+ <allow send_requested_reply="true" send_type="error"/>
+
+- <!-- All messages may be received by default -->
++ <!-- All messages but signals may be received by default -->
+ <allow receive_type="method_call"/>
+ <allow receive_type="method_return"/>
+ <allow receive_type="error"/>
+- <allow receive_type="signal"/>
+
+- <!-- Allow anyone to talk to the message bus -->
++ <!-- If there is a need specific bus services could be protected by Cynara as well.
++ However, this can lead to deadlock during the boot process when such check is made and
++ Cynara is not yet activated (systemd calls protected method synchronously,
++ dbus daemon tries to consult Cynara, Cynara waits for systemd activation).
++ Therefore it is advised to allow root processes to use bus services.
++ Currently anyone is allowed to talk to the message bus -->
+ <allow send_destination="org.freedesktop.DBus"/>
+- <!-- But disallow some specific bus services -->
++ <allow receive_sender="org.freedesktop.DBus"/>
++
++ <!-- Disallow some specific bus services -->
+ <deny send_destination="org.freedesktop.DBus"
+ send_interface="org.freedesktop.DBus"
+ send_member="UpdateActivationEnvironment"/>
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/dbus/dbus-cynara_1.8.18.bb b/meta-security/recipes-core/dbus/dbus-cynara_1.8.18.bb
new file mode 100644
index 000000000..bcff737cd
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-cynara_1.8.18.bb
@@ -0,0 +1,58 @@
+require dbus-oe-core.inc
+FILESEXTRAPATHS_prepend := "${COREBASE}/meta/recipes-core/dbus/dbus:${THISDIR}/dbus-cynara:"
+S = "${WORKDIR}/dbus-${PV}"
+libexecdir = "${libdir}/dbus"
+
+SRC_URI[md5sum] = "83e607e9ccb1c921d5b6bbea2376a36c"
+SRC_URI[sha256sum] = "36f2eb9c777a3c71562573da36a147e900a642afcd44d2b0470d992a4898c4f2"
+
+# From https://review.tizen.org/gerrit/#/admin/projects/platform/upstream/dbus
+# revision 6c9997fb1cdff4281166e8c2fb8276018b1025dd
+# aka https://review.tizen.org/git/?p=platform%2Fupstream%2Fdbus.git;a=shortlog;h=refs%2Fheads%2Fsandbox%2Fjacekbe%2Fupgrade
+# as announced in https://bugs.tizen.org/jira/browse/TC-2520 "D-Bus: local denial of service attack"
+SRC_URI += " \
+file://0001-Fix-memleak-in-GetConnectionCredentials-handler.patch \
+file://0002-New-a-sv-helper-for-using-byte-arrays-as-the-variant.patch \
+file://0003-Add-LSM-agnostic-support-for-LinuxSecurityLabel-cred.patch \
+file://0004-Integration-of-Cynara-asynchronous-security-checks.patch \
+file://0005-Disable-message-dispatching-when-send-rule-result-is.patch \
+file://0006-Handle-unavailability-of-policy-results-for-broadcas.patch \
+file://0007-Add-own-rule-result-unavailability-handling.patch \
+"
+
+# Provides a legacy API which shouldn't be used in new code. It is
+# still needed at the moment because cynara helper methods call it
+# (creds-dbus-inner.cpp, creds-gdbus.cpp).
+SRC_URI += "file://0008-Add-GetConnectionSmackContext-D-Bus-daemon-method.patch"
+
+# Depends on special Cynara rules which get installed in the
+# security-manager-policy package. From patch set 5 in:
+# https://review.tizen.org/gerrit/#/c/31310/
+SRC_URI += "file://Perform-Cynara-runtime-policy-checks-by-default.patch"
+
+DEPENDS += "cynara smack"
+EXTRA_OECONF += "--enable-cynara"
+
+inherit distro_features_check
+REQUIRED_DISTRO_FEATURES += "smack"
+
+# Only the main package gets created here, everything else remains in the
+# normal dbus recipe.
+do_install_append () {
+ for i in ${@' '.join([d.getVar('D', True) + x for x in (' '.join([d.getVar('FILES_${PN}-' + p, True) or '' for p in ['lib', 'dev', 'staticdev', 'doc', 'locale', 'ptest']])).split()])}; do
+ rm -rf $i
+ done
+
+ # Try to remove empty directories, starting with the
+ # longest path (= deepest directory) first.
+ # Find needs a valid current directory. Somehow the directory
+ # we get called in is gone by the time that we get invoked.
+ ( cd ${D}
+ for i in `find . -type d | sort -r`; do
+ rmdir $i || true
+ done
+ )
+}
+
+# Avoid warning about dbus and dbus-cynara providing dbus-x11.
+RPROVIDES_${PN}_remove = "${OLDPKGNAME}"
diff --git a/meta-security/recipes-core/dbus/dbus-oe-core.inc b/meta-security/recipes-core/dbus/dbus-oe-core.inc
new file mode 100644
index 000000000..3971081fd
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus-oe-core.inc
@@ -0,0 +1,170 @@
+SUMMARY = "D-Bus message bus"
+DESCRIPTION = "D-Bus is a message bus system, a simple way for applications to talk to one another. In addition to interprocess communication, D-Bus helps coordinate process lifecycle; it makes it simple and reliable to code a \"single instance\" application or daemon, and to launch applications and daemons on demand when their services are needed."
+HOMEPAGE = "http://dbus.freedesktop.org"
+SECTION = "base"
+LICENSE = "AFL-2 | GPLv2+"
+LIC_FILES_CHKSUM = "file://COPYING;md5=10dded3b58148f3f1fd804b26354af3e \
+ file://dbus/dbus.h;beginline=6;endline=20;md5=7755c9d7abccd5dbd25a6a974538bb3c"
+DEPENDS = "expat virtual/libintl"
+RDEPENDS_dbus_class-native = ""
+RDEPENDS_dbus_class-nativesdk = ""
+PACKAGES += "${@bb.utils.contains('DISTRO_FEATURES', 'ptest', '${PN}-ptest', '', d)}"
+ALLOW_EMPTY_dbus-ptest = "1"
+RDEPENDS_dbus-ptest_class-target = "dbus-test-ptest"
+
+SRC_URI = "http://dbus.freedesktop.org/releases/dbus/dbus-${PV}.tar.gz \
+ file://tmpdir.patch \
+ file://dbus-1.init \
+ file://os-test.patch \
+ file://clear-guid_from_server-if-send_negotiate_unix_f.patch \
+"
+
+inherit useradd autotools pkgconfig gettext update-rc.d
+
+INITSCRIPT_NAME = "dbus-1"
+INITSCRIPT_PARAMS = "start 02 5 3 2 . stop 20 0 1 6 ."
+
+python __anonymous() {
+ if not bb.utils.contains('DISTRO_FEATURES', 'sysvinit', True, False, d):
+ d.setVar("INHIBIT_UPDATERCD_BBCLASS", "1")
+}
+
+USERADD_PACKAGES = "${PN}"
+GROUPADD_PARAM_${PN} = "-r netdev"
+USERADD_PARAM_${PN} = "--system --home ${localstatedir}/lib/dbus \
+ --no-create-home --shell /bin/false \
+ --user-group messagebus"
+
+CONFFILES_${PN} = "${sysconfdir}/dbus-1/system.conf ${sysconfdir}/dbus-1/session.conf"
+
+DEBIANNAME_${PN} = "dbus-1"
+
+PACKAGES =+ "${PN}-lib"
+
+OLDPKGNAME = "dbus-x11"
+OLDPKGNAME_class-nativesdk = ""
+
+# for compatibility
+RPROVIDES_${PN} = "${OLDPKGNAME}"
+RREPLACES_${PN} += "${OLDPKGNAME}"
+
+FILES_${PN} = "${bindir}/dbus-daemon* \
+ ${bindir}/dbus-uuidgen \
+ ${bindir}/dbus-cleanup-sockets \
+ ${bindir}/dbus-send \
+ ${bindir}/dbus-monitor \
+ ${bindir}/dbus-launch \
+ ${bindir}/dbus-run-session \
+ ${libexecdir}/dbus* \
+ ${sysconfdir} \
+ ${localstatedir} \
+ ${datadir}/dbus-1/services \
+ ${datadir}/dbus-1/system-services \
+ ${systemd_unitdir}/system/"
+FILES_${PN}-lib = "${libdir}/lib*.so.*"
+RRECOMMENDS_${PN}-lib = "${PN}"
+FILES_${PN}-dev += "${libdir}/dbus-1.0/include ${bindir}/dbus-glib-tool"
+
+pkg_postinst_dbus() {
+ # If both systemd and sysvinit are enabled, mask the dbus-1 init script
+ if ${@bb.utils.contains('DISTRO_FEATURES','systemd sysvinit','true','false',d)}; then
+ if [ -n "$D" ]; then
+ OPTS="--root=$D"
+ fi
+ systemctl $OPTS mask dbus-1.service
+ fi
+
+ if [ -z "$D" ] && [ -e /etc/init.d/populate-volatile.sh ] ; then
+ /etc/init.d/populate-volatile.sh update
+ fi
+}
+
+EXTRA_OECONF = "--disable-tests \
+ --disable-xml-docs \
+ --disable-doxygen-docs \
+ --disable-libaudit \
+ --disable-systemd \
+ --without-dbus-glib"
+
+EXTRA_OECONF_append_class-native = " --disable-selinux"
+
+PACKAGECONFIG ??= "${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'systemd', '', d)} \
+ ${@bb.utils.contains('DISTRO_FEATURES', 'x11', 'x11', '', d)}"
+PACKAGECONFIG_class-native = ""
+PACKAGECONFIG_class-nativesdk = ""
+
+# Would like to --enable-systemd but that's a circular build-dependency between
+# systemd<->dbus
+PACKAGECONFIG[systemd] = "--with-systemdsystemunitdir=${systemd_unitdir}/system/,--without-systemdsystemunitdir"
+PACKAGECONFIG[x11] = "--with-x --enable-x11-autolaunch,--without-x --disable-x11-autolaunch, virtual/libx11 libsm"
+
+do_install() {
+ autotools_do_install
+
+ if ${@bb.utils.contains('DISTRO_FEATURES', 'sysvinit', 'true', 'false', d)}; then
+ install -d ${D}${sysconfdir}/init.d
+ sed 's:@bindir@:${bindir}:' < ${WORKDIR}/dbus-1.init >${WORKDIR}/dbus-1.init.sh
+ install -m 0755 ${WORKDIR}/dbus-1.init.sh ${D}${sysconfdir}/init.d/dbus-1
+ fi
+
+ if ${@bb.utils.contains('DISTRO_FEATURES', 'systemd', 'true', 'false', d)}; then
+ for i in dbus.target.wants sockets.target.wants multi-user.target.wants; do \
+ install -d ${D}${systemd_unitdir}/system/$i; done
+ install -m 0644 ${B}/bus/dbus.service ${B}/bus/dbus.socket ${D}${systemd_unitdir}/system/
+ cd ${D}${systemd_unitdir}/system/dbus.target.wants/
+ ln -fs ../dbus.socket ${D}${systemd_unitdir}/system/dbus.target.wants/dbus.socket
+ ln -fs ../dbus.socket ${D}${systemd_unitdir}/system/sockets.target.wants/dbus.socket
+ ln -fs ../dbus.service ${D}${systemd_unitdir}/system/multi-user.target.wants/dbus.service
+ fi
+
+ install -d ${D}${sysconfdir}/default/volatiles
+ echo "d messagebus messagebus 0755 ${localstatedir}/run/dbus none" \
+ > ${D}${sysconfdir}/default/volatiles/99_dbus
+
+
+ mkdir -p ${D}${localstatedir}/lib/dbus
+
+ chown messagebus:messagebus ${D}${localstatedir}/lib/dbus
+
+ chown root:messagebus ${D}${libexecdir}/dbus-daemon-launch-helper
+ chmod 4755 ${D}${libexecdir}/dbus-daemon-launch-helper
+
+ # Remove Red Hat initscript
+ rm -rf ${D}${sysconfdir}/rc.d
+
+ # Remove empty testexec directory as we don't build tests
+ rm -rf ${D}${libdir}/dbus-1.0/test
+
+ # Remove /var/run as it is created on startup
+ rm -rf ${D}${localstatedir}/run
+}
+
+do_install_class-native() {
+ autotools_do_install
+
+ # for dbus-glib-native introspection generation
+ install -d ${D}${STAGING_DATADIR_NATIVE}/dbus/
+ # N.B. is below install actually required?
+ install -m 0644 bus/session.conf ${D}${STAGING_DATADIR_NATIVE}/dbus/session.conf
+
+ # dbus-glib-native and dbus-glib need this xml file
+ ./bus/dbus-daemon --introspect > ${D}${STAGING_DATADIR_NATIVE}/dbus/dbus-bus-introspect.xml
+
+ # dbus-launch has no X support so lets not install it in case the host
+ # has a more featured and useful version
+ rm -f ${D}${bindir}/dbus-launch
+}
+
+do_install_class-nativesdk() {
+ autotools_do_install
+
+ # dbus-launch has no X support so lets not install it in case the host
+ # has a more featured and useful version
+ rm -f ${D}${bindir}/dbus-launch
+
+ # Remove /var/run to avoid QA error
+ rm -rf ${D}${localstatedir}/run
+}
+BBCLASSEXTEND = "native nativesdk"
+
+INSANE_SKIP_${PN}-ptest += "build-deps"
diff --git a/meta-security/recipes-core/dbus/dbus_%.bbappend b/meta-security/recipes-core/dbus/dbus_%.bbappend
new file mode 100644
index 000000000..e352b4d05
--- /dev/null
+++ b/meta-security/recipes-core/dbus/dbus_%.bbappend
@@ -0,0 +1,27 @@
+# Optionally, compilation of the main package with the daemon gets moved into
+# dbus-cynara. That is necessary to break a dependency cycle once the
+# daemon gets compiled with Cynara support (dbus -> cynara -> systemd
+# -> dbus).
+do_install_append_class-target () {
+ if ${@bb.utils.contains('DISTRO_FEATURES', 'dbus-cynara', 'true', 'false', d)}; then
+ for i in ${@' '.join([d.getVar('D', True) + x for x in (d.getVar('FILES_${PN}', True) or '').split()])}; do
+ rm -rf $i
+ done
+
+ # Try to remove empty directories, starting with the
+ # longest path (= deepest directory) first.
+ # Find needs a valid current directory. Somehow the directory
+ # we get called in is gone by the time that we get invoked.
+ ( cd ${D}
+ for i in `find . -type d | sort -r`; do
+ rmdir $i || true
+ done
+ )
+ fi
+}
+
+# The main package will be empty, but we want to have it created
+# anyway because of the dependencies on it. Installing it will pull in
+# the replacement dbus-cynara package.
+ALLOW_EMPTY_${PN}_class-target = "1"
+RDEPENDS_${PN}_append_class-target = "${@bb.utils.contains('DISTRO_FEATURES', 'dbus-cynara', ' dbus-cynara', '', d)}"
diff --git a/meta-security/recipes-core/packagegroups/packagegroup-security-framework.bb b/meta-security/recipes-core/packagegroups/packagegroup-security-framework.bb
new file mode 100644
index 000000000..c728da3b9
--- /dev/null
+++ b/meta-security/recipes-core/packagegroups/packagegroup-security-framework.bb
@@ -0,0 +1,22 @@
+SUMMARY = "Security middleware components"
+LICENSE = "MIT"
+
+inherit packagegroup
+
+# Install Cynara and security-manager by default if (and only if)
+# Smack is enabled.
+#
+# Cynara does not have a hard dependency on Smack security,
+# but is meant to be used with it. security-manager however
+# links against smack-userspace and expects Smack to be active,
+# so we do not have any choice.
+#
+# Without configuration, security-manager is not usable. We use
+# the policy packaged from the upstream source code here. Adapting
+# it for the distro can be done by patching that source.
+RDEPENDS_${PN}_append_with-lsm-smack = " \
+ cynara \
+ security-manager \
+ security-manager-policy \
+ smacknet \
+"
diff --git a/meta-security/recipes-core/systemd/systemd/0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup-v216.patch b/meta-security/recipes-core/systemd/systemd/0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup-v216.patch
new file mode 100644
index 000000000..2ff51f86b
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup-v216.patch
@@ -0,0 +1,49 @@
+From da574755b8abe1d5fb9151f901ccea51d40d9509 Mon Sep 17 00:00:00 2001
+From: Michael Demeter <michael.demeter@intel.com>
+Date: Fri, 30 Oct 2015 11:25:50 +0100
+Subject: [PATCH] tizen-smack: Handling of /run and /sys/fs/cgroup
+
+Make /run a transmuting directory to enable systemd
+communications with services in the User domain.
+
+Upstream-Status: Pending
+
+Change-Id: I9e23b78d17a108d8e56ad85a9e839b6ccbe4feff
+---
+ src/core/mount-setup.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
+index cc2633e..3dc7cd7 100644
+--- a/src/core/mount-setup.c
++++ b/src/core/mount-setup.c
+@@ -85,19 +85,23 @@ static const MountPoint mount_table[] = {
+ use_smack, MNT_FATAL },
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ use_smack, MNT_FATAL },
+-#endif
++#else
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
++#endif
+ { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
+ NULL, MNT_IN_CONTAINER },
+ #ifdef HAVE_SMACK
+- { "tmpfs", "/run", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
++ { "tmpfs", "/run", "tmpfs", "mode=755,smackfstransmute=System::Run", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ use_smack, MNT_FATAL },
+-#endif
++ { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
++ use_smack, MNT_IN_CONTAINER },
++#else
+ { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
+ { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
++#endif
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL, MNT_IN_CONTAINER },
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/systemd/systemd/0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup.patch b/meta-security/recipes-core/systemd/systemd/0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup.patch
new file mode 100644
index 000000000..a4a3e50a6
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup.patch
@@ -0,0 +1,50 @@
+From 831d552a9589bb2b99c042d01672409efa3d94fc Mon Sep 17 00:00:00 2001
+From: Michael Demeter <michael.demeter@intel.com>
+Date: Fri, 11 Oct 2013 15:37:57 -0700
+Subject: [PATCH 3/9] tizen-smack: Handling of /run and /sys/fs/cgroup
+
+Make /run a transmuting directory to enable systemd
+communications with services in the User domain.
+
+Upstream-Status: Pending
+
+Change-Id: I9e23b78d17a108d8e56ad85a9e839b6ccbe4feff
+---
+ src/core/mount-setup.c | 12 ++++++++----
+ 1 file changed, 8 insertions(+), 4 deletions(-)
+
+diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
+index 521545e..ba0867c 100644
+--- a/src/core/mount-setup.c
++++ b/src/core/mount-setup.c
+@@ -85,19 +85,23 @@ static const MountPoint mount_table[] = {
+ mac_smack_use, MNT_FATAL },
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ mac_smack_use, MNT_FATAL },
+-#endif
++#else
+ { "tmpfs", "/dev/shm", "tmpfs", "mode=1777", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
++#endif
+ { "devpts", "/dev/pts", "devpts", "mode=620,gid=" STRINGIFY(TTY_GID), MS_NOSUID|MS_NOEXEC,
+ NULL, MNT_IN_CONTAINER },
+ #ifdef HAVE_SMACK
+- { "tmpfs", "/run", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+- mac_smack_use, MNT_FATAL },
+-#endif
++ { "tmpfs", "/run", "tmpfs", "mode=755,smackfstransmute=System::Run", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
++ mac_smack_use, MNT_FATAL },
++ { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755,smackfsroot=*", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
++ mac_smack_use, MNT_IN_CONTAINER },
++#else
+ { "tmpfs", "/run", "tmpfs", "mode=755", MS_NOSUID|MS_NODEV|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
+ { "tmpfs", "/sys/fs/cgroup", "tmpfs", "mode=755", MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_STRICTATIME,
+ NULL, MNT_FATAL|MNT_IN_CONTAINER },
++#endif
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd,xattr", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+ NULL, MNT_IN_CONTAINER },
+ { "cgroup", "/sys/fs/cgroup/systemd", "cgroup", "none,name=systemd", MS_NOSUID|MS_NOEXEC|MS_NODEV,
+--
+1.8.4.5
+
diff --git a/meta-security/recipes-core/systemd/systemd/0004-tizen-smack-Handling-of-dev-v216.patch b/meta-security/recipes-core/systemd/systemd/0004-tizen-smack-Handling-of-dev-v216.patch
new file mode 100644
index 000000000..88c100fed
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/0004-tizen-smack-Handling-of-dev-v216.patch
@@ -0,0 +1,82 @@
+From 468ef790a7a0e53c390cec9c63090a0ae04a4d58 Mon Sep 17 00:00:00 2001
+From: Michael Demeter <michael.demeter@intel.com>
+Date: Fri, 11 Oct 2013 15:37:57 -0700
+Subject: [PATCH 4/9] tizen-smack: Handling of /dev
+
+Smack enabled systems need /dev special devices correctly labeled
+
+- Add AC_DEFINE for HAVE_SMACK to configure.ac
+- Add Check for smack in Makefile.am to include smack default rules
+- Add smack default rules to label /dev/xxx correctly for access
+
+Upstream-Status: Inappropriate [configuration]
+
+Change-Id: Iebe2e349cbedb3013abdf32edb55e9310f1d17f5
+---
+ configure.ac | 2 ++
+ Makefile.am | 5 +++++
+ rules/55-udev-smack-default.rules | 23 +++++++++++++++++++++++
+ 3 files changed, 30 insertions(+)
+ create mode 100644 rules/55-udev-smack-default.rules
+
+diff --git a/configure.ac b/configure.ac
+index 18b7198..05f49ed 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -635,6 +635,8 @@ if test "x${have_smack}" = xyes ; then
+ AC_DEFINE(HAVE_SMACK, 1, [Define if SMACK is available])
+ fi
+
++AM_CONDITIONAL([HAVE_SMACK], [test "x$have_smack" = "xyes"])
++
+ # ------------------------------------------------------------------------------
+ AC_ARG_ENABLE([gcrypt],
+ AS_HELP_STRING([--disable-gcrypt],[Disable optional GCRYPT support]),
+diff --git a/Makefile.am b/Makefile.am
+index bf04d31..1a05607 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -3108,6 +3108,11 @@ dist_udevrules_DATA += \
+ nodist_udevrules_DATA += \
+ rules/99-systemd.rules
+
++if HAVE_SMACK
++dist_udevrules_DATA += \
++ rules/55-udev-smack-default.rules
++endif
++
+ dist_udevhwdb_DATA = \
+ hwdb/20-pci-vendor-model.hwdb \
+ hwdb/20-pci-classes.hwdb \
+diff --git a/rules/55-udev-smack-default.rules b/rules/55-udev-smack-default.rules
+new file mode 100644
+index 0000000..3829019
+--- /dev/null
++++ b/rules/55-udev-smack-default.rules
+@@ -0,0 +1,23 @@
++# do not edit this file, it will be overwritten on update
++
++KERNEL=="null", SECLABEL{smack}="*"
++KERNEL=="zero", SECLABEL{smack}="*"
++KERNEL=="console", SECLABEL{smack}="*"
++KERNEL=="kmsg", SECLABEL{smack}="*"
++KERNEL=="video*", SECLABEL{smack}="*"
++KERNEL=="card*", SECLABEL{smack}="*"
++KERNEL=="ptmx", SECLABEL{smack}="*"
++KERNEL=="tty", SECLABEL{smack}="*"
++
++SUBSYSTEM=="graphics", GROUP="video", SECLABEL{smack}="*"
++SUBSYSTEM=="drm", GROUP="video", SECLABEL{smack}="*"
++SUBSYSTEM=="dvb", GROUP="video", SECLABEL{smack}="*"
++
++SUBSYSTEM=="tty", KERNEL=="ptmx", GROUP="tty", MODE="0666", SECLABEL{smack}="*"
++SUBSYSTEM=="tty", KERNEL=="tty", GROUP="tty", MODE="0666", SECLABEL{smack}="*"
++SUBSYSTEM=="tty", KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620", SECLABEL{smack}="*"
++SUBSYSTEM=="vc", KERNEL=="vcs*|vcsa*", GROUP="tty", SECLABEL{smack}="*"
++KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout", SECLABEL{smack}="*"
++
++SUBSYSTEM=="input", KERNEL=="mouse*|mice|event*", MODE="0640", SECLABEL{smack}="*"
++SUBSYSTEM=="input", KERNEL=="ts[0-9]*|uinput", MODE="0640", SECLABEL{smack}="*"
+--
+1.8.4.5
+
diff --git a/meta-security/recipes-core/systemd/systemd/0004-tizen-smack-Handling-of-dev.patch b/meta-security/recipes-core/systemd/systemd/0004-tizen-smack-Handling-of-dev.patch
new file mode 100644
index 000000000..b12caaec5
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/0004-tizen-smack-Handling-of-dev.patch
@@ -0,0 +1,68 @@
+From 468ef790a7a0e53c390cec9c63090a0ae04a4d58 Mon Sep 17 00:00:00 2001
+From: Michael Demeter <michael.demeter@intel.com>
+Date: Fri, 11 Oct 2013 15:37:57 -0700
+Subject: [PATCH 4/9] tizen-smack: Handling of /dev
+
+Smack enabled systems need /dev special devices correctly labeled
+
+- Add AC_DEFINE for HAVE_SMACK to configure.ac
+- Add Check for smack in Makefile.am to include smack default rules
+- Add smack default rules to label /dev/xxx correctly for access
+
+Upstream-Status: Inappropriate [configuration]
+
+Change-Id: Iebe2e349cbedb3013abdf32edb55e9310f1d17f5
+---
+ Makefile.am | 5 +++++
+ rules/55-udev-smack-default.rules | 23 +++++++++++++++++++++++
+ 2 files changed, 28 insertions(+)
+ create mode 100644 rules/55-udev-smack-default.rules
+
+diff --git a/Makefile.am b/Makefile.am
+index bf04d31..1a05607 100644
+--- a/Makefile.am
++++ b/Makefile.am
+@@ -3571,6 +3571,11 @@ dist_udevrules_DATA += \
+ nodist_udevrules_DATA += \
+ rules/99-systemd.rules
+
++if HAVE_SMACK
++dist_udevrules_DATA += \
++ rules/55-udev-smack-default.rules
++endif
++
+ udevconfdir = $(sysconfdir)/udev
+ dist_udevconf_DATA = \
+ src/udev/udev.conf
+diff --git a/rules/55-udev-smack-default.rules b/rules/55-udev-smack-default.rules
+new file mode 100644
+index 0000000..3829019
+--- /dev/null
++++ b/rules/55-udev-smack-default.rules
+@@ -0,0 +1,23 @@
++# do not edit this file, it will be overwritten on update
++
++KERNEL=="null", SECLABEL{smack}="*"
++KERNEL=="zero", SECLABEL{smack}="*"
++KERNEL=="console", SECLABEL{smack}="*"
++KERNEL=="kmsg", SECLABEL{smack}="*"
++KERNEL=="video*", SECLABEL{smack}="*"
++KERNEL=="card*", SECLABEL{smack}="*"
++KERNEL=="ptmx", SECLABEL{smack}="*"
++KERNEL=="tty", SECLABEL{smack}="*"
++
++SUBSYSTEM=="graphics", GROUP="video", SECLABEL{smack}="*"
++SUBSYSTEM=="drm", GROUP="video", SECLABEL{smack}="*"
++SUBSYSTEM=="dvb", GROUP="video", SECLABEL{smack}="*"
++
++SUBSYSTEM=="tty", KERNEL=="ptmx", GROUP="tty", MODE="0666", SECLABEL{smack}="*"
++SUBSYSTEM=="tty", KERNEL=="tty", GROUP="tty", MODE="0666", SECLABEL{smack}="*"
++SUBSYSTEM=="tty", KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620", SECLABEL{smack}="*"
++SUBSYSTEM=="vc", KERNEL=="vcs*|vcsa*", GROUP="tty", SECLABEL{smack}="*"
++KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout", SECLABEL{smack}="*"
++
++SUBSYSTEM=="input", KERNEL=="mouse*|mice|event*", MODE="0640", SECLABEL{smack}="*"
++SUBSYSTEM=="input", KERNEL=="ts[0-9]*|uinput", MODE="0640", SECLABEL{smack}="*"
+--
+1.8.4.5
+
diff --git a/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v216.patch b/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v216.patch
new file mode 100644
index 000000000..3d69bb2a8
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v216.patch
@@ -0,0 +1,107 @@
+From c257eade1a39ea00d26c4c297efd654b6ad4edb4 Mon Sep 17 00:00:00 2001
+From: Casey Schaufler <casey@schaufler-ca.com>
+Date: Fri, 8 Nov 2013 09:42:26 -0800
+Subject: [PATCH 5/9] tizen-smack: Handling network
+
+- Set Smack ambient to match run label
+- Set Smack netlabel host rules
+
+Set Smack ambient to match run label
+------------------------------------
+Set the Smack networking ambient label to match the
+run label of systemd. System services may expect to
+communicate with external services over IP. Setting
+the ambient label assigns that label to IP packets
+that do not include CIPSO headers. This allows systemd
+and the services it spawns access to unlabeled IP
+packets, and hence external services.
+
+A system may choose to restrict network access to
+particular services later in the startup process.
+This is easily done by resetting the ambient label
+elsewhere.
+
+Set Smack netlabel host rules
+-----------------------------
+If SMACK_RUN_LABEL is defined set all other hosts to be
+single label hosts at the specified label. Set the loopback
+address to be a CIPSO host.
+
+If any netlabel host rules are defined in /etc/smack/netlabel.d
+install them into the smackfs netlabel interface.
+
+Upstream-Status: Pending
+
+---
+ src/core/smack-setup.c | 33 ++++++++++++++++++++++++++++++++-
+ 1 file changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
+index 59f6832..33dc1ca 100644
+--- a/src/core/smack-setup.c
++++ b/src/core/smack-setup.c
+@@ -42,6 +42,7 @@
+
+ #define SMACK_CONFIG "/etc/smack/accesses.d/"
+ #define CIPSO_CONFIG "/etc/smack/cipso.d/"
++#define NETLABEL_CONFIG "/etc/smack/netlabel.d/"
+
+ #ifdef HAVE_SMACK
+
+@@ -146,6 +147,19 @@ int smack_setup(bool *loaded_policy) {
+ if (r)
+ log_warning("Failed to set SMACK label \"%s\" on self: %s",
+ SMACK_RUN_LABEL, strerror(-r));
++ r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL);
++ if (r)
++ log_warning("Failed to set SMACK ambient label \"%s\": %s",
++ SMACK_RUN_LABEL, strerror(-r));
++ r = write_string_file("/sys/fs/smackfs/netlabel",
++ "0.0.0.0/0 " SMACK_RUN_LABEL);
++ if (r)
++ log_warning("Failed to set SMACK netlabel rule \"%s\": %s",
++ "0.0.0.0/0 " SMACK_RUN_LABEL, strerror(-r));
++ r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO");
++ if (r)
++ log_warning("Failed to set SMACK netlabel rule \"%s\": %s",
++ "127.0.0.1 -CIPSO", strerror(-r));
+ #endif
+
+ r = write_rules("/sys/fs/smackfs/cipso2", CIPSO_CONFIG);
+@@ -155,14 +169,31 @@ int smack_setup(bool *loaded_policy) {
+ return 0;
+ case ENOENT:
+ log_debug("Smack/CIPSO access rules directory " CIPSO_CONFIG " not found");
+- return 0;
++ break;
+ case 0:
+ log_info("Successfully loaded Smack/CIPSO policies.");
+- return 0;
++ break;
+ default:
+ log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.",
+ strerror(abs(r)));
++ break;
++ }
++
++ r = write_rules("/sys/fs/smackfs/netlabel", NETLABEL_CONFIG);
++ switch(r) {
++ case -ENOENT:
++ log_debug("Smack/CIPSO is not enabled in the kernel.");
+ return 0;
++ case ENOENT:
++ log_debug("Smack network host rules directory " NETLABEL_CONFIG " not found");
++ break;
++ case 0:
++ log_info("Successfully loaded Smack network host rules.");
++ break;
++ default:
++ log_warning("Failed to load Smack network host rules: %s, ignoring.",
++ strerror(abs(r)));
++ break;
+ }
+
+ *loaded_policy = true;
+--
+1.8.4.5
+
diff --git a/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v225.patch b/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v225.patch
new file mode 100644
index 000000000..d5678f2e6
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v225.patch
@@ -0,0 +1,191 @@
+From 513a8d943538643fabf0d31f1eed261677dfbddc Mon Sep 17 00:00:00 2001
+From: Casey Schaufler <casey@schaufler-ca.com>
+Date: Fri, 8 Nov 2013 09:42:26 -0800
+Subject: [PATCH] tizen-smack: Handling network
+
+- Set Smack ambient to match run label
+- Set Smack netlabel host rules
+
+Set Smack ambient to match run label
+------------------------------------
+Set the Smack networking ambient label to match the
+run label of systemd. System services may expect to
+communicate with external services over IP. Setting
+the ambient label assigns that label to IP packets
+that do not include CIPSO headers. This allows systemd
+and the services it spawns access to unlabeled IP
+packets, and hence external services.
+
+A system may choose to restrict network access to
+particular services later in the startup process.
+This is easily done by resetting the ambient label
+elsewhere.
+
+Set Smack netlabel host rules
+-----------------------------
+If SMACK_RUN_LABEL is defined set all other hosts to be
+single label hosts at the specified label. Set the loopback
+address to be a CIPSO host.
+
+If any netlabel host rules are defined in /etc/smack/netlabel.d
+install them into the smackfs netlabel interface.
+
+[Patrick Ohly: adapt to write_string_file() change in "fileio: consolidate write_string_file*()"]
+[Patrick Ohly: create write_netlabel_rules() based on the original write_rules() that was removed in "smack: support smack access change-rule"]
+
+Upstream-Status: Pending
+---
+ src/core/smack-setup.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 106 insertions(+), 3 deletions(-)
+
+diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
+index cbe7d0b..b384aa0 100644
+--- a/src/core/smack-setup.c
++++ b/src/core/smack-setup.c
+@@ -34,6 +34,9 @@
+ #include "fileio.h"
+ #include "log.h"
+
++#define CIPSO_CONFIG "/etc/smack/cipso.d/"
++#define NETLABEL_CONFIG "/etc/smack/netlabel.d/"
++
+ #ifdef HAVE_SMACK
+
+ static int write_access2_rules(const char* srcdir) {
+@@ -193,6 +196,76 @@ static int write_cipso2_rules(const char* srcdir) {
+ return r;
+ }
+
++static int write_netlabel_rules(const char* srcdir) {
++ _cleanup_fclose_ FILE *dst = NULL;
++ _cleanup_closedir_ DIR *dir = NULL;
++ struct dirent *entry;
++ char buf[NAME_MAX];
++ int dfd = -1;
++ int r = 0;
++ static const char dstpath[] = "/sys/fs/smackfs/netlabel";
++
++ dst = fopen(dstpath, "we");
++ if (!dst) {
++ if (errno != ENOENT)
++ log_warning_errno(errno, "Failed to open %s: %m", dstpath);
++ return -errno; /* negative error */
++ }
++
++ /* write rules to dst from every file in the directory */
++ dir = opendir(srcdir);
++ if (!dir) {
++ if (errno != ENOENT)
++ log_warning_errno(errno, "Failed to opendir %s: %m", srcdir);
++ return errno; /* positive on purpose */
++ }
++
++ dfd = dirfd(dir);
++ assert(dfd >= 0);
++
++ FOREACH_DIRENT(entry, dir, return 0) {
++ int fd;
++ _cleanup_fclose_ FILE *policy = NULL;
++
++ fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
++ if (fd < 0) {
++ if (r == 0)
++ r = -errno;
++ log_warning_errno(errno, "Failed to open %s: %m", entry->d_name);
++ continue;
++ }
++
++ policy = fdopen(fd, "re");
++ if (!policy) {
++ if (r == 0)
++ r = -errno;
++ safe_close(fd);
++ log_error_errno(errno, "Failed to open %s: %m", entry->d_name);
++ continue;
++ }
++
++ /* load2 write rules in the kernel require a line buffered stream */
++ FOREACH_LINE(buf, policy,
++ log_error_errno(errno, "Failed to read line from %s: %m",
++ entry->d_name)) {
++ if (!fputs(buf, dst)) {
++ if (r == 0)
++ r = -EINVAL;
++ log_error("Failed to write line to %s", dstpath);
++ break;
++ }
++ if (fflush(dst)) {
++ if (r == 0)
++ r = -errno;
++ log_error_errno(errno, "Failed to flush writes to %s: %m", dstpath);
++ break;
++ }
++ }
++ }
++
++ return r;
++}
++
+ #endif
+
+ int mac_smack_setup(bool *loaded_policy) {
+@@ -225,23 +298,53 @@ int mac_smack_setup(bool *loaded_policy) {
+ if (r)
+ log_warning("Failed to set SMACK label \"%s\" on self: %s",
+ SMACK_RUN_LABEL, strerror(-r));
++ r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, 0);
++ if (r)
++ log_warning("Failed to set SMACK ambient label \"%s\": %s",
++ SMACK_RUN_LABEL, strerror(-r));
++ r = write_string_file("/sys/fs/smackfs/netlabel",
++ "0.0.0.0/0 " SMACK_RUN_LABEL, 0);
++ if (r)
++ log_warning("Failed to set SMACK netlabel rule \"%s\": %s",
++ "0.0.0.0/0 " SMACK_RUN_LABEL, strerror(-r));
++ r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", 0);
++ if (r)
++ log_warning("Failed to set SMACK netlabel rule \"%s\": %s",
++ "127.0.0.1 -CIPSO", strerror(-r));
+ #endif
+
+- r = write_cipso2_rules("/etc/smack/cipso.d/");
++ r = write_cipso2_rules(CIPSO_CONFIG);
+ switch(r) {
+ case -ENOENT:
+ log_debug("Smack/CIPSO is not enabled in the kernel.");
+ return 0;
+ case ENOENT:
+- log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found");
+- return 0;
++ log_debug("Smack/CIPSO access rules directory " CIPSO_CONFIG " not found");
++ break;
+ case 0:
+ log_info("Successfully loaded Smack/CIPSO policies.");
+ break;
+ default:
+ log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.",
+ strerror(abs(r)));
++ break;
++ }
++
++ r = write_netlabel_rules(NETLABEL_CONFIG);
++ switch(r) {
++ case -ENOENT:
++ log_debug("Smack/CIPSO is not enabled in the kernel.");
+ return 0;
++ case ENOENT:
++ log_debug("Smack network host rules directory " NETLABEL_CONFIG " not found");
++ break;
++ case 0:
++ log_info("Successfully loaded Smack network host rules.");
++ break;
++ default:
++ log_warning("Failed to load Smack network host rules: %s, ignoring.",
++ strerror(abs(r)));
++ break;
+ }
+
+ *loaded_policy = true;
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v228.patch b/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v228.patch
new file mode 100644
index 000000000..bc6b97c8f
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network-v228.patch
@@ -0,0 +1,179 @@
+From e714327016fb65a0bf977588efaecbaf41ac3cfc Mon Sep 17 00:00:00 2001
+From: Casey Schaufler <casey@schaufler-ca.com>
+Date: Fri, 8 Nov 2013 09:42:26 -0800
+Subject: [PATCH 4/6] tizen-smack: Handling network
+
+- Set Smack ambient to match run label
+- Set Smack netlabel host rules
+
+Set Smack ambient to match run label
+------------------------------------
+Set the Smack networking ambient label to match the
+run label of systemd. System services may expect to
+communicate with external services over IP. Setting
+the ambient label assigns that label to IP packets
+that do not include CIPSO headers. This allows systemd
+and the services it spawns access to unlabeled IP
+packets, and hence external services.
+
+A system may choose to restrict network access to
+particular services later in the startup process.
+This is easily done by resetting the ambient label
+elsewhere.
+
+Set Smack netlabel host rules
+-----------------------------
+If SMACK_RUN_LABEL is defined set all other hosts to be
+single label hosts at the specified label. Set the loopback
+address to be a CIPSO host.
+
+If any netlabel host rules are defined in /etc/smack/netlabel.d
+install them into the smackfs netlabel interface.
+
+[Patrick Ohly: copied from https://review.tizen.org/git/?p=platform/upstream/systemd.git;a=commit;h=db4f6c9a074644aa2bf]
+[Patrick Ohly: adapt to write_string_file() change in "fileio: consolidate write_string_file*()"]
+[Patrick Ohly: create write_netlabel_rules() based on the original write_rules() that was removed in "smack: support smack access change-rule"]
+[Patrick Ohly: adapted to upstream code review feedback: error logging, string constants]
+
+Upstream-Status: Accepted [https://github.com/systemd/systemd/pull/2262]
+
+%% original patch: 0005-tizen-smack-Handling-network-v225.patch
+---
+ src/core/smack-setup.c | 101 +++++++++++++++++++++++++++++++++++++++++++++++--
+ 1 file changed, 98 insertions(+), 3 deletions(-)
+
+diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
+index 0661ff9..c9374ca 100644
+--- a/src/core/smack-setup.c
++++ b/src/core/smack-setup.c
+@@ -197,6 +197,75 @@ static int write_cipso2_rules(const char* srcdir) {
+ return r;
+ }
+
++static int write_netlabel_rules(const char* srcdir) {
++ _cleanup_fclose_ FILE *dst = NULL;
++ _cleanup_closedir_ DIR *dir = NULL;
++ struct dirent *entry;
++ char buf[NAME_MAX];
++ int dfd = -1;
++ int r = 0;
++
++ dst = fopen("/sys/fs/smackfs/netlabel", "we");
++ if (!dst) {
++ if (errno != ENOENT)
++ log_warning_errno(errno, "Failed to open /sys/fs/smackfs/netlabel: %m");
++ return -errno; /* negative error */
++ }
++
++ /* write rules to dst from every file in the directory */
++ dir = opendir(srcdir);
++ if (!dir) {
++ if (errno != ENOENT)
++ log_warning_errno(errno, "Failed to opendir %s: %m", srcdir);
++ return errno; /* positive on purpose */
++ }
++
++ dfd = dirfd(dir);
++ assert(dfd >= 0);
++
++ FOREACH_DIRENT(entry, dir, return 0) {
++ int fd;
++ _cleanup_fclose_ FILE *policy = NULL;
++
++ fd = openat(dfd, entry->d_name, O_RDONLY|O_CLOEXEC);
++ if (fd < 0) {
++ if (r == 0)
++ r = -errno;
++ log_warning_errno(errno, "Failed to open %s: %m", entry->d_name);
++ continue;
++ }
++
++ policy = fdopen(fd, "re");
++ if (!policy) {
++ if (r == 0)
++ r = -errno;
++ safe_close(fd);
++ log_error_errno(errno, "Failed to open %s: %m", entry->d_name);
++ continue;
++ }
++
++ /* load2 write rules in the kernel require a line buffered stream */
++ FOREACH_LINE(buf, policy,
++ log_error_errno(errno, "Failed to read line from %s: %m",
++ entry->d_name)) {
++ if (!fputs(buf, dst)) {
++ if (r == 0)
++ r = -EINVAL;
++ log_error_errno(errno, "Failed to write line to /sys/fs/smackfs/netlabel");
++ break;
++ }
++ if (fflush(dst)) {
++ if (r == 0)
++ r = -errno;
++ log_error_errno(errno, "Failed to flush writes to /sys/fs/smackfs/netlabel: %m");
++ break;
++ }
++ }
++ }
++
++ return r;
++}
++
+ #endif
+
+ int mac_smack_setup(bool *loaded_policy) {
+@@ -225,8 +294,18 @@ int mac_smack_setup(bool *loaded_policy) {
+
+ #ifdef SMACK_RUN_LABEL
+ r = write_string_file("/proc/self/attr/current", SMACK_RUN_LABEL, 0);
+- if (r)
+- log_warning_errno(r, "Failed to set SMACK label \"%s\" on self: %m", SMACK_RUN_LABEL);
++ if (r < 0)
++ log_warning_errno(r, "Failed to set SMACK label \"" SMACK_RUN_LABEL "\" on self: %m");
++ r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL, 0);
++ if (r < 0)
++ log_warning_errno(r, "Failed to set SMACK ambient label \"" SMACK_RUN_LABEL "\": %m");
++ r = write_string_file("/sys/fs/smackfs/netlabel",
++ "0.0.0.0/0 " SMACK_RUN_LABEL, 0);
++ if (r < 0)
++ log_warning_errno(r, "Failed to set SMACK netlabel rule \"0.0.0.0/0 " SMACK_RUN_LABEL "\": %m");
++ r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO", 0);
++ if (r < 0)
++ log_warning_errno(r, "Failed to set SMACK netlabel rule \"127.0.0.1 -CIPSO\": %m");
+ #endif
+
+ r = write_cipso2_rules("/etc/smack/cipso.d/");
+@@ -236,13 +315,29 @@ int mac_smack_setup(bool *loaded_policy) {
+ return 0;
+ case ENOENT:
+ log_debug("Smack/CIPSO access rules directory '/etc/smack/cipso.d/' not found");
+- return 0;
++ break;
+ case 0:
+ log_info("Successfully loaded Smack/CIPSO policies.");
+ break;
+ default:
+ log_warning_errno(r, "Failed to load Smack/CIPSO access rules, ignoring: %m");
++ break;
++ }
++
++ r = write_netlabel_rules("/etc/smack/netlabel.d/");
++ switch(r) {
++ case -ENOENT:
++ log_debug("Smack/CIPSO is not enabled in the kernel.");
+ return 0;
++ case ENOENT:
++ log_debug("Smack network host rules directory '/etc/smack/netlabel.d/' not found");
++ break;
++ case 0:
++ log_info("Successfully loaded Smack network host rules.");
++ break;
++ default:
++ log_warning_errno(r, "Failed to load Smack network host rules: %m, ignoring.");
++ break;
+ }
+
+ *loaded_policy = true;
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network.patch b/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network.patch
new file mode 100644
index 000000000..cd6a3c90b
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/0005-tizen-smack-Handling-network.patch
@@ -0,0 +1,106 @@
+From c257eade1a39ea00d26c4c297efd654b6ad4edb4 Mon Sep 17 00:00:00 2001
+From: Casey Schaufler <casey@schaufler-ca.com>
+Date: Fri, 8 Nov 2013 09:42:26 -0800
+Subject: [PATCH 5/9] tizen-smack: Handling network
+
+- Set Smack ambient to match run label
+- Set Smack netlabel host rules
+
+Set Smack ambient to match run label
+------------------------------------
+Set the Smack networking ambient label to match the
+run label of systemd. System services may expect to
+communicate with external services over IP. Setting
+the ambient label assigns that label to IP packets
+that do not include CIPSO headers. This allows systemd
+and the services it spawns access to unlabeled IP
+packets, and hence external services.
+
+A system may choose to restrict network access to
+particular services later in the startup process.
+This is easily done by resetting the ambient label
+elsewhere.
+
+Set Smack netlabel host rules
+-----------------------------
+If SMACK_RUN_LABEL is defined set all other hosts to be
+single label hosts at the specified label. Set the loopback
+address to be a CIPSO host.
+
+If any netlabel host rules are defined in /etc/smack/netlabel.d
+install them into the smackfs netlabel interface.
+
+Upstream-Status: Pending
+
+---
+ src/core/smack-setup.c | 33 ++++++++++++++++++++++++++++++++-
+ 1 file changed, 32 insertions(+), 1 deletion(-)
+
+diff --git a/src/core/smack-setup.c b/src/core/smack-setup.c
+index 59f6832..33dc1ca 100644
+--- a/src/core/smack-setup.c
++++ b/src/core/smack-setup.c
+@@ -42,6 +42,7 @@
+
+ #define SMACK_CONFIG "/etc/smack/accesses.d/"
+ #define CIPSO_CONFIG "/etc/smack/cipso.d/"
++#define NETLABEL_CONFIG "/etc/smack/netlabel.d/"
+
+ #ifdef HAVE_SMACK
+
+@@ -146,6 +147,19 @@ int mac_smack_setup(bool *loaded_policy) {
+ if (r)
+ log_warning("Failed to set SMACK label \"%s\" on self: %s",
+ SMACK_RUN_LABEL, strerror(-r));
++ r = write_string_file("/sys/fs/smackfs/ambient", SMACK_RUN_LABEL);
++ if (r)
++ log_warning("Failed to set SMACK ambient label \"%s\": %s",
++ SMACK_RUN_LABEL, strerror(-r));
++ r = write_string_file("/sys/fs/smackfs/netlabel",
++ "0.0.0.0/0 " SMACK_RUN_LABEL);
++ if (r)
++ log_warning("Failed to set SMACK netlabel rule \"%s\": %s",
++ "0.0.0.0/0 " SMACK_RUN_LABEL, strerror(-r));
++ r = write_string_file("/sys/fs/smackfs/netlabel", "127.0.0.1 -CIPSO");
++ if (r)
++ log_warning("Failed to set SMACK netlabel rule \"%s\": %s",
++ "127.0.0.1 -CIPSO", strerror(-r));
+ #endif
+
+ r = write_rules("/sys/fs/smackfs/cipso2", CIPSO_CONFIG);
+@@ -155,14 +169,31 @@ int mac_smack_setup(bool *loaded_policy) {
+ return 0;
+ case ENOENT:
+ log_debug("Smack/CIPSO access rules directory " CIPSO_CONFIG " not found");
+- return 0;
++ break;
+ case 0:
+ log_info("Successfully loaded Smack/CIPSO policies.");
+ break;
+ default:
+ log_warning("Failed to load Smack/CIPSO access rules: %s, ignoring.",
+ strerror(abs(r)));
++ break;
++ }
++
++ r = write_rules("/sys/fs/smackfs/netlabel", NETLABEL_CONFIG);
++ switch(r) {
++ case -ENOENT:
++ log_debug("Smack/CIPSO is not enabled in the kernel.");
+ return 0;
++ case ENOENT:
++ log_debug("Smack network host rules directory " NETLABEL_CONFIG " not found");
++ break;
++ case 0:
++ log_info("Successfully loaded Smack network host rules.");
++ break;
++ default:
++ log_warning("Failed to load Smack network host rules: %s, ignoring.",
++ strerror(abs(r)));
++ break;
+ }
+
+ *loaded_policy = true;
+--
+1.8.4.5
+
diff --git a/meta-security/recipes-core/systemd/systemd/0007-tizen-smack-Runs-systemd-journald-with-v216.patch b/meta-security/recipes-core/systemd/systemd/0007-tizen-smack-Runs-systemd-journald-with-v216.patch
new file mode 100644
index 000000000..dd2c6542e
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/0007-tizen-smack-Runs-systemd-journald-with-v216.patch
@@ -0,0 +1,41 @@
+From ccf384ca0f1cabe37e07e752df95ddb1e017a7ef Mon Sep 17 00:00:00 2001
+From: Casey Schaufler <casey@schaufler-ca.com>
+Date: Thu, 19 Dec 2013 16:49:28 -0800
+Subject: [PATCH 7/9] tizen-smack: Runs systemd-journald with ^
+
+Run systemd-journald with the hat ("^") Smack label.
+
+The journal daemon needs global read access to gather information
+about the services spawned by systemd. The hat label is intended
+for this purpose. The journal daemon is the only part of the
+System domain that needs read access to the User domain. Giving
+the journal daemon the hat label means that we can remove the
+System domain's read access to the User domain.
+
+Upstream-Status: Inappropriate [configuration]
+
+Change-Id: Ic22633f0c9d99c04f873be8a346786ea577d0370
+Signed-off-by: Casey Schaufler <casey.schaufler@intel.com>
+---
+ units/systemd-journald.service.in | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in
+index a3540c6..745dd84 100644
+--- a/units/systemd-journald.service.in
++++ b/units/systemd-journald.service.in
+@@ -20,8 +20,10 @@ Restart=always
+ RestartSec=0
+ NotifyAccess=all
+ StandardOutput=null
++SmackProcessLabel=^
+-CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID
++CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE
+ WatchdogSec=1min
++FileDescriptorStoreMax=1024
+
+ # Increase the default a bit in order to allow many simultaneous
+ # services being run since we keep one fd open per service.
+--
+1.8.4.5
+
diff --git a/meta-security/recipes-core/systemd/systemd/0007-tizen-smack-Runs-systemd-journald-with.patch b/meta-security/recipes-core/systemd/systemd/0007-tizen-smack-Runs-systemd-journald-with.patch
new file mode 100644
index 000000000..27a9d0bc6
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/0007-tizen-smack-Runs-systemd-journald-with.patch
@@ -0,0 +1,37 @@
+From ccf384ca0f1cabe37e07e752df95ddb1e017a7ef Mon Sep 17 00:00:00 2001
+From: Casey Schaufler <casey@schaufler-ca.com>
+Date: Thu, 19 Dec 2013 16:49:28 -0800
+Subject: [PATCH 7/9] tizen-smack: Runs systemd-journald with ^
+
+Run systemd-journald with the hat ("^") Smack label.
+
+The journal daemon needs global read access to gather information
+about the services spawned by systemd. The hat label is intended
+for this purpose. The journal daemon is the only part of the
+System domain that needs read access to the User domain. Giving
+the journal daemon the hat label means that we can remove the
+System domain's read access to the User domain.
+
+Upstream-Status: Inappropriate [configuration]
+
+Change-Id: Ic22633f0c9d99c04f873be8a346786ea577d0370
+Signed-off-by: Casey Schaufler <casey.schaufler@intel.com>
+---
+ units/systemd-journald.service.in | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/units/systemd-journald.service.in b/units/systemd-journald.service.in
+index a3540c6..745dd84 100644
+--- a/units/systemd-journald.service.in
++++ b/units/systemd-journald.service.in
+@@ -21,6 +21,7 @@ Restart=always
+ RestartSec=0
+ NotifyAccess=all
+ StandardOutput=null
++SmackProcessLabel=^
+ CapabilityBoundingSet=CAP_SYS_ADMIN CAP_DAC_OVERRIDE CAP_SYS_PTRACE CAP_SYSLOG CAP_AUDIT_CONTROL CAP_AUDIT_READ CAP_CHOWN CAP_DAC_READ_SEARCH CAP_FOWNER CAP_SETUID CAP_SETGID CAP_MAC_OVERRIDE
+ WatchdogSec=1min
+ FileDescriptorStoreMax=1024
+--
+1.8.4.5
+
diff --git a/meta-security/recipes-core/systemd/systemd/mount-setup.c-fix-handling-of-symlink-Smack-labellin-v228.patch b/meta-security/recipes-core/systemd/systemd/mount-setup.c-fix-handling-of-symlink-Smack-labellin-v228.patch
new file mode 100644
index 000000000..5a1baefed
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/mount-setup.c-fix-handling-of-symlink-Smack-labellin-v228.patch
@@ -0,0 +1,58 @@
+From fd84be63d15fc94c1f396979c67e070c6cd7451b Mon Sep 17 00:00:00 2001
+From: Patrick Ohly <patrick.ohly@intel.com>
+Date: Mon, 21 Dec 2015 14:56:00 +0100
+Subject: [PATCH] mount-setup.c: fix handling of symlink Smack labelling in
+ cgroup setup
+
+The code introduced in f8c1a81c51 (= systemd 227) failed for me with:
+ Failed to copy smack label from net_cls to /sys/fs/cgroup/net_cls: No such file or directory
+
+There is no need for a symlink in this case because source and target
+are identical. The symlink() call is allowed to fail when the target
+already exists. When that happens, copying the Smack label must be
+skipped.
+
+But the code also failed when there is a symlink, like "cpu ->
+cpu,cpuacct", because mac_smack_copy() got called with
+src="cpu,cpuacct" which fails to find the entry because the current
+directory is not inside /sys/fs/cgroup. The absolute path to the existing
+entry must be used instead.
+
+Upstream-Status: Accepted [https://github.com/systemd/systemd/pull/2205]
+
+Signed-off-by: Patrick Ohly <patrick.ohly@intel.com>
+---
+ src/core/mount-setup.c | 15 ++++++++++-----
+ 1 file changed, 10 insertions(+), 5 deletions(-)
+
+diff --git a/src/core/mount-setup.c b/src/core/mount-setup.c
+index 2b8d590..d73b319 100644
+--- a/src/core/mount-setup.c
++++ b/src/core/mount-setup.c
+@@ -304,13 +304,18 @@ int mount_cgroup_controllers(char ***join_controllers) {
+ return log_oom();
+
+ r = symlink(options, t);
+- if (r < 0 && errno != EEXIST)
+- return log_error_errno(errno, "Failed to create symlink %s: %m", t);
++ if (r >= 0) {
+ #ifdef SMACK_RUN_LABEL
+- r = mac_smack_copy(t, options);
+- if (r < 0 && r != -EOPNOTSUPP)
+- return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", options, t);
++ _cleanup_free_ char *src;
++ src = strappend("/sys/fs/cgroup/", options);
++ if (!src)
++ return log_oom();
++ r = mac_smack_copy(t, src);
++ if (r < 0 && r != -EOPNOTSUPP)
++ return log_error_errno(r, "Failed to copy smack label from %s to %s: %m", src, t);
+ #endif
++ } else if (errno != EEXIST)
++ return log_error_errno(errno, "Failed to create symlink %s: %m", t);
+ }
+ }
+ }
+--
+2.1.4
+
diff --git a/meta-security/recipes-core/systemd/systemd/udev-smack-default.rules b/meta-security/recipes-core/systemd/systemd/udev-smack-default.rules
new file mode 100644
index 000000000..3829019de
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd/udev-smack-default.rules
@@ -0,0 +1,23 @@
+# do not edit this file, it will be overwritten on update
+
+KERNEL=="null", SECLABEL{smack}="*"
+KERNEL=="zero", SECLABEL{smack}="*"
+KERNEL=="console", SECLABEL{smack}="*"
+KERNEL=="kmsg", SECLABEL{smack}="*"
+KERNEL=="video*", SECLABEL{smack}="*"
+KERNEL=="card*", SECLABEL{smack}="*"
+KERNEL=="ptmx", SECLABEL{smack}="*"
+KERNEL=="tty", SECLABEL{smack}="*"
+
+SUBSYSTEM=="graphics", GROUP="video", SECLABEL{smack}="*"
+SUBSYSTEM=="drm", GROUP="video", SECLABEL{smack}="*"
+SUBSYSTEM=="dvb", GROUP="video", SECLABEL{smack}="*"
+
+SUBSYSTEM=="tty", KERNEL=="ptmx", GROUP="tty", MODE="0666", SECLABEL{smack}="*"
+SUBSYSTEM=="tty", KERNEL=="tty", GROUP="tty", MODE="0666", SECLABEL{smack}="*"
+SUBSYSTEM=="tty", KERNEL=="tty[0-9]*", GROUP="tty", MODE="0620", SECLABEL{smack}="*"
+SUBSYSTEM=="vc", KERNEL=="vcs*|vcsa*", GROUP="tty", SECLABEL{smack}="*"
+KERNEL=="tty[A-Z]*[0-9]|pppox[0-9]*|ircomm[0-9]*|noz[0-9]*|rfcomm[0-9]*", GROUP="dialout", SECLABEL{smack}="*"
+
+SUBSYSTEM=="input", KERNEL=="mouse*|mice|event*", MODE="0640", SECLABEL{smack}="*"
+SUBSYSTEM=="input", KERNEL=="ts[0-9]*|uinput", MODE="0640", SECLABEL{smack}="*"
diff --git a/meta-security/recipes-core/systemd/systemd_%.bbappend b/meta-security/recipes-core/systemd/systemd_%.bbappend
new file mode 100644
index 000000000..bea5a3731
--- /dev/null
+++ b/meta-security/recipes-core/systemd/systemd_%.bbappend
@@ -0,0 +1,120 @@
+FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"
+
+# Most patches from sandbox/jobol/v219. Cannot be applied unconditionally
+# because systemd panics when booted without Smack support:
+# systemd[1]: Cannot determine cgroup we are running in: No such file or directory
+# systemd[1]: Failed to allocate manager object: No such file or directory
+# [!!!!!!] Failed to allocate manager object, freezing.
+#
+# There's a slight dependency on the base systemd in 0005-tizen-smack-Handling-network.
+# We use the beginning of PV (unexpanded here to prevent a cyclic dependency
+# during resolution apparently caused by ${SRCPV}) to pick the right set of
+# patches.
+#
+# Patches are optional. Hopefully we won't need any for systemd >= 229.
+SRC_URI_append_with-lsm-smack = " ${@d.getVar('SYSTEMD_SMACK_PATCHES_' + d.getVar('PV', False)[0:3], True) or ''}"
+
+SYSTEMD_SMACK_PATCHES_216 = " \
+file://0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup-v216.patch \
+file://0004-tizen-smack-Handling-of-dev-v216.patch \
+file://0005-tizen-smack-Handling-network-v216.patch \
+file://0007-tizen-smack-Runs-systemd-journald-with-v216.patch \
+"
+
+SYSTEMD_SMACK_PATCHES_219 = " \
+file://0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup.patch \
+file://0004-tizen-smack-Handling-of-dev.patch \
+file://0005-tizen-smack-Handling-network.patch \
+file://0007-tizen-smack-Runs-systemd-journald-with.patch \
+"
+SYSTEMD_SMACK_PATCHES_225 = " \
+file://0003-tizen-smack-Handling-of-run-and-sys-fs-cgroup.patch \
+file://0004-tizen-smack-Handling-of-dev.patch \
+file://0005-tizen-smack-Handling-network-v225.patch \
+file://0007-tizen-smack-Runs-systemd-journald-with.patch \
+"
+
+SYSTEMD_SMACK_PATCHES_228 = " \
+file://0005-tizen-smack-Handling-network-v228.patch \
+file://mount-setup.c-fix-handling-of-symlink-Smack-labellin-v228.patch \
+"
+
+# From Tizen .spec file.
+EXTRA_OECONF_append_with-lsm-smack = " --with-smack-run-label=System"
+
+install_file() {
+ install -d $(dirname $1)
+ cat >>$1
+ chmod ${2:-0644} $1
+}
+
+# We need to emulate parts of the filesystem permissions from Tizen here.
+# The part for regular files is in base-files.bbappend, but /var/log and
+# /var/tmp point into /var/volatile (tmpfs) and get created anew during
+# startup. We set these permissions directly after creating them via
+# /etc/tmpfiles.d/00-create-volatile.conf
+RDEPENDS_${PN}_append_with-lsm-smack = " smack-userspace"
+do_install_append_with-lsm-smack() {
+ install_file ${D}${systemd_unitdir}/system/systemd-tmpfiles-setup.service.d/smack.conf <<EOF
+[Service]
+ExecStartPost=/bin/sh -c '([ ! -d /var/tmp ] || chsmack -L -a \"*\" /var/tmp) && ([ ! -d /var/log ] || chsmack -L -a System::Log /var/log && chsmack -L -t /var/log)'
+EOF
+
+ # Mount /tmp publicly accessable. Based on patch by Michael Demeter <michael.demeter@intel.com>.
+ # Upstream systemd temporarily had SmackFileSystemRoot for this (https://github.com/systemd/systemd/pull/1664),
+ # but it was removed again (https://github.com/systemd/systemd/issues/1696) because
+ # util-linux mount will ignore smackfsroot when Smack is not active. However,
+ # busybox is not that intelligent.
+ #
+ # When using busybox mount, adding smackfsroot=* and booting without
+ # Smack (i.e. security=none), tmp.mount will fail with an error about
+ # "Bad mount option smackfsroot".
+ install_file ${D}${systemd_unitdir}/system/tmp.mount.d/smack.conf <<EOF
+[Mount]
+Options=smackfsroot=*
+EOF
+
+ # Run systemd-journald with the hat ("^") Smack label.
+ #
+ # The journal daemon needs global read access to gather information
+ # about the services spawned by systemd. The hat label is intended
+ # for this purpose. The journal daemon is the only part of the
+ # System domain that needs read access to the User domain. Giving
+ # the journal daemon the hat label means that we can remove the
+ # System domain's read access to the User domain and we can avoid
+ # hard-coding a specific label name for that domain.
+ #
+ # Original author: Casey Schaufler <casey@schaufler-ca.com>
+ #
+ # This is considered a configuration change and thus distro specific.
+ install_file ${D}${systemd_unitdir}/system/systemd-journald.service.d/smack.conf <<EOF
+[Service]
+SmackProcessLabel=^
+EOF
+}
+
+# Will get installed in ${sysconfdir}/udev/rules.d/ by base systemd recipe.
+SRC_URI += "file://udev-smack-default.rules"
+
+# A workaround for a missing space in a SRC_URI_append in a private layer elsewhere:
+SRC_URI += ""
+
+# Maintaining trivial, non-upstreamable configuration changes as patches
+# is tedious. But in same cases (like early mounting of special directories)
+# the configuration has to be in code. We make these changes here directly.
+do_patch[prefuncs] += "patch_systemd"
+do_patch[vardeps] += "patch_systemd"
+patch_systemd() {
+ # Handling of /run and /sys/fs/cgroup. Make /run a transmuting directory to
+ # enable systemd communications with services in the User domain.
+ # Original patch by Michael Demeter <michael.demeter@intel.com>.
+ #
+ # We simplify the patching by touching only lines which check the result of
+ # mac_smack_use(). Those are the ones which are used when Smack is active.
+ #
+ # smackfsroot=* on /sys/fs/cgroup may be upstreamable, but smackfstransmute=System::Run
+ # is too distro specific (depends on Smack rules) and thus has to remain here.
+ sed -i -e 's;\("/sys/fs/cgroup", *"[^"]*", *"[^"]*\)\(.*mac_smack_use.*\);\1,smackfsroot=*\2;' \
+ -e 's;\("/run", *"[^"]*", *"[^"]*\)\(.*mac_smack_use.*\);\1,smackfstransmute=System::Run\2;' \
+ ${S}/src/core/mount-setup.c
+}
diff --git a/meta-security/recipes-core/util-linux/util-linux_%.bbappend b/meta-security/recipes-core/util-linux/util-linux_%.bbappend
new file mode 100644
index 000000000..05286f80d
--- /dev/null
+++ b/meta-security/recipes-core/util-linux/util-linux_%.bbappend
@@ -0,0 +1,8 @@
+# Enabling Smack support in util-linux enables special support
+# in [lib]mount for Smack mount options: they get removed if
+# Smack is not active in the current kernel. Important for
+# booting with "security=none" when userspace otherwise is
+# compiled to use Smack.
+
+PACKAGECONFIG_append_with-lsm-smack_class-target = " smack"
+PACKAGECONFIG[smack] = "--with-smack, --without-smack"