Store AppArmor label of connecting processes
authorTyler Hicks <tyhicks@canonical.com>
Thu, 13 Feb 2014 15:59:53 +0000 (09:59 -0600)
committerSimon McVittie <simon.mcvittie@collabora.co.uk>
Wed, 18 Feb 2015 17:04:05 +0000 (17:04 +0000)
When processes connect the bus, the AppArmor confinement context should
be stored for later use when checks are to be done during message
sending/receiving, acquire a name, and eavesdropping.

Code outside of apparmor.c will need to initialize and unreference the
confinement context, so bus_apparmor_confinement_unref() can no longer
be a static function.

[Move bus_apparmor_confinement_unref back to its old location for
a more reasonable diff -smcv]

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=75113
Reviewed-by: Simon McVittie <simon.mcvittie@collabora.co.uk>
bus/apparmor.c
bus/apparmor.h
bus/bus.h
bus/connection.c

index 3b2be35..d22ac67 100644 (file)
@@ -48,6 +48,8 @@
 #include <syslog.h>
 #endif /* HAVE_LIBAUDIT */
 
+#include "utils.h"
+
 /* Store the value telling us if AppArmor D-Bus mediation is enabled. */
 static dbus_bool_t apparmor_enabled = FALSE;
 
@@ -72,8 +74,6 @@ struct BusAppArmorConfinement
   const char *mode; /* AppArmor confinement mode (freed by freeing *context) */
 };
 
-typedef struct BusAppArmorConfinement BusAppArmorConfinement;
-
 static BusAppArmorConfinement *bus_con = NULL;
 
 /**
@@ -103,9 +103,10 @@ bus_apparmor_confinement_new (char *context, const char *mode)
   return confinement;
 }
 
-static void
+void
 bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement)
 {
+#ifdef HAVE_APPARMOR
   if (!apparmor_enabled)
     return;
 
@@ -123,6 +124,7 @@ bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement)
       free (confinement->context);
       dbus_free (confinement);
     }
+#endif
 }
 
 void
@@ -339,3 +341,49 @@ bus_apparmor_enabled (void)
   return FALSE;
 #endif
 }
+
+BusAppArmorConfinement*
+bus_apparmor_init_connection_confinement (DBusConnection *connection,
+                                          DBusError      *error)
+{
+#ifdef HAVE_APPARMOR
+  BusAppArmorConfinement *confinement;
+  char *context, *mode;
+  int fd;
+
+  if (!apparmor_enabled)
+    return NULL;
+
+  _dbus_assert (connection != NULL);
+
+  if (!dbus_connection_get_socket (connection, &fd))
+    {
+      dbus_set_error (error, DBUS_ERROR_FAILED,
+                      "Failed to get socket file descriptor of connection");
+      return NULL;
+    }
+
+  if (aa_getpeercon (fd, &context, &mode) == -1)
+    {
+      if (errno == ENOMEM)
+        BUS_SET_OOM (error);
+      else
+        dbus_set_error (error, _dbus_error_from_errno (errno),
+                        "Failed to get AppArmor confinement information of socket peer: %s",
+                        _dbus_strerror (errno));
+      return NULL;
+    }
+
+  confinement = bus_apparmor_confinement_new (context, mode);
+  if (confinement == NULL)
+    {
+      BUS_SET_OOM (error);
+      free (context);
+      return NULL;
+    }
+
+  return confinement;
+#else
+  return NULL;
+#endif /* HAVE_APPARMOR */
+}
index 66a77c0..861094e 100644 (file)
@@ -27,6 +27,7 @@
 #define BUS_APPARMOR_H
 
 #include <dbus/dbus.h>
+#include "bus.h"
 
 void bus_apparmor_audit_init (void);
 dbus_bool_t bus_apparmor_pre_init (void);
@@ -36,4 +37,8 @@ dbus_bool_t bus_apparmor_full_init (DBusError *error);
 void bus_apparmor_shutdown (void);
 dbus_bool_t bus_apparmor_enabled (void);
 
+void bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement);
+BusAppArmorConfinement* bus_apparmor_init_connection_confinement (DBusConnection *connection,
+                                                                  DBusError      *error);
+
 #endif /* BUS_APPARMOR_H */
index 57ad5c7..3fab59f 100644 (file)
--- a/bus/bus.h
+++ b/bus/bus.h
@@ -38,6 +38,7 @@ typedef struct BusClientPolicy  BusClientPolicy;
 typedef struct BusPolicyRule    BusPolicyRule;
 typedef struct BusRegistry      BusRegistry;
 typedef struct BusSELinuxID     BusSELinuxID;
+typedef struct BusAppArmorConfinement BusAppArmorConfinement;
 typedef struct BusService       BusService;
 typedef struct BusOwner                BusOwner;
 typedef struct BusTransaction   BusTransaction;
index 64da129..93f9967 100644 (file)
@@ -30,6 +30,7 @@
 #include "signals.h"
 #include "expirelist.h"
 #include "selinux.h"
+#include "apparmor.h"
 #include <dbus/dbus-list.h>
 #include <dbus/dbus-hash.h>
 #include <dbus/dbus-timeout.h>
@@ -99,6 +100,7 @@ typedef struct
 
   char *cached_loginfo_string;
   BusSELinuxID *selinux_id;
+  BusAppArmorConfinement *apparmor_confinement;
 
   long connection_tv_sec;  /**< Time when we connected (seconds component) */
   long connection_tv_usec; /**< Time when we connected (microsec component) */
@@ -439,6 +441,9 @@ free_connection_data (void *data)
 
   if (d->selinux_id)
     bus_selinux_id_unref (d->selinux_id);
+
+  if (d->apparmor_confinement)
+    bus_apparmor_confinement_unref (d->apparmor_confinement);
   
   dbus_free (d->cached_loginfo_string);
   
@@ -714,6 +719,19 @@ bus_connections_setup_connection (BusConnections *connections,
       goto out;
     }
 
+  d->apparmor_confinement = bus_apparmor_init_connection_confinement (connection,
+                                                                      &error);
+  if (dbus_error_is_set (&error))
+    {
+      /* This is a bit bogus because we pretend all errors
+       * are OOM; this is done because we know that in bus.c
+       * an OOM error disconnects the connection, which is
+       * the same thing we want on any other error.
+       */
+      dbus_error_free (&error);
+      goto out;
+    }
+
   if (!dbus_connection_set_watch_functions (connection,
                                             add_connection_watch,
                                             remove_connection_watch,
@@ -801,6 +819,10 @@ bus_connections_setup_connection (BusConnections *connections,
       if (d->selinux_id)
         bus_selinux_id_unref (d->selinux_id);
       d->selinux_id = NULL;
+
+      if (d->apparmor_confinement)
+        bus_apparmor_confinement_unref (d->apparmor_confinement);
+      d->apparmor_confinement = NULL;
       
       if (!dbus_connection_set_watch_functions (connection,
                                                 NULL, NULL, NULL,