]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
RHEL-4: Import dbus-0.22-selinux-backport.patch
authorColin Walters <walters@verbum.org>
Fri, 7 Jan 2011 18:31:04 +0000 (13:31 -0500)
committerColin Walters <walters@verbum.org>
Fri, 7 Jan 2011 18:31:04 +0000 (13:31 -0500)
bus/main.c
bus/selinux.c
bus/selinux.h
bus/test-main.c
configure.in

index 01a6dd42563806e849b0a155b270e32dc14c3a24..6ea712b80d651e8ae99bc7ddf2483fa535d64ed1 100644 (file)
@@ -375,9 +375,9 @@ main (int argc, char **argv)
     }
   _dbus_string_free (&pid_fd);
 
-  if (!bus_selinux_init ())
+  if (!bus_selinux_pre_init ())
     {
-      _dbus_warn ("SELinux initialization failed\n");
+      _dbus_warn ("SELinux pre-initialization failed\n");
       exit (1);
     }
 
@@ -394,6 +394,12 @@ main (int argc, char **argv)
       exit (1);
     }
 
+  if (!bus_selinux_full_init ())
+    {
+      _dbus_warn ("SELinux initialization failed\n");
+      exit (1);
+    }
+
   setup_reload_pipe (bus_context_get_loop (context));
  
   _dbus_set_signal_handler (SIGHUP, signal_handler);
index 2477233b8c8281fa0fc1eb764a3023acc8e8d738..33f59873dab1049c37998224d25539c7f96d6d25 100644 (file)
 
 #ifdef HAVE_SELINUX
 #include <errno.h>
+#include <pthread.h>
 #include <syslog.h>
 #include <selinux/selinux.h>
 #include <selinux/avc.h>
 #include <selinux/av_permissions.h>
 #include <selinux/flask.h>
+#include <signal.h>
 #include <stdarg.h>
 #endif /* HAVE_SELINUX */
 
@@ -47,7 +49,44 @@ static dbus_bool_t selinux_enabled = FALSE;
 /* Store an avc_entry_ref to speed AVC decisions. */
 static struct avc_entry_ref aeref;
 
+/* Store the SID of the bus itself to use as the default. */
 static security_id_t bus_sid = SECSID_WILD;
