]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
Do not auto-activate services if we could not send a message
authorSimon McVittie <simon.mcvittie@collabora.co.uk>
Mon, 21 Nov 2016 20:56:55 +0000 (20:56 +0000)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Mon, 28 Nov 2016 12:11:41 +0000 (12:11 +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

bus/activation.c
bus/apparmor.c
bus/apparmor.h
bus/bus.c
bus/bus.h
bus/connection.c
bus/dispatch.c
bus/policy.c
bus/selinux.c
bus/selinux.h
test/sd-activation.c

index 1e5919022f00b11d4da86b2be73800820263648f..e131a801e6eb9f2c2867a1ee7bdbe4aca2609606 100644 (file)
@@ -64,7 +64,7 @@ typedef struct
   DBusHashTable *entries;
 } BusServiceDirectory;
 
-typedef struct
+struct BusActivationEntry
 {
   int refcount;
   char *name;
@@ -74,7 +74,7 @@ typedef struct
   unsigned long mtime;
   BusServiceDirectory *s_dir;
   char *filename;
-} BusActivationEntry;
+};
 
 typedef struct BusPendingActivationEntry BusPendingActivationEntry;
 
@@ -1691,6 +1691,24 @@ bus_activation_activate_service (BusActivation  *activation,
         return FALSE;
     }
 
+  if (auto_activation &&
+      entry != NULL &&
+      !bus_context_check_security_policy (activation->context,
+        transaction,
+        connection, /* sender */
+        NULL, /* addressed recipient */
+        NULL, /* proposed recipient */
+        activation_message,
+        entry,
+        error))
+    {
+      _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 FALSE;
+    }
+
   /* Bypass the registry lookup if we're auto-activating, bus_dispatch would not
    * call us if the service is already active.
    */
index c679ac54a6f2779d6e8aa61f5beeaebc12777455..1701ca4cfbed51105bffc745eac3cd98f882a53d 100644 (file)
@@ -739,6 +739,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
@@ -755,6 +756,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 18f3ee79550e5adfdd4709d553d098cd7edcbde4..ed465f7113c0e4183a2d5aef448878fc16f1918a 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 df8239fff00b772d27884d91b5294315f4f954ac..b27b4a542a2e05de932c43dfdc0196890caa282b 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -1511,7 +1511,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).
@@ -1523,6 +1527,7 @@ bus_context_check_security_policy (BusContext     *context,
                                    DBusConnection *addressed_recipient,
                                    DBusConnection *proposed_recipient,
                                    DBusMessage    *message,
+                                   BusActivationEntry *activation_entry,
                                    DBusError      *error)
 {
   const char *src, *dest;
@@ -1543,6 +1548,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)
@@ -1608,7 +1614,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))
             {
@@ -1637,6 +1645,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;
 
@@ -1769,6 +1778,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 ca425336a02c057d22086cd56c579ec7d6dbdfc8..2e0de82559e2863f72eb86cb33e066014303ecaa 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
 {
@@ -141,6 +142,7 @@ dbus_bool_t       bus_context_check_security_policy              (BusContext
                                                                   DBusConnection   *addressed_recipient,
                                                                   DBusConnection   *proposed_recipient,
                                                                   DBusMessage      *message,
+                                                                  BusActivationEntry *activation_entry,
                                                                   DBusError        *error);
 void              bus_context_check_all_watches                  (BusContext       *context);
 
index 58fc219ec6cf4f3f020fbf3f778c5ff080f4b072..4b53cd0bf8c25c43accbcf85823f5979b3241b0e 100644 (file)
@@ -2387,7 +2387,8 @@ bus_transaction_send_from_driver (BusTransaction *transaction,
    */
   if (!bus_context_check_security_policy (bus_transaction_get_context (transaction),
                                           transaction,
-                                          NULL, connection, connection, message, &error))
+                                          NULL, connection, connection,
+                                          message, NULL, &error))
     {
       if (!bus_transaction_capture_error_reply (transaction, connection,
                                                 &error, message))
index 021dfc4a417996c830261a021c4a682447d55d26..620fd36ad385f01db7606b5a2a0c955cf1f9f395 100644 (file)
@@ -70,6 +70,7 @@ send_one_message (DBusConnection *connection,
                                           addressed_recipient,
                                           connection,
                                           message,
+                                          NULL,
                                           &stack_error))
     {
       if (!bus_transaction_capture_error_reply (transaction, sender,
@@ -147,7 +148,7 @@ bus_dispatch_matches (BusTransaction *transaction,
       if (!bus_context_check_security_policy (context, transaction,
                                               sender, addressed_recipient,
                                               addressed_recipient,
-                                              message, error))
+                                              message, NULL, error))
         return FALSE;
 
       if (dbus_message_contains_unix_fds (message) &&
@@ -380,7 +381,8 @@ bus_dispatch (DBusConnection *connection,
         }
 
       if (!bus_context_check_security_policy (context, transaction,
-                                              connection, NULL, NULL, message, &error))
+                                              connection, NULL, NULL, message,
+                                              NULL, &error))
         {
           _dbus_verbose ("Security policy rejected message\n");
           goto out;
@@ -426,12 +428,13 @@ bus_dispatch (DBusConnection *connection,
               goto out;
             }
 
-          /* 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.
+           */
           if (!bus_activation_activate_service (activation, connection, transaction, TRUE,
                                                 message, service_name, &error))
             {
index 082f3853b82794bf22e80fbbce5aea1c2fe329b8..dd0ac869c9743eae33fb1946fa20b543d83c3b53 100644 (file)
@@ -993,6 +993,11 @@ bus_client_policy_check_can_send (BusClientPolicy *policy,
            * 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 16791c8392842079715da5dbfe570d489b726ec6..e484be68f5947cb57f335f625fe6ac8e09a22c5c 100644 (file)
@@ -553,6 +553,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
@@ -566,6 +567,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))
@@ -633,7 +638,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 e44c97ede3d77169fc739b34a11effeb550ea380..5252b18988b6c6ce3263e71a1d86291e2b832c5d 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 6d5298701e0ec0676cd2c511a912f412add92622..9b2a5bb540c79f2275d25307f00f04343c5f081b 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,