From 7f2405d41c2e7c523b2c1ce3d790c9e862536b4d Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 13 Feb 2014 09:59:53 -0600 Subject: [PATCH v3 07/13] Store AppArmor label of connecting processes 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. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=75113 Signed-off-by: Tyler Hicks --- * Changes in v2: - Use _dbus_error_from_errno() in bus_apparmor_init_connection_confinement() - Removed trailing newlines from error strings - Fix coding style issue of bus_apparmor_init_connection_confinement() declaration * Changes in v3: - Added Bug link in commit message bus/apparmor.c | 96 ++++++++++++++++++++++++++++++++++++++++++-------------- bus/apparmor.h | 5 +++ bus/bus.h | 1 + bus/connection.c | 22 +++++++++++++ 4 files changed, 100 insertions(+), 24 deletions(-) diff --git a/bus/apparmor.c b/bus/apparmor.c index 35a297f..fb3a97a 100644 --- a/bus/apparmor.c +++ b/bus/apparmor.c @@ -48,6 +48,8 @@ #include #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 char *mode; /* AppArmor confinement mode */ }; -typedef struct BusAppArmorConfinement BusAppArmorConfinement; - static BusAppArmorConfinement *bus_con = NULL; static BusAppArmorConfinement* @@ -92,28 +92,6 @@ bus_apparmor_confinement_new (char *context, char *mode) return confinement; } -static void -bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement) -{ - if (!apparmor_enabled) - return; - - _dbus_assert (confinement != NULL); - _dbus_assert (confinement->refcount > 0); - - confinement->refcount -= 1; - - if (confinement->refcount == 0) - { - /** - * Do not free confinement->mode, as libapparmor does a single malloc for - * both confinement->context and confinement->mode. - */ - free (confinement->context); - dbus_free (confinement); - } -} - void bus_apparmor_audit_init (void) { @@ -297,3 +275,73 @@ bus_apparmor_enabled (void) #endif return FALSE; } + +void +bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement) +{ +#ifdef HAVE_APPARMOR + if (!apparmor_enabled) + return; + + _dbus_assert (confinement != NULL); + _dbus_assert (confinement->refcount > 0); + + confinement->refcount -= 1; + + if (confinement->refcount == 0) + { + /** + * Do not free confinement->mode, as libapparmor does a single malloc for + * both confinement->context and confinement->mode. + */ + free (confinement->context); + dbus_free (confinement); + } +#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 */ +} diff --git a/bus/apparmor.h b/bus/apparmor.h index bf8f94f..8c97420 100644 --- a/bus/apparmor.h +++ b/bus/apparmor.h @@ -27,6 +27,7 @@ #define BUS_APPARMOR_H #include +#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 (void); 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 */ diff --git a/bus/bus.h b/bus/bus.h index 3597884..8e12e27 100644 --- 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; diff --git a/bus/connection.c b/bus/connection.c index ea2d155..d15cb56 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -30,6 +30,7 @@ #include "signals.h" #include "expirelist.h" #include "selinux.h" +#include "apparmor.h" #include #include #include @@ -93,6 +94,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) */ @@ -404,6 +406,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); @@ -637,6 +642,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, @@ -722,6 +740,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, -- 1.9.1