+
+/* Thread to listen for SELinux status changes via netlink. */
+static pthread_t avc_notify_thread;
+
+/* Prototypes for AVC callback functions.  */
+static void log_callback (const char *fmt, ...);
+static void *avc_create_thread (void (*run) (void));
+static void avc_stop_thread (void *thread);
+static void *avc_alloc_lock (void);
+static void avc_get_lock (void *lock);
+static void avc_release_lock (void *lock);
+static void avc_free_lock (void *lock);
+
+/* AVC callback structures for use in avc_init.  */
+static const struct avc_memory_callback mem_cb =
+{
+  .func_malloc = dbus_malloc,
+  .func_free = dbus_free
+};
+static const struct avc_log_callback log_cb =
+{
+  .func_log = log_callback,
+  .func_audit = NULL
+};
+static const struct avc_thread_callback thread_cb =
+{
+  .func_create_thread = avc_create_thread,
+  .func_stop_thread = avc_stop_thread
+};
+static const struct avc_lock_callback lock_cb =
+{
+  .func_alloc_lock = avc_alloc_lock,
+  .func_get_lock = avc_get_lock,
+  .func_release_lock = avc_release_lock,
+  .func_free_lock = avc_free_lock
+};
 #endif /* HAVE_SELINUX */
 
 /**
@@ -67,18 +106,111 @@ log_callback (const char *fmt, ...)
   vsyslog (LOG_INFO, fmt, ap);
   va_end(ap);
 }
+
+/**
+ * On a policy reload we need to reparse the SELinux configuration file, since
+ * this could have changed.  Send a SIGHUP to reload all configs.
+ */
+static int
+policy_reload_callback (u_int32_t event, security_id_t ssid,
+                        security_id_t tsid, security_class_t tclass,
+                        access_vector_t perms, access_vector_t *out_retained)
+{
+  if (event == AVC_CALLBACK_RESET)
+    return raise (SIGHUP);
+
+  return 0;
+}
+
+/**
+ * Create thread to notify the AVC of enforcing and policy reload
+ * changes via netlink.
+ *
+ * @param run the thread run function
+ * @return pointer to the thread
+ */
+static void *
+avc_create_thread (void (*run) (void))
+{
+  int rc;
+
+  rc = pthread_create (&avc_notify_thread, NULL, (void *(*) (void *)) run, NULL);
+  if (rc != 0)
+    {
+      _dbus_warn ("Failed to start AVC thread: %s\n", _dbus_strerror (rc));
+      exit (1);
+    }
+  return &avc_notify_thread;
+}
+
+/* Stop AVC netlink thread.  */
+static void
+avc_stop_thread (void *thread)
+{
+  pthread_cancel (*(pthread_t *) thread);
+}
+
+/* Allocate a new AVC lock.  */
+static void *
+avc_alloc_lock (void)
+{
+  pthread_mutex_t *avc_mutex;
+
+  avc_mutex = dbus_new (pthread_mutex_t, 1);
+  if (avc_mutex == NULL)
+    {
+      _dbus_warn ("Could not create mutex: %s\n", _dbus_strerror (errno));
+      exit (1);
+    }
+  pthread_mutex_init (avc_mutex, NULL);
+
+  return avc_mutex;
+}
+
+/* Acquire an AVC lock.  */
+static void
+avc_get_lock (void *lock)
+{
+  pthread_mutex_lock (lock);
+}
+
+/* Release an AVC lock.  */
+static void
+avc_release_lock (void *lock)
+{
+  pthread_mutex_unlock (lock);
+}
+
+/* Free an AVC lock.  */
+static void
+avc_free_lock (void *lock)
+{
+  pthread_mutex_destroy (lock);
+  dbus_free (lock);
+}
 #endif /* HAVE_SELINUX */
 
+/**
+ * Return whether or not SELinux is enabled; must be
+ * called after bus_selinux_init.
+ */
+dbus_bool_t
+bus_selinux_enabled (void)
+{
+#ifdef HAVE_SELINUX
+  return selinux_enabled;
+#else
+  return FALSE;
+#endif /* HAVE_SELINUX */
+}
 
 /**
- * Initialize the user space access vector cache (AVC) for D-BUS and set up
- * logging callbacks.
+ * Do early initialization; determine whether SELinux is enabled.
  */
 dbus_bool_t
-bus_selinux_init (void)
+bus_selinux_pre_init (void)
 {
 #ifdef HAVE_SELINUX
-  struct avc_log_callback log_cb = {(void*)log_callback, NULL};
   int r;
   char *bus_context;
 
@@ -94,6 +226,24 @@ bus_selinux_init (void)
     }
 
   selinux_enabled = r != 0;
