Do not auto-activate services if we could not send a message 07/193007/2 accepted/tizen/unified/20181115.151616 submit/tizen/20181115.015729
authorSimon McVittie <simon.mcvittie@collabora.co.uk>
Mon, 21 Nov 2016 20:56:55 +0000 (20:56 +0000)
committerHyotaek Shim <hyotaek.shim@samsung.com>
Thu, 15 Nov 2018 03:19:01 +0000 (03:19 +0000)
We specifically do not check recipient policies, because
the recipient policy is based on properties of the
recipient process (in particular, its uid), which we do
not necessarily know until we have already started it.

In this initial implementation we do not check LSMs either,
because we cannot know what LSM context the recipient process
is going to have. However, LSM support will need to be added
to make this feature useful, because StartServiceByName is
normally allowed in non-LSM environments, and is more
powerful than auto-activation anyway.

The StartServiceByName method does not go through this check,
because if access to that method has been granted, then
it's somewhat obvious that you can start arbitrary services.

Signed-off-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
Reviewed-by: Philip Withnall <philip.withnall@collabora.co.uk>
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=98666

Change-Id: I53ff4f6d02e631fcd09bf1c5c306b8828f075963

12 files changed:
bus/activation.c
bus/apparmor.c
bus/apparmor.h
bus/bus.c
bus/bus.h
bus/check.c
bus/connection.c
bus/dispatch.c
bus/policy.c
bus/selinux.c
bus/selinux.h
test/sd-activation.c

index 6d8a7c7..99b3554 100644 (file)
@@ -65,7 +65,7 @@ typedef struct
   DBusHashTable *entries;
 } BusServiceDirectory;
 
-typedef struct
+struct BusActivationEntry
 {
   int refcount;
   char *name;
@@ -75,7 +75,7 @@ typedef struct
   unsigned long mtime;
   BusServiceDirectory *s_dir;
   char *filename;
-} BusActivationEntry;
+};
 
 typedef struct BusPendingActivationEntry BusPendingActivationEntry;
 
