e3782d
From 8b74179ee31652bbaaf979777b9e829b426053ef Mon Sep 17 00:00:00 2001
e3782d
From: David King <dking@redhat.com>
e3782d
Date: Tue, 4 Nov 2014 10:10:36 +0000
e3782d
Subject: [PATCH] selinux: Check ListNames permissions with MLS
e3782d
e3782d
https://bugzilla.redhat.com/show_bug.cgi?id=1118399
e3782d
---
e3782d
 bus/driver.c  |  52 +++++++++++++++++++++++++
e3782d
 bus/selinux.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
e3782d
 bus/selinux.h |   5 +++
e3782d
 3 files changed, 180 insertions(+)
e3782d
e3782d
diff --git a/bus/driver.c b/bus/driver.c
e3782d
index 574e0f3..20cc940 100644
e3782d
--- a/bus/driver.c
e3782d
+++ b/bus/driver.c
e3782d
@@ -379,6 +379,9 @@ bus_driver_handle_list_services (DBusConnection *connection,
e3782d
   char **services;
e3782d
   BusRegistry *registry;
e3782d
   int i;
e3782d
+#ifdef HAVE_SELINUX
e3782d
+  dbus_bool_t mls_enabled;
e3782d
+#endif
e3782d
   DBusMessageIter iter;
e3782d
   DBusMessageIter sub;
e3782d
 
e3782d
@@ -425,9 +428,58 @@ bus_driver_handle_list_services (DBusConnection *connection,
e3782d
       }
e3782d
   }
e3782d
 
e3782d
+#ifdef HAVE_SELINUX
e3782d
+  mls_enabled = bus_selinux_mls_enabled ();
e3782d
+#endif
e3782d
   i = 0;
e3782d
   while (i < len)
e3782d
     {
e3782d
+#ifdef HAVE_SELINUX
e3782d
+      if (mls_enabled)
e3782d
+        {
e3782d
+          const char *requester;
e3782d
+          BusService *service;
e3782d
+          DBusString str;
e3782d
+          DBusConnection *service_conn;
e3782d
+          DBusConnection *requester_conn;
e3782d
+
e3782d
+          requester = dbus_message_get_destination (reply);
e3782d
+          _dbus_string_init_const (&str, requester);
e3782d
+          service = bus_registry_lookup (registry, &str);
e3782d
+
e3782d
+          if (service == NULL)
e3782d
+            {
e3782d
+              _dbus_warn_check_failed ("service lookup failed: %s", requester);
e3782d
+              ++i;
e3782d
+              continue;
e3782d
+            }
e3782d
+          requester_conn = bus_service_get_primary_owners_connection (service);
e3782d
+          _dbus_string_init_const (&str, services[i]);
e3782d
+          service = bus_registry_lookup (registry, &str);
e3782d
+          if (service == NULL)
e3782d
+            {
e3782d
+              _dbus_warn_check_failed ("service lookup failed: %s", services[i]);
e3782d
+              ++i;
e3782d
+              continue;
e3782d
+            }
e3782d
+          service_conn = bus_service_get_primary_owners_connection (service);
e3782d
+
e3782d
+          if (!bus_selinux_allows_name (requester_conn, service_conn, error))
e3782d
+            {
e3782d
+              if (dbus_error_is_set (error) &&
e3782d
+                  dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY))
e3782d
+                {
e3782d
+                  dbus_free_string_array (services);
e3782d
+                  dbus_message_unref (reply);
e3782d
+                  return FALSE;
e3782d
+                }
e3782d
+
e3782d
+              /* Skip any services which are disallowed by SELinux policy. */
e3782d
+              ++i;
e3782d
+              continue;
e3782d
+            }
e3782d
+        }
e3782d
+#endif
e3782d
       if (!dbus_message_iter_append_basic (&sub, DBUS_TYPE_STRING,
e3782d
                                            &services[i]))
