From ae476fe69866a06555c120630de5007ef690d0e3 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 12 Feb 2014 12:37:41 -0600 Subject: [PATCH v3 05/13] Initialize AppArmor mediation When starting dbus-daemon, autodetect AppArmor kernel support and use the results from parsing the busconfig to determine if mediation should be enabled. In the busconfig, "enabled" means that kernel support is autodetected and, if available, AppArmor mediation occurs in dbus-daemon. In "enabled" mode, if kernel support is not detected, mediation is disabled. "disabled" means that mediation does not occur. "required" means that kernel support must be detected for dbus-daemon to start. Additionally, when libaudit support is built into dbus-daemon, the AppArmor initialization routines set up the audit connection. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=75113 Signed-off-by: John Johansen [tyhicks: Honor enforcement modes and detect AppArmor dbus rule support] Signed-off-by: Tyler Hicks --- * Changes in v2: - Assume errno.h will always be available - Convert aa_dbus from char * to DBusString - #include * Changes in v3: - Added Bug link in commit message - Rename aa_supports_dbus() to _bus_apparmor_aa_supports_dbus() - Only close the AppArmor mask file when the open succeeded in _bus_apparmor_aa_supports_dbus() - Improve the bus_apparmor_full_init() description bus/apparmor.c | 147 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bus/apparmor.h | 5 ++ bus/bus.c | 19 ++++++++ bus/main.c | 8 ++++ 4 files changed, 179 insertions(+) diff --git a/bus/apparmor.c b/bus/apparmor.c index 8c2cd84..78986d9 100644 --- a/bus/apparmor.c +++ b/bus/apparmor.c @@ -29,7 +29,27 @@ #ifdef HAVE_APPARMOR #include +#include +#include +#include +#include +#include +#include #include +#include +#include +#include +#include + +#ifdef HAVE_LIBAUDIT +#include +#include +#else +#include +#endif /* HAVE_LIBAUDIT */ + +/* Store the value telling us if AppArmor D-Bus mediation is enabled. */ +static dbus_bool_t apparmor_enabled = FALSE; typedef enum { APPARMOR_DISABLED, @@ -40,8 +60,76 @@ typedef enum { /* Store the value of the AppArmor mediation mode in the bus configuration */ static AppArmorConfigMode apparmor_config_mode = APPARMOR_ENABLED; +#ifdef HAVE_LIBAUDIT +static int audit_fd = -1; +#endif + +void +bus_apparmor_audit_init (void) +{ +#ifdef HAVE_LIBAUDIT + audit_fd = audit_open (); + + if (audit_fd < 0) + { + /* If kernel doesn't support audit, bail out */ + if (errno == EINVAL || errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) + return; + /* If user bus, bail out */ + if (errno == EPERM && getuid () != 0) + return; + _dbus_warn ("Failed opening connection to the audit subsystem"); + } +#endif /* HAVE_LIBAUDIT */ +} + +static dbus_bool_t +_bus_apparmor_aa_supports_dbus (void) +{ + int mask_file; + DBusString aa_dbus; + char *aa_securityfs = NULL; + dbus_bool_t retval = FALSE; + + if (!_dbus_string_init (&aa_dbus)) + return FALSE; + + if (aa_find_mountpoint (&aa_securityfs) != 0) + goto out; + + if (!_dbus_string_append (&aa_dbus, aa_securityfs) || + !_dbus_string_append (&aa_dbus, "/features/dbus/mask")) + goto out; + + mask_file = open (_dbus_string_get_const_data (&aa_dbus), + O_RDONLY | O_CLOEXEC); + if (mask_file != -1) + { + retval = TRUE; + close (mask_file); + } + +out: + free (aa_securityfs); + _dbus_string_free (&aa_dbus); + + return retval; +} #endif /* HAVE_APPARMOR */ +/** + * Do early initialization; determine whether AppArmor is enabled. + */ +dbus_bool_t +bus_apparmor_pre_init (void) +{ +#ifdef HAVE_APPARMOR + apparmor_enabled = (aa_is_enabled () && _bus_apparmor_aa_supports_dbus ()); +#endif + + return TRUE; +} + dbus_bool_t bus_apparmor_set_mode_from_config (const char *mode, DBusError *error) { @@ -77,3 +165,62 @@ bus_apparmor_set_mode_from_config (const char *mode, DBusError *error) return FALSE; #endif } + +/** + * Verify that the config mode is compatible with the kernel's AppArmor + * support. If AppArmor mediation will be enabled, determine the bus + * confinement context. + */ +dbus_bool_t +bus_apparmor_full_init (void) +{ +#ifdef HAVE_APPARMOR + if (apparmor_enabled) + { + if (apparmor_config_mode == APPARMOR_DISABLED) + { + apparmor_enabled = FALSE; + return TRUE; + } + } + else + { + if (apparmor_config_mode == APPARMOR_REQUIRED) + { + _dbus_warn ("AppArmor mediation required but not present\n"); + return FALSE; + } + else if (apparmor_config_mode == APPARMOR_ENABLED) + { + return TRUE; + } + } +#endif + + return TRUE; +} + +void +bus_apparmor_shutdown (void) +{ +#ifdef HAVE_APPARMOR + if (!apparmor_enabled) + return; + + _dbus_verbose ("AppArmor shutdown\n"); + +#ifdef HAVE_LIBAUDIT + audit_close (audit_fd); +#endif /* HAVE_LIBAUDIT */ + +#endif /* HAVE_APPARMOR */ +} + +dbus_bool_t +bus_apparmor_enabled (void) +{ +#ifdef HAVE_APPARMOR + return apparmor_enabled; +#endif + return FALSE; +} diff --git a/bus/apparmor.h b/bus/apparmor.h index 0d6f274..bf8f94f 100644 --- a/bus/apparmor.h +++ b/bus/apparmor.h @@ -28,7 +28,12 @@ #include +void bus_apparmor_audit_init (void); +dbus_bool_t bus_apparmor_pre_init (void); dbus_bool_t bus_apparmor_set_mode_from_config (const char *mode, DBusError *error); +dbus_bool_t bus_apparmor_full_init (void); +void bus_apparmor_shutdown (void); +dbus_bool_t bus_apparmor_enabled (void); #endif /* BUS_APPARMOR_H */ diff --git a/bus/bus.c b/bus/bus.c index a514e31..9c26249 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -34,6 +34,7 @@ #include "config-parser.h" #include "signals.h" #include "selinux.h" +#include "apparmor.h" #include "dir-watch.h" #include #include @@ -909,6 +910,21 @@ bus_context_new (const DBusString *config_file, bus_context_log (context, DBUS_SYSTEM_LOG_FATAL, "SELinux enabled but D-Bus initialization failed; check system log\n"); } + if (!bus_apparmor_full_init ()) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "AppArmor enabled but full initialization failed; check system log\n"); + goto failed; + } + + if (bus_apparmor_enabled ()) + { + /* Only print AppArmor mediation message when syslog support is enabled */ + if (context->syslog) + bus_context_log (context, DBUS_SYSTEM_LOG_INFO, + "AppArmor D-Bus mediation is enabled\n"); + } + if (!process_config_postinit (context, parser, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); @@ -936,6 +952,9 @@ bus_context_new (const DBusString *config_file, /* FIXME - why not just put this in full_init() below? */ bus_selinux_audit_init (); #endif +#ifdef HAVE_APPARMOR + bus_apparmor_audit_init (); +#endif } dbus_server_free_data_slot (&server_data_slot); diff --git a/bus/main.c b/bus/main.c index e060baa..1575195 100644 --- a/bus/main.c +++ b/bus/main.c @@ -39,6 +39,7 @@ #include /* for write() and STDERR_FILENO */ #endif #include "selinux.h" +#include "apparmor.h" static BusContext *context; @@ -614,6 +615,12 @@ main (int argc, char **argv) exit (1); } + if (!bus_apparmor_pre_init ()) + { + _dbus_warn ("AppArmor pre-initialization failed\n"); + exit (1); + } + dbus_error_init (&error); context = bus_context_new (&config_file, flags, &print_addr_pipe, &print_pid_pipe, @@ -649,6 +656,7 @@ main (int argc, char **argv) bus_context_shutdown (context); bus_context_unref (context); bus_selinux_shutdown (); + bus_apparmor_shutdown (); return 0; } -- 1.9.1