From 6b034f3d1a047e1b982ed1cfe358a5f493a5774a Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 13 Feb 2014 09:59:53 -0600 Subject: [PATCH 07/10] Store AppArmor label of connecting processes When processes connect the 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. Signed-off-by: Tyler Hicks --- bus/apparmor.c | 96 ++++++++++++++++++++++++++++++++++++++++++-------------- bus/apparmor.h | 6 ++++ bus/bus.h | 1 + bus/connection.c | 22 +++++++++++++ 4 files changed, 101 insertions(+), 24 deletions(-) diff --git a/bus/apparmor.c b/bus/apparmor.c index 2bcd18d..414047c 100644 --- a/bus/apparmor.c +++ b/bus/apparmor.c @@ -50,6 +50,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; @@ -74,8 +76,6 @@ struct BusAppArmorConfinement char *mode; /* AppArmor confinement mode */ }; -typedef struct BusAppArmorConfinement BusAppArmorConfinement; - static BusAppArmorConfinement *bus_con = NULL; static BusAppArmorConfinement* @@ -94,28 +94,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) { @@ -285,3 +263,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\n"); + return NULL; + } + + if (aa_getpeercon (fd, &context, &mode) == -1) + { + if (errno == ENOMEM) + BUS_SET_OOM (error); + else + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to get AppArmor confinement information of socket peer: %s\n", + _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..8c359d8 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,9 @@ 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.rc1