From 438562ec4d2f0253355bfbbd677f7601b1bb8cc0 Mon Sep 17 00:00:00 2001 From: Tyler Hicks Date: Thu, 13 Feb 2014 13:17:23 -0600 Subject: [PATCH 10/10] Mediation of processes eavesdropping When an AppArmor confined process wants to eavesdrop on a bus, a check is performed to see if the action should be allowed. The check is based on the connection's label and the bus type. This patch adds a new hook, which was not previously included in the SELinux mediation, to mediate eavesdropping from bus_driver_handle_add_match(). A new function is added to bus/signals.c to see if a match rule is an eavesdropping rule since the rule flags field is private to signals.c. An example AppArmor rule that would allow a process to eavesdrop on the session bus would be: dbus eavesdrop bus=session, Signed-off-by: Tyler Hicks --- bus/apparmor.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ bus/apparmor.h | 5 ++++ bus/driver.c | 16 ++++++++++ bus/signals.c | 9 ++++++ bus/signals.h | 2 ++ 5 files changed, 125 insertions(+) diff --git a/bus/apparmor.c b/bus/apparmor.c index 8047ea7..83c97b2 100644 --- a/bus/apparmor.c +++ b/bus/apparmor.c @@ -828,3 +828,96 @@ bus_apparmor_allows_send (DBusConnection *sender, return TRUE; #endif /* HAVE_APPARMOR */ } +/** + * Check if Apparmor security controls allow the connection to eavesdrop on + * other connections. + * + * @param connection the connection attempting to eavesdrop. + * @returns whether to allow the eavesdropping + */ +dbus_bool_t +bus_apparmor_allows_eavesdropping (DBusConnection *connection, + const char *bustype, + DBusError *error) +{ +#ifdef HAVE_APPARMOR + BusAppArmorConfinement *con = NULL; + DBusString auxdata; + dbus_bool_t allow = FALSE, audit = TRUE; + dbus_bool_t string_alloced = FALSE; + unsigned long pid; + int res, serrno = 0; + char *qstr = NULL; + ssize_t qsize; + + if (!apparmor_enabled) + return TRUE; + + con = bus_connection_get_apparmor_confinement (connection); + + if (is_unconfined (con->context, con->mode)) + { + allow = TRUE; + audit = FALSE; + goto out; + } + + qsize = build_query (&qstr, con->context, bustype); + if (qsize == -1) + goto oom; + + res = aa_query_label (AA_DBUS_EAVESDROP, qstr, qsize, &allow, &audit); + free (qstr); + if (res == -1) + { + serrno = errno; + goto audit; + } + + /* Don't fail operations on profiles in complain mode */ + if (modestr_to_complain (con->mode)) + allow = TRUE; + + if (!audit) + goto out; + + audit: + if (!_dbus_string_init (&auxdata)) + goto oom; + string_alloced = TRUE; + + if (bustype && !_dbus_append_pair_str (&auxdata, "bus", bustype ? bustype : "unknown")) + goto oom; + + if (serrno && !_dbus_append_pair_str (&auxdata, "info", strerror (serrno))) + goto oom; + + if (!_dbus_append_pair_str (&auxdata, "mask", "eavesdrop")) + goto oom; + + if (connection && dbus_connection_get_unix_process_id (connection, &pid) && + !_dbus_append_pair_uint (&auxdata, "pid", pid)) + goto oom; + + if (con->context && !_dbus_append_pair_str (&auxdata, "profile", con->context)) + goto oom; + + log_message (allow, "eavesdrop", &auxdata); + + out: + if (con != NULL) + bus_apparmor_confinement_unref (con); + if (string_alloced) + _dbus_string_free (&auxdata); + + return allow; + + oom: + BUS_SET_OOM (error); + allow = FALSE; + goto out; + +#else + return TRUE; +#endif /* HAVE_APPARMOR */ +} diff --git a/bus/apparmor.h b/bus/apparmor.h index 0618afd..e846f7f 100644 --- a/bus/apparmor.h +++ b/bus/apparmor.h @@ -62,4 +62,9 @@ bus_apparmor_allows_send (DBusConnection *sender, const char *source, DBusError *error); +dbus_bool_t +bus_apparmor_allows_eavesdropping (DBusConnection *connection, + const char *bustype, + DBusError *error); + #endif /* BUS_APPARMOR_H */ diff --git a/bus/driver.c b/bus/driver.c index e95a79d..1d498db 100644 --- a/bus/driver.c +++ b/bus/driver.c @@ -24,6 +24,7 @@ #include #include "activation.h" +#include "apparmor.h" #include "connection.h" #include "driver.h" #include "dispatch.h" @@ -994,6 +995,7 @@ bus_driver_handle_add_match (DBusConnection *connection, const char *text; DBusString str; BusMatchmaker *matchmaker; + BusContext *context; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -1026,6 +1028,20 @@ bus_driver_handle_add_match (DBusConnection *connection, if (rule == NULL) goto failed; + context = bus_transaction_get_context (transaction); + if (bus_match_rule_get_client_is_eavesdropping (rule) && + !bus_apparmor_allows_eavesdropping (connection, + context ? bus_context_get_type (context) : NULL, + error)) + { + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Connection \"%s\" is not allowed to eavesdrop due to " + "AppArmor policy", + bus_connection_is_active (connection) ? + bus_connection_get_name (connection) : "(inactive)"); + goto failed; + } + matchmaker = bus_connection_get_matchmaker (connection); if (!bus_matchmaker_add_rule (matchmaker, rule)) diff --git a/bus/signals.c b/bus/signals.c index 4c500c6..0642de5 100644 --- a/bus/signals.c +++ b/bus/signals.c @@ -379,6 +379,15 @@ bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule, } dbus_bool_t +bus_match_rule_get_client_is_eavesdropping (BusMatchRule *rule) +{ + if (rule->flags & BUS_MATCH_CLIENT_IS_EAVESDROPPING) + return TRUE; + else + return FALSE; +} + +dbus_bool_t bus_match_rule_set_path (BusMatchRule *rule, const char *path, dbus_bool_t is_namespace) diff --git a/bus/signals.h b/bus/signals.h index a71d2e4..5db87fd 100644 --- a/bus/signals.h +++ b/bus/signals.h @@ -73,6 +73,8 @@ dbus_bool_t bus_match_rule_set_arg (BusMatchRule *rule, void bus_match_rule_set_client_is_eavesdropping (BusMatchRule *rule, dbus_bool_t is_eavesdropping); +dbus_bool_t bus_match_rule_get_client_is_eavesdropping (BusMatchRule *rule); + BusMatchRule* bus_match_rule_parse (DBusConnection *matches_go_to, const DBusString *rule_text, DBusError *error); -- 1.9.rc1