kdbus: add memfd_create() syscall number for aarch64
[platform/upstream/dbus.git] / dbus / dbus-transport-kdbus.c
old mode 100644 (file)
new mode 100755 (executable)
index e9aca6f..5bb82e5
@@ -32,7 +32,7 @@
 #include "dbus-marshal-gvariant.h"
 #include "dbus-marshal-validate.h"
 #include "dbus-asv-util.h"
-#include "kdbus.h"
+#include <linux/kdbus.h>
 #include "dbus-watch.h"
 #include "dbus-errors.h"
 #include "dbus-bus.h"
 
 #include <linux/version.h>
 #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 17, 0)
-#  if defined(__arm__) || defined(__aarch64__)
+#  if defined(__arm__)
 #    define __NR_memfd_create 385
-#  elif defined(__i386__)
+#  elif defined(__aarch64__)
 #    define __NR_memfd_create 279
+#  elif defined(__i386__)
+#    define __NR_memfd_create 356
+#  elif defined(__x86_64__)
+#    define __NR_memfd_create 319
 #  else
 #    error "Architecture not supported"
 #  endif
@@ -102,7 +106,7 @@ int debug = -1;
              ((uint8_t *)(iter) < (uint8_t *)(first) + (_size)) &&      \
                ((uint8_t *)(iter) >= (uint8_t *)(first));               \
              iter = (void*)(((uint8_t *)iter) + ALIGN8((iter)->size)))
-#define KDBUS_DEFAULT_TIMEOUT_NS   5000000000LU
+#define KDBUS_INFINITE_TIMEOUT_NS   0x3fffffffffffffffLLU
 
 /**
  * @defgroup DBusTransportKdbus DBusTransport implementations for kdbus
@@ -113,7 +117,7 @@ int debug = -1;
  */
 
 /** Default Size of the memory area for received non-memfd messages. */
-#define RECEIVE_POOL_SIZE_DEFAULT_SIZE (2 * 1024LU * 1024LU)
+#define RECEIVE_POOL_SIZE_DEFAULT_SIZE (16 * 1024LU * 1024LU)
 /** Name of environmental variable to define receive pool size*/
 #define RECEIVE_POOL_SIZE_ENV_VAR_NAME "KDBUS_MEMORY_POOL_SIZE"
 /** Max size of pool size in megabytes*/
@@ -235,8 +239,12 @@ reply_with_error_preset_sender (const char     *error_type,
   if (errMessage == NULL)
      return NULL;
 
-  if (sender)
-    dbus_message_set_sender (errMessage, sender);
+  if (sender && !dbus_message_set_sender (errMessage, sender))
+    {
+      _dbus_verbose ("oom");
+      dbus_message_unref (errMessage);
+      return NULL;
+    }
 
   return errMessage;
 }
@@ -373,10 +381,10 @@ bloom_add_pair (kdbus_bloom_data_t *bloom_data,
     return;
 
   size = strlen (parameter) + strlen (value) + 1;
-  if (size > 1024)
+  if (size >= 1024)
     return;
 
-  snprintf (buf, size, "%s:%s", parameter, value);
+  snprintf (buf, size + 1, "%s:%s", parameter, value);
   _kdbus_bloom_add_data (kdbus, bloom_data, buf, size);
 }
 