e3782d
         {
e3782d
diff --git a/bus/selinux.c b/bus/selinux.c
e3782d
index 36287e9..6442b79 100644
e3782d
--- a/bus/selinux.c
e3782d
+++ b/bus/selinux.c
e3782d
@@ -63,6 +63,9 @@
e3782d
 /* Store the value telling us if SELinux is enabled in the kernel. */
e3782d
 static dbus_bool_t selinux_enabled = FALSE;
e3782d
 
e3782d
+/* Store the value telling us if SELinux with MLS is enabled in the kernel. */
e3782d
+static dbus_bool_t selinux_mls_enabled = FALSE;
e3782d
+
e3782d
 /* Store an avc_entry_ref to speed AVC decisions. */
e3782d
 static struct avc_entry_ref aeref;
e3782d
 
e3782d
@@ -289,6 +292,20 @@ bus_selinux_enabled (void)
e3782d
 }
e3782d
 
e3782d
 /**
e3782d
+ * Return whether or not SELinux with MLS support is enabled; must be
e3782d
+ * called after bus_selinux_init.
e3782d
+ */
e3782d
+dbus_bool_t
e3782d
+bus_selinux_mls_enabled (void)
e3782d
+{
e3782d
+#ifdef HAVE_SELINUX
e3782d
+  return selinux_mls_enabled;
e3782d
+#else
e3782d
+  return FALSE;
e3782d
+#endif /* HAVE_SELINUX */
e3782d
+}
e3782d
+
e3782d
+/**
e3782d
  * Do early initialization; determine whether SELinux is enabled.
e3782d
  */
e3782d
 dbus_bool_t
e3782d
@@ -308,6 +325,16 @@ bus_selinux_pre_init (void)
e3782d
     }
e3782d
 
e3782d
   selinux_enabled = r != 0;
e3782d
+
e3782d
+  r = is_selinux_mls_enabled ();
e3782d
+  if (r < 0)
e3782d
+    {
e3782d
+      _dbus_warn ("Could not tell if SELinux MLS is enabled: %s\n",
e3782d
+                  _dbus_strerror (errno));
e3782d
+      return FALSE;
e3782d
+    }
e3782d
+
e3782d
+  selinux_mls_enabled = r != 0;
e3782d
   return TRUE;
e3782d
 #else
e3782d
   return TRUE;
