Mediation of processes eavesdropping
authorTyler Hicks <tyhicks@canonical.com>
Thu, 13 Feb 2014 19:17:23 +0000 (13:17 -0600)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Wed, 18 Feb 2015 18:59:46 +0000 (18:59 +0000)
When an AppArmor confined process wants to eavesdrop on a bus, a check
is performed to see if the action should be allowed.

The check is based on the connection's label and the bus type.

This patch adds a new hook, which was not previously included in the
SELinux mediation, to mediate eavesdropping from
bus_driver_handle_add_match().

A new function is added to bus/signals.c to see if a match rule is an
eavesdropping rule since the rule flags field is private to signals.c.

An example AppArmor rule that would allow a process to eavesdrop on the
session bus would be:

  dbus eavesdrop bus=session,

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=75113
Signed-off-by: Tyler Hicks <tyhicks@canonical.com>
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
bus/apparmor.c
bus/apparmor.h
bus/driver.c
bus/signals.c
bus/signals.h

index 615a525..8d7e910 100644 (file)
@@ -357,6 +357,12 @@ build_message_query (DBusString *query,
          query_append (query, member);
 }
 
+static dbus_bool_t
+build_eavesdrop_query (DBusString *query, const char *con, const char *bustype)
+{
+  return build_common_query (query, con, bustype);
+}
+
 static void
 set_error_from_query_errno (DBusError *error, int error_number)
 {
@@ -1007,3 +1013,114 @@ bus_apparmor_allows_send (DBusConnection     *sender,
   return TRUE;
 #endif /* HAVE_APPARMOR */
 }
+
+/**
+ * Check if Apparmor security controls allow the connection to eavesdrop on
+ * other connections.
+ *
+ * @param connection the connection attempting to eavesdrop.
+ * @param bustype name of the bus
+ * @param error the reason for failure when FALSE is returned
+ * @returns TRUE if eavesdropping is permitted
+ */
+dbus_bool_t
+bus_apparmor_allows_eavesdropping (DBusConnection     *connection,
+                                   const char         *bustype,
+                                   DBusError          *error)
+{
+#ifdef HAVE_APPARMOR
+  BusAppArmorConfinement *con = NULL;
+  DBusString qstr, auxdata;
+  dbus_bool_t allow = FALSE, audit = TRUE;
+  dbus_bool_t free_auxdata = FALSE;
+  unsigned long pid;
+  int res, serrno = 0;
+
+  if (!apparmor_enabled)
+    return TRUE;
+
+  con = bus_connection_dup_apparmor_confinement (connection);
+
+  if (is_unconfined (con->context, con->mode))
+    {
+      allow = TRUE;
+      audit = FALSE;
+      goto out;
+    }
+
+  if (!_dbus_string_init (&qstr))
+    goto oom;
+
+  if (!build_eavesdrop_query (&qstr, con->context, bustype))
+    {
+      _dbus_string_free (&qstr);
+      goto oom;
+    }
+
+  res = aa_query_label (AA_DBUS_EAVESDROP,
+                        _dbus_string_get_data (&qstr),
+                        _dbus_string_get_length (&qstr),
+                        &allow, &audit);
+  _dbus_string_free (&qstr);
+  if (res == -1)
+    {
+      serrno = errno;
+      set_error_from_query_errno (error, serrno);
+      goto audit;
+    }
+
+  /* Don't fail operations on profiles in complain mode */
+  if (modestr_is_complain (con->mode))
+    allow = TRUE;
+
+  if (!allow)
+    dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED,
+                    "Connection \"%s\" is not allowed to eavesdrop due to "
+                    "AppArmor policy",
+                    bus_connection_is_active (connection) ?
+                    bus_connection_get_name (connection) : "(inactive)");
+
+  if (!audit)
+    goto out;
+
+ audit:
+  if (!_dbus_string_init (&auxdata))
+    goto oom;
+  free_auxdata = TRUE;
+
+  if (!_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown"))
+    goto oom;
+
+  if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno)))
+    goto oom;
+
+  if (!_dbus_append_pair_str (&auxdata, "mask", "eavesdrop"))
+    goto oom;
+
+  if (connection && dbus_connection_get_unix_process_id (connection, &pid) &&
+      !_dbus_append_pair_uint (&auxdata, "pid", pid))
+    goto oom;
+
+  if (con->context && !_dbus_append_pair_str (&auxdata, "profile", con->context))
+    goto oom;
+
+  log_message (allow, "eavesdrop", &auxdata);
+
+ out:
+  if (con != NULL)
+    bus_apparmor_confinement_unref (con);
+  if (free_auxdata)
+    _dbus_string_free (&auxdata);
+
+  return allow;
+
+ oom:
+  if (error != NULL && !dbus_error_is_set (error))
+    BUS_SET_OOM (error);
+  allow = FALSE;
+  goto out;
+
+#else
+  return TRUE;
+#endif /* HAVE_APPARMOR */
+}
index 3f3d646..4a47aec 100644 (file)
@@ -59,4 +59,8 @@ dbus_bool_t bus_apparmor_allows_send (DBusConnection     *sender,
                                       const char         *source,
                                       DBusError          *error);
 
+dbus_bool_t bus_apparmor_allows_eavesdropping (DBusConnection     *connection,
+                                               const char         *bustype,
+                                               DBusError          *error);
+
 #endif /* BUS_APPARMOR_H */
index 442dd01..53bd559 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <config.h>
 #include "activation.h"
+#include "apparmor.h"
 #include "connection.h"
 #include "driver.h"
 #include "dispatch.h"
@@ -1110,9 +1111,10 @@ bus_driver_handle_add_match (DBusConnection *connection,
                              DBusError      *error)
 {
   BusMatchRule *rule;
-  const char *text;
+  const char *text, *bustype;
   DBusString str;
   BusMatchmaker *matchmaker;
+  BusContext *context;
 
   _DBUS_ASSERT_ERROR_IS_CLEAR (error);
 
@@ -1145,6 +1147,12 @@ bus_driver_handle_add_match (DBusConnection *connection,
   if (rule == NULL)
     goto failed;
 
+  context = bus_transaction_get_context (transaction);
+  bustype = context ? bus_context_get_type (context) : NULL;
+  if (bus_match_rule_get_client_is_eavesdropping (rule) &&
+      !bus_apparmor_allows_eavesdropping (connection, bustype, error))
+    goto failed;
+
   matchmaker = bus_connection_get_matchmaker (connection);
 
   if (!bus_matchmaker_add_rule (matchmaker, rule))
index 4390028..260dd24 100644 (file)
@@ -411,6 +411,15 @@ bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule,
 }
 
 dbus_bool_t
+bus_match_rule_get_client_is_eavesdropping (BusMatchRule *rule)
+{
+  if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+dbus_bool_t
 bus_match_rule_set_path (BusMatchRule *rule,
                          const char   *path,
                          dbus_bool_t   is_namespace)
index d19fc7c..0edfb07 100644 (file)
@@ -73,6 +73,8 @@ dbus_bool_t bus_match_rule_set_arg          (BusMatchRule     *rule,
 void bus_match_rule_set_client_is_eavesdropping (BusMatchRule     *rule,
                                                  dbus_bool_t is_eavesdropping);
 
+dbus_bool_t bus_match_rule_get_client_is_eavesdropping (BusMatchRule *rule);
+
 BusMatchRule* bus_match_rule_parse (DBusConnection   *matches_go_to,
                                     const DBusString *rule_text,
                                     DBusError        *error);