+  return TRUE;
+#else
+  return TRUE;
+#endif
+}
+
+/**
+ * Initialize the user space access vector cache (AVC) for D-BUS and set up
+ * logging callbacks.
+ */
+dbus_bool_t
+bus_selinux_full_init (void)
+{
+#ifdef HAVE_SELINUX
+  int r;
+  char *bus_context;
+
+  _dbus_assert (bus_sid == SECSID_WILD);
 
   if (!selinux_enabled)
     {
@@ -104,7 +254,7 @@ bus_selinux_init (void)
   _dbus_verbose ("SELinux is enabled in this kernel.\n");
 
   avc_entry_ref_init (&aeref);
-  if (avc_init ("avc", NULL, &log_cb, NULL, NULL) < 0)
+  if (avc_init ("avc", &mem_cb, &log_cb, &thread_cb, &lock_cb) < 0)
     {
       _dbus_warn ("Failed to start Access Vector Cache (AVC).\n");
       return FALSE;
@@ -115,6 +265,15 @@ bus_selinux_init (void)
       _dbus_verbose ("Access Vector Cache (AVC) started.\n");
     }
 
+  if (avc_add_callback (policy_reload_callback, AVC_CALLBACK_RESET,
+                       NULL, NULL, 0, 0) < 0)
+    {
+      _dbus_warn ("Failed to add policy reload callback: %s\n",
+                  _dbus_strerror (errno));
+      avc_destroy ();
+      return FALSE;
+    }
+
   bus_context = NULL;
   bus_sid = SECSID_WILD;
 
@@ -141,7 +300,6 @@ bus_selinux_init (void)
 #endif /* HAVE_SELINUX */
 }
 
-
 /**
  * Decrement SID reference count.
  * 
@@ -198,7 +356,7 @@ bus_selinux_check (BusSELinuxID        *sender_sid,
 {
   if (!selinux_enabled)
     return TRUE;
-  
+
   /* Make the security check.  AVC checks enforcing mode here as well. */
   if (avc_has_perm (SELINUX_SID_FROM_BUS (sender_sid),
                     override_sid ?
@@ -367,7 +525,8 @@ bus_selinux_init_connection_id (DBusConnection *connection,
 }
 
 
-/* Function for freeing hash table data.  These SIDs
+/**
+ * Function for freeing hash table data.  These SIDs
  * should no longer be referenced.
  */
 static void
@@ -424,7 +583,7 @@ bus_selinux_id_table_insert (DBusHashTable *service_table,
   if (key == NULL)
     return retval;
   
-  if (avc_context_to_sid (service_context, &sid) < 0)
+  if (avc_context_to_sid ((char *) service_context, &sid) < 0)
     {
       _dbus_assert (errno == ENOMEM);
       goto out;
@@ -466,9 +625,6 @@ bus_selinux_id_table_insert (DBusHashTable *service_table,
  * constant time operation.  If SELinux support is not available,
  * always return NULL.
  *
- * @todo This should return a const security_id_t since we don't
- *       want the caller to mess with it.
- *
  * @param service_table the hash table to check for service name.
  * @param service_name the name of the service to look for.
  * @returns the SELinux ID associated with the service
@@ -503,6 +659,13 @@ bus_selinux_id_table_lookup (DBusHashTable    *service_table,
   return NULL;
 }
 
+/**
+ * Copy security ID table mapping from one table into another.
+ *
+ * @param dest the table to copy into
+ * @param override the table to copy from
+ * @returns #FALSE if out of memory
+ */
 #ifdef HAVE_SELINUX
 static dbus_bool_t
 bus_selinux_id_table_copy_over (DBusHashTable    *dest,
@@ -578,6 +741,20 @@ bus_selinux_id_table_union (DBusHashTable    *base,
   return combined_table;
 }
 
+/**
+ * Get the SELinux policy root.  This is used to find the D-BUS
+ * specific config file within the policy.
+ */
+const char *
+bus_selinux_get_policy_root (void)
+{
+#ifdef HAVE_SELINUX
+  return selinux_policy_root ();
+#else
+  return NULL;
+#endif /* HAVE_SELINUX */
+}
+
 /**
  * For debugging:  Print out the current hash table of service SIDs.
  */
index 08ea3a023df1e37c8cfb1fb6f923e40c1d523cf4..13122520580e681e33da28b055de8d99661a700e 100644 (file)
 #include <dbus/dbus-connection.h>
 #include "services.h"
 
-dbus_bool_t bus_selinux_init     (void);
+dbus_bool_t bus_selinux_pre_init (void);
+dbus_bool_t bus_selinux_full_init(void);
 void        bus_selinux_shutdown (void);
 
+dbus_bool_t bus_selinux_enabled  (void);
+
 void bus_selinux_id_ref    (BusSELinuxID *sid);
 void bus_selinux_id_unref  (BusSELinuxID *sid);
 
@@ -42,7 +45,7 @@ dbus_bool_t    bus_selinux_id_table_insert (DBusHashTable    *service_table,
 DBusHashTable* bus_selinux_id_table_union  (DBusHashTable    *base,
                                             DBusHashTable    *override);
 void           bus_selinux_id_table_print  (DBusHashTable    *service_table);
-
+const char*    bus_selinux_get_policy_root (void);
 
 
 dbus_bool_t bus_selinux_allows_acquire_service (DBusConnection *connection,
index d92e3fee02a6223c142720edecdea0f39cd9736f..7409182d309143e6c2c1e50c78af5152a28257d5 100644 (file)
@@ -52,6 +52,25 @@ check_memleaks (const char *name)
 }
 #endif /* DBUS_BUILD_TESTS */
 
+static void
+test_pre_hook (void)
+{
+
+  if (_dbus_getenv ("DBUS_TEST_SELINUX")
+      && !bus_selinux_pre_init ()
+      && !bus_selinux_full_init ())
+    die ("could not init selinux support");
+}
+
+static char *progname = "";
+static void
+test_post_hook (void)
+{
+  if (_dbus_getenv ("DBUS_TEST_SELINUX"))
+    bus_selinux_shutdown ();
+  check_memleaks (progname);
+}
+
 int
 main (int argc, char **argv)
 {
@@ -59,6 +78,8 @@ main (int argc, char **argv)
   const char *dir;
   DBusString test_data_dir;
 
+  progname = argv[0];
+
   if (argc > 1)
     dir = argv[1];
   else
@@ -70,9 +91,6 @@ main (int argc, char **argv)
       return 1;
     }
 
-  if (!bus_selinux_init ())
-    die ("could not init selinux support");
-
   _dbus_string_init_const (&test_data_dir, dir);
 
 #if 0
@@ -81,50 +99,50 @@ main (int argc, char **argv)
     die ("initializing debug threads");
 #endif
  
+  test_pre_hook ();
   printf ("%s: Running expire list test\n", argv[0]);
   if (!bus_expire_list_test (&test_data_dir))
     die ("expire list");
-  
-  check_memleaks (argv[0]);
-  
+  test_post_hook ();
+
+  test_pre_hook ();
   printf ("%s: Running config file parser test\n", argv[0]);
   if (!bus_config_parser_test (&test_data_dir))
     die ("parser");
-  
-  check_memleaks (argv[0]);  
-  
+  test_post_hook ();
+
+  test_pre_hook ();
   printf ("%s: Running policy test\n", argv[0]);
   if (!bus_policy_test (&test_data_dir))
     die ("policy");
+  test_post_hook ();
 
-  check_memleaks (argv[0]);
-
+  test_pre_hook ();
   printf ("%s: Running signals test\n", argv[0]);
   if (!bus_signals_test (&test_data_dir))
     die ("signals");
+  test_post_hook ();
 
-  check_memleaks (argv[0]);
-  
+  test_pre_hook ();
   printf ("%s: Running SHA1 connection test\n", argv[0]);
   if (!bus_dispatch_sha1_test (&test_data_dir))
     die ("sha1");
+  test_post_hook ();
 
-  check_memleaks (argv[0]);
+  test_pre_hook ();
   printf ("%s: Running message dispatch test\n", argv[0]);
   if (!bus_dispatch_test (&test_data_dir)) 
     die ("dispatch");
+  test_post_hook ();
 
-  check_memleaks (argv[0]);
-
+  test_pre_hook ();
   printf ("%s: Running service files reloading test\n", argv[0]);
   if (!bus_activation_service_reload_test (&test_data_dir))
     die ("service reload");
+  test_post_hook ();
 
-  check_memleaks (argv[0]);
-  
   printf ("%s: Success\n", argv[0]);
 
-  bus_selinux_shutdown ();
   
   return 0;
 #else /* DBUS_BUILD_TESTS */
index 56607e3e0fb931c55a5b19cf2719d2879fd7cf48..83946a483cac5e7ee7d4eceff34457b5f4bf6a92 100644 (file)
@@ -718,7 +718,7 @@ fi
 AM_CONDITIONAL(HAVE_SELINUX, test x$have_selinux = xyes)
 
 if test x$have_selinux = xyes ; then
-    SELINUX_LIBS=-lselinux
+    SELINUX_LIBS="-lselinux -lpthread"
     AC_DEFINE(HAVE_SELINUX,1,[SELinux support])
 else
     SELINUX_LIBS=