@@ -1804,6 +1804,31 @@ bus_activation_activate_service (BusActivation  *activation,
   if (!entry)
     return BUS_RESULT_FALSE;
 
+  if (auto_activation && entry != NULL)
+    {
+      switch (bus_context_check_security_policy (activation->context,
+        transaction,
+        connection, /* sender */
+        NULL, /* addressed recipient */
+        NULL, /* proposed recipient */
+        activation_message,
+        entry,
+        error,
+        deferred_message))
+        {
+        case BUS_RESULT_TRUE:
+            break;
+        case BUS_RESULT_FALSE:
+          _DBUS_ASSERT_ERROR_IS_SET (error);
+          _dbus_verbose ("activation not authorized: %s: %s\n",
+                  error != NULL ? error->name : "(error ignored)",
+                  error != NULL ? error->message : "(error ignored)");
+          return BUS_RESULT_FALSE;
+        case BUS_RESULT_LATER:
+          return BUS_RESULT_LATER;
+        }
+      }
+
   /* Bypass the registry lookup if we're auto-activating, bus_dispatch would not
    * call us if the service is already active.
    */
index 3ba84d8..46725db 100644 (file)
@@ -737,6 +737,7 @@ bus_apparmor_allows_send (DBusConnection     *sender,
                           const char         *error_name,
                           const char         *destination,
                           const char         *source,
+                          BusActivationEntry *activation_entry,
                           DBusError          *error)
 {
 #ifdef HAVE_APPARMOR
@@ -753,6 +754,10 @@ bus_apparmor_allows_send (DBusConnection     *sender,
   if (!apparmor_enabled)
     return TRUE;
 
+  /* We do not mediate activation attempts yet. */
+  if (activation_entry != NULL)
+    return TRUE;
+
   _dbus_assert (sender != NULL);
 
   src_con = bus_connection_dup_apparmor_confinement (sender);
index 18f3ee7..ed465f7 100644 (file)
@@ -56,6 +56,7 @@ dbus_bool_t bus_apparmor_allows_send (DBusConnection     *sender,
                                       const char         *error_name,
                                       const char         *destination,
                                       const char         *source,
+                                      BusActivationEntry *activation_entry,
                                       DBusError          *error);
 
 dbus_bool_t bus_apparmor_allows_eavesdropping (DBusConnection     *connection,
index 144c0df..4943b9f 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -1524,7 +1524,11 @@ complain_about_message (BusContext     *context,
  *
  * sender is the sender of the message.
  *
- * NULL for proposed_recipient or sender definitely means the bus driver.
+ * NULL for sender definitely means the bus driver.
+ *
+ * NULL for proposed_recipient may mean the bus driver, or may mean
+ * we are checking whether service-activation is allowed as a first
+ * pass before all details of the activated service are known.
  *
  * NULL for addressed_recipient may mean the bus driver, or may mean
  * no destination was specified in the message (e.g. a signal).
@@ -1536,6 +1540,7 @@ bus_context_check_security_policy (BusContext          *context,
                                    DBusConnection      *addressed_recipient,
                                    DBusConnection      *proposed_recipient,
                                    DBusMessage         *message,
+                                   BusActivationEntry  *activation_entry,
                                    DBusError           *error,
                                    BusDeferredMessage **deferred_message)
 {
@@ -1558,6 +1563,7 @@ bus_context_check_security_policy (BusContext          *context,
                 (sender == NULL && !bus_connection_is_active (proposed_recipient)));
   _dbus_assert (type == DBUS_MESSAGE_TYPE_SIGNAL ||
                 addressed_recipient != NULL ||
+                activation_entry != NULL ||
                 strcmp (dest, DBUS_SERVICE_DBUS) == 0);
 
   switch (type)
@@ -1623,7 +1629,9 @@ bus_context_check_security_policy (BusContext          *context,
                                    dbus_message_get_interface (message),
                                    dbus_message_get_member (message),
                                    dbus_message_get_error_name (message),
-                                   dest ? dest : DBUS_SERVICE_DBUS, error))
+                                   dest ? dest : DBUS_SERVICE_DBUS,
+                                   activation_entry,
+                                   error))
         {
           if (error != NULL && !dbus_error_is_set (error))
             {
@@ -1652,6 +1660,7 @@ bus_context_check_security_policy (BusContext          *context,
                                      dbus_message_get_error_name (message),
                                      dest ? dest : DBUS_SERVICE_DBUS,
                                      src ? src : DBUS_SERVICE_DBUS,
+                                     activation_entry,
                                      error))
         return FALSE;
 
@@ -1795,6 +1804,10 @@ bus_context_check_security_policy (BusContext          *context,
   /* 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
    * connection). Only the addressed recipient may reply.
+   *
+   * This isn't done for activation attempts because they have no addressed
+   * or proposed recipient; when we check whether to actually deliver the
+   * message, later, we'll record the reply expectation at that point.
    */
   if (type == DBUS_MESSAGE_TYPE_METHOD_CALL &&
       sender &&
index 95ca9a8..6382b18 100644 (file)
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -44,6 +44,7 @@ typedef struct BusOwner               BusOwner;
 typedef struct BusTransaction   BusTransaction;
 typedef struct BusMatchmaker    BusMatchmaker;
 typedef struct BusMatchRule     BusMatchRule;
+typedef struct BusActivationEntry BusActivationEntry;
 typedef struct BusCheck           BusCheck;
 typedef struct BusDeferredMessage BusDeferredMessage;
 typedef struct BusCynara          BusCynara;
@@ -158,6 +159,7 @@ BusResult         bus_context_check_security_policy              (BusContext
                                                                   DBusConnection      *addressed_recipient,
                                                                   DBusConnection      *proposed_recipient,
                                                                   DBusMessage         *message,
+                                                                  BusActivationEntry  *activation_entry,
                                                                   DBusError           *error,
                                                                   BusDeferredMessage **deferred_message);
 
index 9bbca63..2aeb69e 100644 (file)
@@ -470,7 +470,7 @@ bus_deferred_message_dispatch (BusDeferredMessage *deferred_message)
                                                         deferred_message->sender,
                                                         deferred_message->addressed_recipient,
                                                         deferred_message->proposed_recipient,
-                                                        deferred_message->message, NULL,
+                                                        deferred_message->message, NULL, NULL,
                                                         &deferred_message2);
 
             if (result == BUS_RESULT_LATER)
index 2173ce9..b4a2995 100644 (file)
@@ -2340,7 +2340,8 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
    */
   switch (bus_context_check_security_policy (bus_transaction_get_context (transaction),
                                              transaction,
-                                             NULL, connection, connection, message, &error,
+                                             NULL, connection, connection,
+                                             message, NULL, &error,
                                              &deferred_message))
     {
     case BUS_RESULT_TRUE:
index 67763b9..f4dea60 100644 (file)
@@ -71,7 +71,7 @@ send_one_message (DBusConnection *connection,
   BusResult result;
 
   result = bus_context_check_security_policy (context, transaction, sender, addressed_recipient,
-      connection, message, &stack_error, &deferred_message);
+      connection, message, NULL, &stack_error, &deferred_message);
 
   if (result == BUS_RESULT_FALSE)
     {
@@ -211,7 +211,7 @@ bus_dispatch_matches (BusTransaction     *transaction,
 
       if (result == BUS_RESULT_LATER)
         result = bus_context_check_security_policy(context, transaction,
-            sender, addressed_recipient, addressed_recipient, message, error,
+            sender, addressed_recipient, addressed_recipient, message, NULL, error,
             &deferred_message);
 
       switch (result)
@@ -495,7 +495,8 @@ bus_dispatch (DBusConnection *connection,
       BusDeferredMessage *deferred_message;
 
       switch (bus_context_check_security_policy (context, transaction,
-                                                 connection, NULL, NULL, message, &error,
+                                                 connection, NULL, NULL, message,
+                                                 NULL, &error,
                                                  &deferred_message))
         {
         case BUS_RESULT_TRUE:
@@ -551,12 +552,13 @@ bus_dispatch (DBusConnection *connection,
           BusActivation *activation;
           BusDeferredMessage *deferred_message;
 
-          /* We can't do the security policy check here, since the addressed
-           * recipient service doesn't exist yet. We do it before sending the
-           * message after the service has been created.
-           */
           activation = bus_connection_get_activation (connection);
 
+          /* This will do as much of a security policy check as it can.
+           * We can't do the full security policy check here, since the
+           * addressed recipient service doesn't exist yet. We do it before
+           * sending the message after the service has been created.
+           */
           switch (bus_activation_activate_service (activation, connection, transaction, TRUE,
                                                 message, service_name, &error,
                                                 &deferred_message))
index 932a9b4..3d4f547 100644 (file)
@@ -1007,6 +1007,11 @@ bus_client_policy_check_can_send (DBusConnection      *sender,
            * message bus itself, we check the strings in that case as
            * built-in services don't have a DBusConnection but messages
            * to them have a destination service name.
+           *
+           * Similarly, receiver can be NULL when we're deciding whether
+           * activation should be allowed; we make the authorization decision
+           * on the assumption that the activated service will have the
+           * requested name and no others.
            */
           if (receiver == NULL)
             {
index ef627c8..be66d4f 100644 (file)
@@ -551,6 +551,7 @@ bus_selinux_allows_send (DBusConnection     *sender,
                         const char         *member,
                         const char         *error_name,
                         const char         *destination,
+                        BusActivationEntry *activation_entry,
                         DBusError          *error)
 {
 #ifdef HAVE_SELINUX
@@ -564,6 +565,10 @@ bus_selinux_allows_send (DBusConnection     *sender,
   if (!selinux_enabled)
     return TRUE;
 
+  /* We do not mediate activation attempts yet. */
+  if (activation_entry)
+    return TRUE;
+
   if (!sender || !dbus_connection_get_unix_process_id (sender, &spid))
     spid = 0;
   if (!proposed_recipient || !dbus_connection_get_unix_process_id (proposed_recipient, &tpid))
@@ -631,7 +636,8 @@ bus_selinux_allows_send (DBusConnection     *sender,
     }
 
   sender_sid = bus_connection_get_selinux_id (sender);
-  /* A NULL proposed_recipient means the bus itself. */
+
+  /* A NULL proposed_recipient with no activation entry means the bus itself. */
   if (proposed_recipient)
     recipient_sid = bus_connection_get_selinux_id (proposed_recipient);
   else
index e44c97e..5252b18 100644 (file)
@@ -61,6 +61,7 @@ dbus_bool_t bus_selinux_allows_send            (DBusConnection *sender,
                                                const char     *member,
                                                const char     *error_name,
                                                const char     *destination,
+                                               BusActivationEntry *activation_entry,
                                                DBusError      *error);
 
 BusSELinuxID* bus_selinux_init_connection_id (DBusConnection *connection,
index 6d52987..9b2a5bb 100644 (file)
@@ -575,44 +575,12 @@ test_deny_send (Fixture *f,
   dbus_connection_send (f->caller, m, NULL);
   dbus_message_unref (m);
 
-  /* The fake systemd connects to the bus. */
-  f->systemd = test_connect_to_bus (f->ctx, f->address);
-  if (!dbus_connection_add_filter (f->systemd, systemd_filter, f, NULL))
-    g_error ("OOM");
-  f->systemd_filter_added = TRUE;
-  f->systemd_name = dbus_bus_get_unique_name (f->systemd);
-  take_well_known_name (f, f->systemd, "org.freedesktop.systemd1");
-
-  /* It gets its activation request. */
-  while (f->caller_message == NULL && f->systemd_message == NULL)
-    test_main_context_iterate (f->ctx, TRUE);
-
-  g_assert (f->caller_message == NULL);
-  g_assert (f->systemd_message != NULL);
-
-  m = f->systemd_message;
-  f->systemd_message = NULL;
-  assert_signal (m, DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
-      "org.freedesktop.systemd1.Activator", "ActivationRequest", "s",
-      "org.freedesktop.systemd1");
-  dbus_message_unref (m);
-
-  /* systemd starts the activatable service. */
-  f->activated = test_connect_to_bus (f->ctx, f->address);
-  if (!dbus_connection_add_filter (f->activated, activated_filter,
-        f, NULL))
-    g_error ("OOM");
-  f->activated_filter_added = TRUE;
-  f->activated_name = dbus_bus_get_unique_name (f->activated);
-  take_well_known_name (f, f->activated, "com.example.SendDenied");
+  /* Even before the fake systemd connects to the bus, we get an error
+   * back: activation is not allowed. */
 
-  /* We re-do the message matching, and now the message is
-   * forbidden by the receive policy. */
-  while (f->activated_message == NULL && f->caller_message == NULL)
+  while (f->caller_message == NULL)
     test_main_context_iterate (f->ctx, TRUE);
 
-  g_assert (f->activated_message == NULL);
-
   m = f->caller_message;
   f->caller_message = NULL;
   assert_error_reply (m, DBUS_SERVICE_DBUS, f->caller_name,