@@ -391,10 +399,10 @@ bloom_add_prefixes (kdbus_bloom_data_t *bloom_data,
   size_t size;
 
   size = strlen (parameter) + strlen (value) + 1;
-  if (size > 1024)
+  if (size >= 1024)
     return;
 
-  snprintf (buf, size, "%s:%s", parameter, value);
+  snprintf (buf, size + 1, "%s:%s", parameter, value);
 
   for (;;)
     {
@@ -504,30 +512,22 @@ parse_name (const char *name)
 
 static int
 prepare_mfd (int memfd,
-             const char *header,
-             uint64_t header_size,
              const char *body,
              uint64_t body_size)
 {
-  const char *data[] = { header, body };
-  uint64_t count[] = { header_size, body_size };
   int64_t wr;
-  size_t p;
 
   _dbus_verbose ("sending data via memfd\n");
-  for (p = 0; p < sizeof (data) / sizeof (data[0]); ++p)
+  while (body_size)
     {
-      while (count[p])
+      wr = write (memfd, body, body_size);
+      if (wr < 0)
         {
-          wr = write (memfd, data[p], count[p]);
-          if (wr < 0)
-            {
-              _dbus_verbose ("writing to memfd failed: (%d) %m\n", errno);
-              return -1;
-            }
-          count[p] -= wr;
-          data[p] += wr;
+          _dbus_verbose ("writing to memfd failed: (%d) %m\n", errno);
+          return -1;
         }
+      body_size -= wr;
+      body += wr;
     }
 
   // seal data - kdbus module needs it
@@ -566,15 +566,6 @@ send_message (DBusTransportKdbus *transport,
         {
           case ENXIO: /* no such id on the bus */
           case ESRCH:
-            dbus_set_error (error,
-                            DBUS_ERROR_NAME_HAS_NO_OWNER,
-                            "Name \"%s\" does not exist",
-                            destination);
-            break;
-
-          case EADDRNOTAVAIL:
-          case ECONNRESET:
-            /* when well known name is not available on the bus */
             if (is_auto_start)
                 dbus_set_error (error,
                                 DBUS_ERROR_SERVICE_UNKNOWN,
@@ -587,22 +578,53 @@ send_message (DBusTransportKdbus *transport,
                                 destination);
             break;
 
-          case EMLINK:
+          case EADDRNOTAVAIL:
+            dbus_set_error (error,
+                            DBUS_ERROR_SERVICE_UNKNOWN,
+                            "No support for activation for name: \"%s\"", destination);
+            break;
+
+          case EXFULL:
             dbus_set_error (error,
                             DBUS_ERROR_LIMITS_EXCEEDED,
-                            NULL,
-                            "The maximum number of pending replies per connection has been reached");
+                            "The memory pool of the receiver is full");
             break;
 
           case ENOBUFS:
-          case EXFULL:
             dbus_set_error (error,
                             DBUS_ERROR_LIMITS_EXCEEDED,
-                            "No space in receiver's buffer",
-                            destination);
+                            "Too many pending messages on the receiver side");
+            break;
+
+          case EMSGSIZE:
+            dbus_set_error (error,
+                            DBUS_ERROR_LIMITS_EXCEEDED,
+                            "The size of the message is excessive");
+            break;
+
+          case EMLINK:
+            dbus_set_error (error,
+                            DBUS_ERROR_LIMITS_EXCEEDED,
+                            "The maximum number of pending replies per connection has been reached");
+            break;
+
+          case ETIMEDOUT:
+            dbus_set_error (error,
+                            DBUS_ERROR_TIMEOUT,
+                            "Timeout was reached");
+            break;
+
+          case EPERM:
+            dbus_set_error (error,
+                            DBUS_ERROR_ACCESS_DENIED,
+                            "Permission denied");
             break;
 
           default:
+            dbus_set_error (error,
+                            DBUS_ERROR_FAILED,
+                            "Something went wrong: %s",
+                            _dbus_strerror (ret));
             break;
         }
 
@@ -646,15 +668,13 @@ debug_str (const char *msg, const DBusString *str)
 }
 #endif
 
-static dbus_bool_t
+#ifdef LIBDBUSPOLICY
+static int
 can_send (DBusTransportKdbus *transport,
           DBusMessage        *message)
 {
-  dbus_bool_t result = TRUE;
 
-#ifdef LIBDBUSPOLICY
-  {
-    int ret = 1;
+    int ret = DBUSPOLICY_RESULT_ALLOW;
     if (NULL != transport->policy)
       {
         dbus_uint32_t reply_serial = dbus_message_get_reply_serial (message);
@@ -663,29 +683,42 @@ can_send (DBusTransportKdbus *transport,
          * Otherwise - check the policy.
          */
         if (0 == reply_serial)
-          ret = dbuspolicy1_check_out (transport->policy,
-                                       dbus_message_get_destination (message),
-                                       dbus_message_get_sender (message),
-                                       dbus_message_get_path (message),
-                                       dbus_message_get_interface (message),
-                                       dbus_message_get_member (message),
-                                       dbus_message_get_type (message),
-                                       dbus_message_get_error_name (message),
-                                       reply_serial,
-                                       !dbus_message_get_no_reply (message));
+          {
+            /* If method call or unicast signal, check policy */
+            if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_CALL ||
+               (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL &&
+                 dbus_message_get_destination (message) != NULL))
+              ret = dbuspolicy1_check_out (transport->policy,
+                                           dbus_message_get_destination (message),
+                                           transport->my_DBus_unique_name,
+                                           dbus_message_get_path (message),
+                                           dbus_message_get_interface (message),
+                                           dbus_message_get_member (message),
+                                           dbus_message_get_type (message),
+                                           dbus_message_get_error_name (message),
+                                           reply_serial,
+                                           !dbus_message_get_no_reply (message));
+          }
       }
-    result = (1 == ret);
-  }
-#endif
 
-  return result;
+  return ret;
 }
+#endif
+
+/* function prototypes */
+static int kdbus_message_size (const struct kdbus_msg *msg,
+                               int                    *n_fds);
+static int kdbus_decode_dbus_message (const struct kdbus_msg *msg,
+                                      char                   *data,
+                                      DBusTransportKdbus     *kdbus_transport,
+                                      int                    *fds,
+                                      int                    *n_fds);
 
 static int
 kdbus_write_msg_internal (DBusTransportKdbus  *transport,
                           DBusMessage         *message,
                           const char          *destination,
-                          dbus_bool_t          check_sync_reply,
+                          DBusMessage        **sync_reply,
                           dbus_bool_t          check_privileges)
 {
   struct kdbus_msg *msg = NULL;
@@ -700,15 +733,20 @@ kdbus_write_msg_internal (DBusTransportKdbus  *transport,
   int memfd = -1;
   const int *unix_fds;
   unsigned fds_count;
+  const char* header_data;
   DBusError error;
+  const char *destination_name = destination;
 
   dbus_uint64_t items_size;
   dbus_uint64_t flags = 0;
   dbus_uint64_t timeout_ns_or_cookie_reply = 0;
-
+  dbus_bool_t check_sync_reply = FALSE;
 
   dbus_error_init (&error);
 
+  if (sync_reply != NULL)
+    check_sync_reply = TRUE;
+
   // determine destination and destination id
   if (destination)
     {
@@ -761,12 +799,18 @@ kdbus_write_msg_internal (DBusTransportKdbus  *transport,
       else                                    /* method calls */
         {
           long tv_sec, tv_usec;
+          int timeout_ms = _dbus_message_get_timeout_ms(message);
 
           _dbus_get_monotonic_time (&tv_sec, &tv_usec);
                                            /* ms        us        ns */
-          timeout_ns_or_cookie_reply = (dbus_uint64_t)tv_sec * 1000ULL * 1000ULL * 1000ULL
-                                       + tv_usec * 1000ULL
-                                       + KDBUS_DEFAULT_TIMEOUT_NS;
+          timeout_ns_or_cookie_reply = 1U | ( /* ensure nonzero */
+                                         (dbus_uint64_t)tv_sec * 1000ULL * 1000ULL * 1000ULL
+                                         + tv_usec * 1000ULL + (
+                                           timeout_ms == -1 ? _DBUS_DEFAULT_TIMEOUT_VALUE * 1000000LLU :
+                                           timeout_ms == DBUS_TIMEOUT_INFINITE ? KDBUS_INFINITE_TIMEOUT_NS :
+                                           (uint64_t)timeout_ms * 1000000U
+                                         )
+                                       );
 
           flags |= KDBUS_MSG_EXPECT_REPLY;
         }
@@ -787,48 +831,84 @@ kdbus_write_msg_internal (DBusTransportKdbus  *transport,
   /* build message contents */
   item = msg->items;
 
-  if (memfd >= 0)
+  header_data = _dbus_string_get_const_data (header);
+
+  _dbus_verbose ("sending data by vec\n");
+  item = _kdbus_item_add_payload_vec (item,
+                                      header_size,
+                                      (uintptr_t)header_data);
+  if (body_size > 0)
     {
-      if (prepare_mfd (memfd,
-                       _dbus_string_get_const_data (header), header_size,
-                       _dbus_string_get_const_data (body), body_size) == -1)
+      const char* body_data = _dbus_string_get_const_data (body);
+      size_t body_offsets_size;
+      const char *footer_ptr;
+
+      /* determine body offsets size */
+      if (ret_size <= 0xFF)
+        body_offsets_size = 1;
+      else if (ret_size <= 0xFFFF)
+        body_offsets_size = 2;
+      else if (ret_size <= 0xFFFFFFFF)
+        body_offsets_size = 4;
+      else
+        body_offsets_size = 8;
+
+      /* check footer size */
+      footer_ptr = body_data + body_size - body_offsets_size -1;
+      while (footer_ptr >= body_data && (*footer_ptr) != 0)
+        footer_ptr--;
+
+      if (footer_ptr < body_data)
         {
           ret_size = -1;
           goto out;
         }
 
-      item = _kdbus_item_add_payload_memfd (item,
-                                            0,
-                                            ret_size,
-                                            memfd);
-    }
-  else
-    {
-      const char* header_data = _dbus_string_get_const_data (header);
-
-      _dbus_verbose ("sending data by vec\n");
-      item = _kdbus_item_add_payload_vec (item,
-                                          header_size,
-                                          (uintptr_t)header_data);
-      if (body_size > 0)
+#ifdef DBUS_ENABLE_VERBOSE_MODE
+      if (-1 != debug)
         {
-          const char* body_data = _dbus_string_get_const_data (body);
+          debug_str ("Header to send:", header);
+          debug_str ("Body to send:", body);
+        }
+#endif
 
-#ifdef DBUS_ENABLE_VERBOSE_MODE
-          if (-1 != debug)
+      if (memfd >= 0)
+        {
+          /* prepare memfd for body */
+          if (-1 == prepare_mfd (memfd,
+                           body_data,
+                           (uint64_t)((footer_ptr - body_data) * sizeof(char))))
             {
-              debug_str ("Header to send:", header);
-              debug_str ("Body to send:", body);
+              ret_size = -1;
+              goto out;
             }
-#endif
 
+      /* body */
+          item = _kdbus_item_add_payload_memfd (item,
+                                                0,
+                                                (footer_ptr - body_data) * sizeof(char),
+                                                memfd);
+
+      /* footer */
+          item = _kdbus_item_add_payload_vec (item,
+                                              (body_data + body_size - footer_ptr) * sizeof(char),
+                                              (uintptr_t)footer_ptr);
+        }
+      else
+        {
           while (body_size > 0)
             {
-              dbus_uint64_t part_size = body_size;
+              dbus_uint32_t part_size;
 
-              if (part_size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE)
+              if (body_size < KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE)
+                part_size = body_size;
+              else
                 part_size = KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE;
 
+              /* we need to adjust part size if footer does not fit as a whole */
+              if (body_size - part_size > 0 && footer_ptr < (body_data + part_size))
+                  part_size = footer_ptr - body_data;
+
               _dbus_verbose ("attaching body part\n");
               item = _kdbus_item_add_payload_vec (item,
                                                   part_size,
@@ -836,8 +916,8 @@ kdbus_write_msg_internal (DBusTransportKdbus  *transport,
               body_data += part_size;
               body_size -= part_size;
             }
-        }
-    }
+        } /* memfd */
+    } /* body_size */
 
   if (fds_count)
       item = _kdbus_item_add_fds (item, unix_fds, fds_count);
@@ -856,28 +936,77 @@ kdbus_write_msg_internal (DBusTransportKdbus  *transport,
       setup_bloom_filter_for_message (message, transport->kdbus, filter);
     }
 
-  if (check_privileges && !can_send (transport, message))
+#ifdef LIBDBUSPOLICY
+  if (check_privileges)
     {
-      DBusMessage *reply;
+      int check;
 
-      reply = reply_with_error (DBUS_ERROR_ACCESS_DENIED,
-                                NULL,
-                                "Cannot send message - message rejected "
-                                "due to security policies",
-                                message);
-      if (reply == NULL)
-        {
-          ret_size = -1;
-        }
-      else
+      check = can_send (transport, message);
+
+      if (check != DBUSPOLICY_RESULT_ALLOW)
         {
-          /* puts locally generated reply into received messages queue */
-          if (!add_message_to_received (reply, transport->base.connection))
-            ret_size = -1;
-        }
+          DBusMessage *reply;
 
-      goto out;
-    }
+          switch (check)
+            {
+              case DBUSPOLICY_RESULT_DENY:
+                reply = reply_with_error (DBUS_ERROR_ACCESS_DENIED, NULL,
+                                          "Cannot send message - message rejected due to XML security policies",
+                                          message);
+              break;
+
+              case DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE:
+                _dbus_assert (destination_name != NULL);
+                if (dbus_message_get_auto_start (message))
+                  reply = reply_with_error (DBUS_ERROR_SERVICE_UNKNOWN, NULL,
+                                            "Cannot send message - destination not known",
+                                            message);
+                else
+                  reply = reply_with_error (DBUS_ERROR_NAME_HAS_NO_OWNER, "Name \"%s\" does not exist",
+                                            destination_name,
+                                            message);
+              break;
+
+              case DBUSPOLICY_RESULT_KDBUS_ERROR:
+                reply = reply_with_error (DBUS_ERROR_ACCESS_DENIED, NULL,
+                                          "Cannot send message - message rejected due to internal libdbuspolicy error (kdbus)",
+                                          message);
+              break;
+
+              case DBUSPOLICY_RESULT_CYNARA_ERROR:
+                reply = reply_with_error (DBUS_ERROR_ACCESS_DENIED, NULL,
+                                          "Cannot send message - message rejected due to internal libdbuspolicy error (Cynara)",
+                                          message);
+              break;
+
+              default:
+                reply = reply_with_error (DBUS_ERROR_ACCESS_DENIED, NULL,
+                                          "Cannot send message - unknown libdbuspolicy error",
+                                          message);
+              break;
+            }
+
+          if (reply == NULL)
+            {
+              ret_size = -1;
+            }
+          else
+            {
+              if (check_sync_reply)
+                {
+                  *sync_reply = reply;
+                }
+              else
+                {
+                  /* puts locally generated reply into received messages queue */
+                  if (!add_message_to_received (reply, transport->base.connection))
+                    ret_size = -1;
+                }
+            }
+          goto out;
+        } /* ret != DBUSPOLICY_RESULT_ALLOW */
+    } /* check_privileges */
+#endif
 
   if (send_message (transport,
                     msg,
@@ -895,6 +1024,7 @@ kdbus_write_msg_internal (DBusTransportKdbus  *transport,
                                     NULL,
                                     error.message,
                                     message);
+          dbus_error_free(&error);
         }
 
       if (reply == NULL)
@@ -903,16 +1033,79 @@ kdbus_write_msg_internal (DBusTransportKdbus  *transport,
         }
       else
         {
-          /* puts locally generated reply into received messages queue */
-          if (!add_message_to_received (reply, transport->base.connection))
-            ret_size = -1;
+          if (check_sync_reply)
+            {
+              *sync_reply = reply;
+            }
+          else
+            {
+              /* puts locally generated reply into received messages queue */
+              if (!add_message_to_received (reply, transport->base.connection))
+                ret_size = -1;
+            }
         }
+      goto out;
     }
 
-  if (-1 != ret_size && check_sync_reply)
-    kdbus_close_message (transport, msg_reply);
+  if (check_sync_reply)
+    {
+      DBusString str;
+      int size, ret, *fds;
+      unsigned n_fds;
+      char *data;
+
+      /* check message size */
+      size = kdbus_message_size (msg_reply, &n_fds);
+      if (size <= 0)
+        {
+          ret_size = -1;
+          kdbus_close_message (transport, msg_reply);
+          goto out;
+        }
+
+      /* alloc buffer for decoded message */
+      data = dbus_malloc (sizeof (char) * size);
+      if (data == NULL)
+        {
+          ret_size = -1;
+          kdbus_close_message (transport, msg_reply);
+          goto out;
+        }
+
+      /* alloc palce for fds */
+      fds = dbus_malloc (sizeof (int) * (n_fds + 1));
+      if (fds == NULL)
+        {
+          ret_size = -1;
+          kdbus_close_message (transport, msg_reply);
+          dbus_free (data);
+          goto out;
+        }
 
-  out:
+      /* decode dbus message */
+      ret = kdbus_decode_dbus_message (msg_reply, data,
+                                       transport, fds, &n_fds);
+      if (ret <= 0)
+        {
+          ret_size = -1;
+          kdbus_close_message (transport, msg_reply);
+          dbus_free (fds);
+          dbus_free (data);
+          goto out;
+        }
+      _dbus_string_init_const_len (&str, data, ret);
+
+      /* create DBusMessage from kmsg */
+      *sync_reply = _dbus_decode_kmsg (&str, msg_reply->src_id, fds, n_fds);
+      if (*sync_reply == NULL)
+        ret_size = -1;
+
+      kdbus_close_message (transport, msg_reply);
+      dbus_free (fds);
+      dbus_free (data);
+    }
+
+out:
   if (msg)
     _kdbus_free_msg (msg);
   if (memfd >= 0)
@@ -939,7 +1132,7 @@ kdbus_write_msg (DBusTransportKdbus  *transport,
                  DBusMessage         *message,
                  const char          *destination)
 {
-  return kdbus_write_msg_internal (transport, message, destination, FALSE, TRUE);
+  return kdbus_write_msg_internal (transport, message, destination, NULL, TRUE);
 }
 
 static dbus_uint64_t
@@ -1027,7 +1220,7 @@ get_attach_flags_recv (DBusTransportKdbus *transport)
  * and configures transport.
  * As a result unique id on he bus is obtained.
  *
- * @see KDBUS_HELLO_* flags in kdbus.h
+ * @see KDBUS_HELLO_* flags in <linux/kdbus.h>
  *
  * @param transport transport structure
  * @param registration_flags aditional flags to modify registration process
@@ -1041,6 +1234,20 @@ bus_register_kdbus (DBusTransportKdbus *transport,
   int ret;
   dbus_uint64_t flags;
 
+#ifdef LIBDBUSPOLICY
+  void *policy = dbuspolicy1_init_shared (_kdbus_get_path(transport->kdbus),
+                                          _kdbus_get_fd(transport->kdbus));
+  if (NULL == policy)
+    {
+      dbus_set_error (error,
+                      DBUS_ERROR_NO_REPLY,
+                      "Did not receive a reply. Possible causes include: couldn't load dbus policy for kdbus transport or the message bus security policy blocked the reply.");
+      return FALSE;
+    }
+
+  transport->policy = policy;
+#endif
+
   flags = KDBUS_HELLO_ACCEPT_FD;
   if (registration_flags & REGISTER_FLAG_MONITOR)
     flags |= KDBUS_HELLO_MONITOR;
@@ -1055,13 +1262,23 @@ bus_register_kdbus (DBusTransportKdbus *transport,
   if (ret != 0)
     {
       dbus_set_error (error, DBUS_ERROR_FAILED, "Hello failed: %d", -ret);
+#ifdef LIBDBUSPOLICY
+      dbuspolicy1_free (policy);
+#endif
       return FALSE;
     }
 
+#ifdef LIBDBUSPOLICY
+  dbuspolicy1_init_set_pool (transport->policy, _kdbus_get_pool(transport->kdbus));
+#endif
+
   transport->my_DBus_unique_name = create_unique_name_from_unique_id (_kdbus_get_id (transport->kdbus));
   if (NULL == transport->my_DBus_unique_name)
     {
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, "Hello post failed: %d", -ret);
+#ifdef LIBDBUSPOLICY
+      dbuspolicy1_free (policy);
+#endif
       return FALSE;
     }
 
@@ -1230,33 +1447,6 @@ strcmp_existing (const char *str1, const char *str2)
 }
 
 static dbus_bool_t
-kernel_match_needed (MatchRule *rule)
-{
-  int message_type;
-
-  /* Allow only NameOwnerChanged member */
-  if (strcmp_existing (_match_rule_get_member (rule), "NameOwnerChanged") != 0)
-    return FALSE;
-
-  /* Allow only signals */
-  message_type = _match_rule_get_message_type (rule);
-  if (message_type != DBUS_MESSAGE_TYPE_INVALID && message_type != DBUS_MESSAGE_TYPE_SIGNAL)
-    return FALSE;
-
-  /* Check if from DBus */
-  if (strcmp_existing (_match_rule_get_sender (rule), DBUS_SERVICE_DBUS) != 0)
-    return FALSE;
-
-  if (strcmp_existing (_match_rule_get_interface (rule), DBUS_INTERFACE_DBUS) != 0)
-    return FALSE;
-
-  if (strcmp_existing (_match_rule_get_path (rule), DBUS_PATH_DBUS) != 0)
-    return FALSE;
-
-  return TRUE;
-}
-
-static dbus_bool_t
 is_bloom_needed (MatchRule *rule)
 {
   int rule_int;
@@ -1369,9 +1559,11 @@ add_match_kdbus (DBusTransportKdbus *transport,
   dbus_bool_t need_bloom = FALSE;
 
   const char *rule_sender;
+  const char *rule_arg0 = NULL;
   int ret;
 
   rule_cookie = match_rule_get_cookie (rule);
+  rule_sender = _match_rule_get_sender (rule);
 
 /*
  * First check if it is org.freedesktop.DBus's NameOwnerChanged or any
@@ -1379,45 +1571,95 @@ add_match_kdbus (DBusTransportKdbus *transport,
  * because it must be converted to special kdbus rule (kdbus has separate rules
  * for kdbus (kernel) generated broadcasts).
  */
-  if (kernel_match_needed (rule))
+  if (!strcmp_existing (rule_sender, DBUS_SERVICE_DBUS))
     {
-      ret = _kdbus_add_match_name_change (transport->kdbus,
-                                          0,
-                                          rule_cookie,
-                                          KDBUS_MATCH_ID_ANY,
-                                          0,
-                                          KDBUS_MATCH_ID_ANY,
-                                          0);
-      if (0 != ret)
-        {
-          _dbus_verbose ("Failed adding match rule for name removal for daemon, error: %d, %s\n",
-                         ret, _dbus_strerror (ret));
-          return FALSE;
-        }
+      int message_type = _match_rule_get_message_type (rule);
 
-      ret = _kdbus_add_match_id_change (transport->kdbus,
-                                        0,
-                                        rule_cookie,
-                                        KDBUS_MATCH_ID_ANY,
-                                        0);
-      if (0 != ret)
+      if ((DBUS_MESSAGE_TYPE_INVALID == message_type || DBUS_MESSAGE_TYPE_SIGNAL == message_type)
+          && !strcmp_existing (_match_rule_get_interface (rule), DBUS_INTERFACE_DBUS)
+          && !strcmp_existing (_match_rule_get_path (rule), DBUS_PATH_DBUS))
         {
-          _dbus_verbose ("Failed adding match rule for adding id for daemon, error: %d, %s\n",
-                         ret, _dbus_strerror (ret));
-          return FALSE;
-        }
+          if (_match_rule_get_args_len(rule) == 1)
+            {
+              rule_arg0 = _match_rule_get_args(rule, 0);
+              if (rule_arg0)
+                {
+                  DBusString str;
+                  _dbus_string_init_const (&str, rule_arg0);
+                  ret = _dbus_validate_bus_name (&str, 0, _dbus_string_get_length (&str));
+                  if (!ret)
+                    return FALSE;
+                }
+            }
+          if (!strcmp_existing (_match_rule_get_member (rule), "NameOwnerChanged"))
+            {
+              ret = _kdbus_add_match_name_change (transport->kdbus,
+                                                  0,
+                                                  rule_cookie,
+                                                  KDBUS_MATCH_ID_ANY,
+                                                  0,
+                                                  KDBUS_MATCH_ID_ANY,
+                                                  0,
+                                                  rule_arg0);
+              if (0 != ret)
+                {
+                  _dbus_verbose ("Failed adding match rule for name removal for daemon, error: %d, %s\n",
+                                  ret, _dbus_strerror (ret));
+                  return FALSE;
+                }
 
-      _dbus_verbose ("Added match rule for kernel correctly.\n");
+              _dbus_verbose ("Added match rule for kernel correctly.\n");
 
-/*
- * In case all of sender, interface and path are NULL, the rule
- * says simply about NameHasOwner signal from any object, any interface, any sender.
- * So, we need to consider that.
- * Otherwise, our job is finished here.
- */
-      if (_match_rule_get_sender (rule) != NULL
-          || _match_rule_get_interface (rule) != NULL
-          || _match_rule_get_path (rule) != NULL)
+              ret = _kdbus_add_match_id_change (transport->kdbus,
+                                                0,
+                                                rule_cookie,
+                                                KDBUS_MATCH_ID_ANY,
+                                                0,
+                                                rule_arg0);
+              if (0 != ret)
+                {
+                  _dbus_verbose ("Failed adding match rule for adding id for daemon, error: %d, %s\n",
+                                  ret, _dbus_strerror (ret));
+                  return FALSE;
+                }
+            }
+          else if (strcmp (_match_rule_get_member (rule), "NameAcquired") == 0)
+            {
+              ret = _kdbus_add_match_name_acquired (transport->kdbus,
+                                                    0,
+                                                    rule_cookie,
+                                                    KDBUS_MATCH_ID_ANY,
+                                                    0,
+                                                    _kdbus_get_id (transport->kdbus),
+                                                    0,
+                                                    rule_arg0);
+              if (0 != ret)
+                {
+                  _dbus_verbose ("Failed adding match rule for name removal for daemon, error: %d, %s\n",
+                                  ret, _dbus_strerror (ret));
+                  return FALSE;
+                }
+            }
+          else if (strcmp (_match_rule_get_member (rule), "NameLost") == 0)
+            {
+              ret = _kdbus_add_match_name_lost (transport->kdbus,
+                                               0,
+                                                rule_cookie,
+                                                _kdbus_get_id (transport->kdbus),
+                                                0,
+                                                KDBUS_MATCH_ID_ANY,
+                                                0,
+                                                rule_arg0);
+              if (0 != ret)
+                {
+                  _dbus_verbose ("Failed adding match rule for name removal for daemon, error: %d, %s\n",
+                  ret, _dbus_strerror (ret));
+                  return FALSE;
+                }
+            }
+        }
+      /* Sender=DBUS_SERVICE_DBUS matches (as opposed to wildcard sender) need no standard rule. */
+      if (rule_sender)
         return TRUE;
     }
 
@@ -1428,7 +1670,6 @@ add_match_kdbus (DBusTransportKdbus *transport,
 
   need_bloom = is_bloom_needed (rule);
 
-  rule_sender = _match_rule_get_sender (rule);
   if (rule_sender != NULL)
     {
       DBusString str;
@@ -1754,7 +1995,7 @@ capture_org_freedesktop_DBus_GetConnectionCredentials (DBusTransportKdbus *trans
       dbus_bool_t res = _dbus_asv_add_byte_array (&array_iter,
                                                   "LinuxSecurityLabel",
                                                   info.sec_label,
-                                                  strlen (info.sec_label)+1);
+                                                  info.sec_label_len);
 
       dbus_free (info.sec_label);
 
@@ -1777,6 +2018,17 @@ oom:
   return NULL;
 }
 
+static dbus_bool_t
+_mac_smack_use (void)
+{
+  static int cached_use = -1;
+
+  if (cached_use < 0)
+    cached_use = access("/sys/fs/smackfs/", F_OK) >= 0;
+
+  return cached_use;
+}
+
 static DBusMessage *
 capture_org_freedesktop_DBus_GetConnectionSELinuxSecurityContext (DBusTransportKdbus *transport,
                                                                   DBusMessage        *message,
@@ -1789,14 +2041,23 @@ capture_org_freedesktop_DBus_GetConnectionSELinuxSecurityContext (DBusTransportK
 
   if (info.sec_label != NULL)
     {
-      DBusMessage *reply;
+      if (_mac_smack_use())
+        {
+          dbus_set_error (error, DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN,
+                          "Could not determine security context");
+          dbus_free (info.sec_label);
+        }
+      else
+        {
+          DBusMessage *reply;
 
-      reply = reply_fixed_array (message, DBUS_TYPE_BYTE,
-                                 info.sec_label,
-                                 strlen (info.sec_label)+1);
+          reply = reply_fixed_array (message, DBUS_TYPE_BYTE,
+                                     info.sec_label,
+                                     info.sec_label_len);
 
-      dbus_free (info.sec_label);
-      return reply;
+          dbus_free (info.sec_label);
+          return reply;
+        }
     }
   else
     {
@@ -1957,11 +2218,9 @@ reply_listNames (DBusTransportKdbus *transport,
         {
           if (item->type == KDBUS_ITEM_OWNED_NAME)
             {
-              DBusError local_error;
               char *name_ptr = item->name.name;
 
-              dbus_error_init ( &local_error );
-              if (!dbus_validate_bus_name (name_ptr, &local_error))
+              if (!dbus_validate_bus_name (name_ptr, NULL))
                 continue;
 
               if (flags & KDBUS_LIST_QUEUED)
@@ -1973,7 +2232,11 @@ reply_listNames (DBusTransportKdbus *transport,
               if (!dbus_message_iter_append_basic (&array_iter,
                                                    DBUS_TYPE_STRING,
                                                    &name_ptr))
-                goto oom_iterator;
+                {
+                  if (flags & KDBUS_LIST_QUEUED)
+                    free (name_ptr);
+                  goto oom_iterator;
+                }
 
               if (flags & KDBUS_LIST_QUEUED)
                 free (name_ptr);
@@ -1987,6 +2250,8 @@ reply_listNames (DBusTransportKdbus *transport,
   if (!dbus_message_set_sender (reply, DBUS_SERVICE_DBUS))
     goto oom_reply;
 
+  _kdbus_free_mem (transport->kdbus, name_list);
+
   return reply;
 
 oom_iterator:
@@ -2133,7 +2398,11 @@ capture_org_freedesktop_DBus_StartServiceByName (DBusTransportKdbus *transport,
 
       dbus_message_lock (sub_message);
 
-      if (kdbus_write_msg_internal (transport, sub_message, name, FALSE, FALSE) == -1)
+      ret = kdbus_write_msg_internal (transport, sub_message, name, NULL, FALSE);
+
+      dbus_message_unref (sub_message);
+
+      if (ret == -1)
           return NULL;
       else
         {
@@ -2229,11 +2498,14 @@ capture_org_freedesktop_DBus (DBusTransportKdbus *transport,
   int ret = 1;
   if (!strcmp (destination, DBUS_SERVICE_DBUS))
     {
-      if (!strcmp (dbus_message_get_interface (message), DBUS_INTERFACE_DBUS))
+      const char *interface = dbus_message_get_interface (message);
+      if (interface && !strcmp (interface, DBUS_INTERFACE_DBUS))
         {
           DBusError error;
           const char *member = dbus_message_get_member (message);
 
+          _dbus_assert (member != NULL);
+
           dbus_error_init (&error);
 
           if (!strcmp (member, "Hello"))
@@ -2273,7 +2545,7 @@ capture_org_freedesktop_DBus (DBusTransportKdbus *transport,
            else
              ret = 0;
 
-        } /* id DBUS_INTERFACE_DBUS */
+        } /* if DBUS_INTERFACE_DBUS */
     } /* if DBUS_SERVICE_DBUS */
 
   return ret;
@@ -2369,11 +2641,13 @@ get_next_client_serial (DBusTransportKdbus *transport)
  * @return the length of the kdbus message's payload.
  */
 static int
-kdbus_message_size (const struct kdbus_msg *msg)
+kdbus_message_size (const struct kdbus_msg *msg,
+                    int                    *n_fds)
 {
   const struct kdbus_item *item;
   int ret_size = 0;
 
+  *n_fds = 0;
   KDBUS_ITEM_FOREACH (item, msg, items)
     {
       if (item->size < KDBUS_ITEM_HEADER_SIZE)
@@ -2389,6 +2663,9 @@ kdbus_message_size (const struct kdbus_msg *msg)
           case KDBUS_ITEM_PAYLOAD_MEMFD:
             ret_size += item->memfd.size;
             break;
+          case KDBUS_ITEM_FDS:
+            *n_fds = (item->size - KDBUS_ITEM_HEADER_SIZE) / sizeof (int);
+            break;
           default:
             break;
         }
@@ -2522,7 +2799,8 @@ kdbus_handle_name_owner_changed (__u64               type,
       _dbus_verbose ("%s\n", const_ptr);
     }
 
-  dbus_message_set_sender (message, DBUS_SERVICE_DBUS);
+  if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS))
+    goto error;
   dbus_message_set_serial (message, get_next_client_serial (transport));
 
   if (!add_message_to_received (message, transport->base.connection))
@@ -2625,7 +2903,11 @@ can_receive (DBusTransportKdbus     *transport,
 
         result = FALSE;
 
-        _dbus_string_init (&names);
+        if (!_dbus_string_init (&names))
+          {
+            _dbus_verbose ("oom:_dbus_string_init");
+            return FALSE;
+          }
 
         KDBUS_ITEM_FOREACH(item, msg, items)
           switch (item->type)
@@ -2646,12 +2928,22 @@ can_receive (DBusTransportKdbus     *transport,
                   if (_dbus_validate_bus_name (&name, 0, _dbus_string_get_length (&name)))
                     {
                       if (_dbus_string_get_length (&names) != 0)
-                        _dbus_string_append_byte (&names, ' ');
-
-                      _dbus_string_copy (&name,
+                        {
+                          if (!_dbus_string_append_byte (&names, ' '))
+                            {
+                              _dbus_string_free (&names);
+                              return FALSE;
+                            }
+                        }
+
+                      if (!_dbus_string_copy (&name,
                                          0,
                                          &names,
-                                         _dbus_string_get_length (&names));
+                                         _dbus_string_get_length (&names)))
+                        {
+                          _dbus_string_free (&names);
+                          return FALSE;
+                        }
                     }
                 }
                 break;
@@ -2664,8 +2956,9 @@ can_receive (DBusTransportKdbus     *transport,
             if (load_dbus_header (transport, &header, message_data, message_len))
               got_header = TRUE;
           }
-
-        if (got_header && _dbus_header_get_message_type (&header) != DBUS_MESSAGE_TYPE_METHOD_CALL)
+        if (got_header &&
+            _dbus_header_get_message_type (&header) != DBUS_MESSAGE_TYPE_METHOD_CALL &&
+            _dbus_header_get_message_type (&header) != DBUS_MESSAGE_TYPE_SIGNAL)
           {
             result = TRUE;
           }
@@ -2684,6 +2977,8 @@ can_receive (DBusTransportKdbus     *transport,
                                           DBUS_HEADER_FIELD_DESTINATION,
                                           DBUS_TYPE_STRING,
                                           &destination);
+            if (!destination)
+               destination = transport->my_DBus_unique_name;
 
             _dbus_header_get_field_basic (&header,
                                           DBUS_HEADER_FIELD_PATH,
@@ -2789,7 +3084,7 @@ kdbus_decode_dbus_message (const struct kdbus_msg *msg,
               size = item->memfd.size;
               _dbus_verbose ("memfd.size : %llu\n", (unsigned long long)size);
 
-              buf = mmap (NULL, size, PROT_READ , MAP_SHARED, item->memfd.fd, 0);
+              buf = mmap (NULL, size, PROT_READ, MAP_PRIVATE, item->memfd.fd, 0);
               if (buf == MAP_FAILED)
                 {
                   _dbus_verbose ("mmap () fd=%i failed:%m", item->memfd.fd);
@@ -2950,24 +3245,8 @@ kdbus_decode_kernel_message (const struct kdbus_msg *msg,
         {
           case KDBUS_ITEM_REPLY_TIMEOUT:
           case KDBUS_ITEM_REPLY_DEAD:
-            {
-              DBusMessage *message = NULL;
-              _dbus_verbose ("  +%s (%llu bytes) cookie=%llu\n",
-                            enum_MSG (item->type), item->size, msg->cookie_reply);
-
-              message = _dbus_generate_local_error_message (msg->cookie_reply,
-                      item->type == KDBUS_ITEM_REPLY_TIMEOUT ? DBUS_ERROR_NO_REPLY : DBUS_ERROR_NAME_HAS_NO_OWNER, NULL);
-              if (message == NULL)
-                {
-                  ret_size = -1;
-                  goto out;
-                }
-
-              dbus_message_set_serial (message, get_next_client_serial (kdbus_transport));
-
-              if (!add_message_to_received (message, kdbus_transport->base.connection))
-                ret_size = -1;
-            }
+            _dbus_verbose ("  +%s (%llu bytes) cookie=%llu\n",
+                          enum_MSG (item->type), item->size, msg->cookie_reply);
             break;
 
           case KDBUS_ITEM_NAME_ADD:
@@ -3066,8 +3345,7 @@ kdbus_decode_msg (const struct kdbus_msg *msg,
                   char                   *data,
                   DBusTransportKdbus     *kdbus_transport,
                   int                    *fds,
-                  int                    *n_fds,
-                  DBusError              *error)
+                  int                    *n_fds)
 {
   int ret_size = 0;
 
@@ -3119,9 +3397,6 @@ kdbus_read_message (DBusTransportKdbus *kdbus_transport,
   int start;
   dbus_uint64_t flags = 0;
   int ret;
-  DBusError error;
-
-  dbus_error_init (&error);
 
   start = _dbus_string_get_length (buffer);
 
@@ -3136,7 +3411,7 @@ kdbus_read_message (DBusTransportKdbus *kdbus_transport,
       return -1;
     }
 
-  buf_size = kdbus_message_size (msg);
+  buf_size = kdbus_message_size (msg, n_fds);
   if (buf_size == -1)
     {
       _dbus_verbose ("kdbus error - too short message: %d (%m)\n", errno);
@@ -3154,7 +3429,7 @@ kdbus_read_message (DBusTransportKdbus *kdbus_transport,
     }
   data = _dbus_string_get_data_len (buffer, start, buf_size);
 
-  ret_size = kdbus_decode_msg (msg, data, kdbus_transport, fds, n_fds, &error);
+  ret_size = kdbus_decode_msg (msg, data, kdbus_transport, fds, n_fds);
 
   if (ret_size == -1) /* error */
     _dbus_string_set_length (buffer, start);
@@ -3177,6 +3452,58 @@ kdbus_read_message (DBusTransportKdbus *kdbus_transport,
   return ret_size;
 }
 
+#ifdef ENABLE_KDBUS_SYNC_CALLS
+static DBusMessage *
+kdbus_send_sync_call (DBusTransportKdbus  *transport,
+                      DBusMessage         *message)
+{
+  DBusMessage *reply = NULL;
+  DBusError error;
+  const char *destination;
+
+  dbus_message_lock (message);
+
+  destination = dbus_message_get_destination (message);
+  if (destination)
+    {
+      int ret;
+
+      ret = capture_org_freedesktop_DBus ((DBusTransportKdbus*)transport, destination, message, &reply);
+      if (ret < 0)
+        goto error;
+      else if (ret == 0)
+        goto out;
+    }
+
+  kdbus_write_msg_internal (transport, message, destination, &reply, TRUE);
+  if (reply == NULL)
+    goto error;
+  else
+    goto out;
+
+error:
+
+  dbus_error_init (&error);
+
+  dbus_set_error (&error, DBUS_ERROR_FAILED,
+                  "Something went wrong");
+
+  reply = reply_with_error ((char*)error.name,
+                            NULL,
+                            error.message,
+                            message);
+
+  dbus_error_free (&error);
+
+out:
+
+  _dbus_assert (reply != NULL);
+  dbus_message_lock (reply);
+
+  return reply;
+}
+#endif
+
 /**
  * Copy-paste from socket transport. Only renames done.
  */
@@ -3474,8 +3801,8 @@ do_reading (DBusTransport *transport)
  again:
 
   /* See if we've exceeded max messages and need to disable reading */
- if (kdbus_transport->activator == NULL)
-  check_read_watch (kdbus_transport);
 if (kdbus_transport->activator == NULL)
+    check_read_watch (kdbus_transport);
 
   if (total > kdbus_transport->max_bytes_read_per_iteration)
     {
@@ -3499,7 +3826,7 @@ do_reading (DBusTransport *transport)
       oom = TRUE;
       goto out;
   }
-  _dbus_message_loader_get_buffer (transport->loader, &buffer);
+  _dbus_message_loader_get_buffer (transport->loader, &buffer, NULL, NULL);
 
   bytes_read = kdbus_read_message (kdbus_transport, buffer, fds, &n_fds);
 
@@ -3726,11 +4053,16 @@ kdbus_do_iteration (DBusTransport *transport,
     * When timeout is set to -1 in client application,
     * error messages are inserted directly to incoming queue and
     * application hangs on dbus_poll.
-    */
+    *
+    * This causes a busy loop in _dbus_connection_block_pending_call()
+    * There is no case of waiting for the locally-generated error reply
+
    if (_dbus_connection_get_n_incoming (transport->connection) > 0)
    {
      timeout_milliseconds = 0;
    }
+    */
+
    /* This is kind of a hack; if we have stuff to write, then try
     * to avoid the poll. This is probably about a 5% speedup on an
     * echo client/server.
@@ -3970,6 +4302,10 @@ new_kdbus_transport (kdbus_t          *kdbus,
                                               _dbus_transport_kdbus_get_unix_user);
   _dbus_transport_set_get_unix_process_id_function (&kdbus_transport->base,
                                                     _dbus_transport_kdbus_get_unix_process_id);
+#ifdef ENABLE_KDBUS_SYNC_CALLS
+  _dbus_transport_set_send_sync_call_function (&kdbus_transport->base,
+                                               (DBusTransportSendSyncCallFunction) kdbus_send_sync_call);
+#endif
   _dbus_transport_set_assure_protocol_function (&kdbus_transport->base,
                                                 _dbus_message_assure_gvariant,
                                                 DBUS_PROTOCOL_VERSION_GVARIANT);
@@ -4002,23 +4338,6 @@ new_kdbus_transport (kdbus_t          *kdbus,
   return NULL;
 }
 
-static dbus_bool_t
-initialize_policies (DBusTransportKdbus *transport, DBusBusType bus_type)
-{
-  dbus_bool_t result = TRUE;
-
-#ifdef LIBDBUSPOLICY
-  if (DBUS_BUS_SYSTEM == bus_type || DBUS_BUS_SESSION == bus_type)
-    {
-      transport->policy = dbuspolicy1_init (bus_type);
-      if (NULL == transport->policy)
-        result = FALSE;
-    }
-#endif
-
-  return result;
-}
-
 /**
  * Connects to kdbus, creates and sets-up transport.
  *
@@ -4061,14 +4380,14 @@ _dbus_transport_new_for_kdbus (const char *path,
       goto failed_0;
     }
 
-  kdbus = _kdbus_new ();
+  kdbus = _kdbus_new (path);
   if (NULL == kdbus)
     {
       dbus_set_error (error, DBUS_ERROR_NO_MEMORY, NULL);
       goto failed_0;
     }
 
-  ret = _kdbus_open (kdbus, path);
+  ret = _kdbus_open (kdbus);
   if (ret < 0)
     {
       dbus_set_error (error,
@@ -4088,17 +4407,6 @@ _dbus_transport_new_for_kdbus (const char *path,
       goto failed_1;
     }
 
-  if (!initialize_policies (transport,
-                            _dbus_bus_get_address_type (_dbus_string_get_data (&address))))
-    {
-      dbus_set_error (error,
-                      DBUS_ERROR_FAILED,
-                      "Can't load dbus policy for kdbus transport");
-      _kdbus_close (kdbus);
-      transport_finalize ((DBusTransport*)transport);
-      transport = NULL;
-    }
-
   _dbus_string_free (&address);
 
   return (DBusTransport*)transport;