e3782d
@@ -724,6 +751,102 @@ bus_connection_read_selinux_context (DBusConnection     *connection,
e3782d
 #endif /* HAVE_SELINUX */
e3782d
 
e3782d
 /**
e3782d
+ * Check if SELinux security controls allow one connection to determine the
e3782d
+ * name of the other, taking into account MLS considerations.
e3782d
+ *
e3782d
+ * @param source the requester of the name.
e3782d
+ * @param destination the name being requested.
e3782d
+ * @returns whether the name should be visible by the source of the request
e3782d
+ */
e3782d
+dbus_bool_t
e3782d
+bus_selinux_allows_name (DBusConnection     *source,
e3782d
+                         DBusConnection     *destination,
e3782d
+                         DBusError          *error)
e3782d
+{
e3782d
+#ifdef HAVE_SELINUX
e3782d
+  int err;
e3782d
+  char *policy_type;
e3782d
+  unsigned long spid, tpid;
e3782d
+  BusSELinuxID *source_sid;
e3782d
+  BusSELinuxID *dest_sid;
e3782d
+  dbus_bool_t ret;
e3782d
+  dbus_bool_t string_alloced;
e3782d
+  DBusString auxdata;
e3782d
+
e3782d
+  if (!selinux_mls_enabled)
e3782d
+    return TRUE;
e3782d
+
e3782d
+  err = selinux_getpolicytype (&policy_type);
e3782d
+  if (err < 0)
e3782d
+    {
e3782d
+      dbus_set_error_const (error, DBUS_ERROR_IO_ERROR,
e3782d
+                            "Failed to get SELinux policy type");
e3782d
+      return FALSE;
e3782d
+    }
e3782d
+
e3782d
+  /* Only check against MLS policy if running under that policy. */
e3782d
+  if (strcmp (policy_type, "mls") != 0)
e3782d
+    {
e3782d
+      free (policy_type);
e3782d
+      return TRUE;
e3782d
+    }
e3782d
+
e3782d
+  free (policy_type);
e3782d
+
e3782d
+  _dbus_assert (source != NULL);
e3782d
+  _dbus_assert (destination != NULL);
e3782d
+
e3782d
+  if (!source || !dbus_connection_get_unix_process_id (source, &spid))
e3782d
+    spid = 0;
e3782d
+  if (!destination || !dbus_connection_get_unix_process_id (destination, &tpid))
e3782d
+    tpid = 0;
e3782d
+
e3782d
+  string_alloced = FALSE;
e3782d
+  if (!_dbus_string_init (&auxdata))
e3782d
+    goto oom;
e3782d
+  string_alloced = TRUE;
e3782d
+
e3782d
+  if (spid)
e3782d
+    {
e3782d
+      if (!_dbus_string_append (&auxdata, " spid="))
e3782d
+	goto oom;
e3782d
+
e3782d
+      if (!_dbus_string_append_uint (&auxdata, spid))
e3782d
+	goto oom;
e3782d
+    }
e3782d
+
e3782d
+  if (tpid)
e3782d
+    {
e3782d
+      if (!_dbus_string_append (&auxdata, " tpid="))
e3782d
+	goto oom;
e3782d
+
e3782d
+      if (!_dbus_string_append_uint (&auxdata, tpid))
e3782d
+	goto oom;
e3782d
+    }
e3782d
+
e3782d
+  source_sid = bus_connection_get_selinux_id (source);
e3782d
+  dest_sid = bus_connection_get_selinux_id (destination);
e3782d
+
e3782d
+  ret = bus_selinux_check (source_sid,
e3782d
+                           dest_sid,
e3782d
+                           SECCLASS_CONTEXT,
e3782d
+                           CONTEXT__CONTAINS,
e3782d
+                           &auxdata);
e3782d
+
e3782d
+  _dbus_string_free (&auxdata);
e3782d
+  return ret;
e3782d
+
e3782d
+ oom:
e3782d
+  if (string_alloced)
e3782d
+    _dbus_string_free (&auxdata);
e3782d
+  BUS_SET_OOM (error);
e3782d
+  return FALSE;
e3782d
+#else
e3782d
+  return TRUE;
e3782d
+#endif /* HAVE_SELINUX */
e3782d
+}
e3782d
+
e3782d
+/**
e3782d
  * Read the SELinux ID from the connection.
e3782d
  *
e3782d
  * @param connection the connection to read from
e3782d
diff --git a/bus/selinux.h b/bus/selinux.h
e3782d
index 3bab36d..fcaac5f 100644
e3782d
--- a/bus/selinux.h
e3782d
+++ b/bus/selinux.h
e3782d
@@ -32,6 +32,7 @@ dbus_bool_t bus_selinux_full_init(void);
e3782d
 void        bus_selinux_shutdown (void);
e3782d
 
e3782d
 dbus_bool_t bus_selinux_enabled  (void);
e3782d
+dbus_bool_t bus_selinux_mls_enabled (void);
e3782d
 
e3782d
 void bus_selinux_id_ref    (BusSELinuxID *sid);
e3782d
 void bus_selinux_id_unref  (BusSELinuxID *sid);
e3782d
@@ -54,6 +55,10 @@ dbus_bool_t bus_selinux_allows_acquire_service (DBusConnection *connection,
e3782d
 						const char     *service_name,
e3782d
 						DBusError      *error);
e3782d
 
e3782d
+dbus_bool_t bus_selinux_allows_name            (DBusConnection *source,
e3782d
+                                                DBusConnection *destination,
e3782d
+                                                DBusError      *error);
e3782d
+
e3782d
 dbus_bool_t bus_selinux_allows_send            (DBusConnection *sender,
e3782d
                                                 DBusConnection *proposed_recipient,
e3782d
 						const char     *msgtype, /* Supplementary audit data */
e3782d
-- 
e3782d
2.1.0
e3782d