From 27640ea209e7f30303ceb3cefc88303466392893 Mon Sep 17 00:00:00 2001 From: John Johansen Date: Wed, 12 Feb 2014 12:37:41 -0600 Subject: [PATCH 05/10] 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. Signed-off-by: John Johansen [tyhicks: Honor enforcement modes and detect AppArmor dbus rule support] Signed-off-by: Tyler Hicks --- bus/apparmor.c | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bus/apparmor.h | 5 +++ bus/bus.c | 19 ++++++++ bus/main.c | 8 ++++ 4 files changed, 167 insertions(+) diff --git a/bus/apparmor.c b/bus/apparmor.c index 728b050..757bc95 100644 --- a/bus/apparmor.c +++ b/bus/apparmor.c @@ -28,8 +28,30 @@ #ifdef HAVE_APPARMOR +#ifdef HAVE_ERRNO_H +#include +#endif /* HAVE_ERRNO_H */ + #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 +62,64 @@ 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 +aa_supports_dbus (void) +{ + char aa_dbus[PATH_MAX + 1]; + char *aa_securityfs; + int mask_file; + + if (aa_find_mountpoint (&aa_securityfs) != 0) + return FALSE; + + snprintf (aa_dbus, sizeof (aa_dbus), "%s/features/dbus/mask", aa_securityfs); + free (aa_securityfs); + + mask_file = open (aa_dbus, O_RDONLY | O_CLOEXEC); + if (mask_file == -1) + return FALSE; + + close (mask_file); + return TRUE; +} #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 () && aa_supports_dbus ()) ? TRUE : FALSE; +#endif + + return TRUE; +} + dbus_bool_t bus_apparmor_set_mode_from_config (const char *mode, DBusError *error) { @@ -77,3 +155,60 @@ bus_apparmor_set_mode_from_config (const char *mode, DBusError *error) return TRUE; #endif } + +/** + * Initialize user space + */ +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.rc1