X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=bus%2Fselinux.c;h=c36c94ecf79017fb38d823ad03e7e2e185023892;hb=7d9239c9c78cb6d0b9c282376fcf3cda1de23209;hp=2b88a60d7148bd3afbdb722a3828d005984e1c6d;hpb=6be5b25a71ec6b4e7efb35f20fc1f5357be5cffb;p=platform%2Fupstream%2Fdbus.git diff --git a/bus/selinux.c b/bus/selinux.c index 2b88a60..c36c94e 100644 --- a/bus/selinux.c +++ b/bus/selinux.c @@ -1,5 +1,5 @@ -/* -*- mode: C; c-file-style: "gnu" -*- - * selinux.c SELinux security checks for D-BUS +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * selinux.c SELinux security checks for D-Bus * * Author: Matthew Rickard * @@ -17,19 +17,29 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * */ + +#include #include #include +#ifndef DBUS_WIN +#include +#endif #include "selinux.h" #include "services.h" #include "policy.h" #include "utils.h" #include "config-parser.h" -#ifdef HAVE_SELINUX +#ifdef HAVE_ERRNO_H #include +#endif +#ifdef HAVE_SELINUX +#include +#include +#include #include #include #include @@ -38,7 +48,13 @@ #include #include #include +#include +#include #endif /* HAVE_SELINUX */ +#ifdef HAVE_LIBAUDIT +#include +#include +#endif /* HAVE_LIBAUDIT */ #define BUS_SID_FROM_SELINUX(sid) ((BusSELinuxID*) (sid)) #define SELINUX_SID_FROM_BUS(sid) ((security_id_t) (sid)) @@ -100,12 +116,55 @@ static const struct avc_lock_callback lock_cb = * @param variable argument list */ #ifdef HAVE_SELINUX + +#ifdef HAVE_LIBAUDIT +static int audit_fd = -1; +#endif + +void +bus_selinux_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 void log_callback (const char *fmt, ...) { va_list ap; + va_start(ap, fmt); - vsyslog (LOG_INFO, fmt, ap); + +#ifdef HAVE_LIBAUDIT + if (audit_fd >= 0) + { + capng_get_caps_process(); + if (capng_have_capability(CAPNG_EFFECTIVE, CAP_AUDIT_WRITE)) + { + char buf[PATH_MAX*2]; + + /* FIXME: need to change this to show real user */ + vsnprintf(buf, sizeof(buf), fmt, ap); + audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL, + NULL, getuid()); + return; + } + } +#endif /* HAVE_LIBAUDIT */ + + vsyslog (LOG_USER | LOG_INFO, fmt, ap); va_end(ap); } @@ -131,7 +190,20 @@ static void log_audit_callback (void *data, security_class_t class, char *buf, size_t bufleft) { DBusString *audmsg = data; - _dbus_string_copy_to_buffer (audmsg, buf, bufleft); + + if (bufleft > (size_t) _dbus_string_get_length(audmsg)) + { + _dbus_string_copy_to_buffer_with_nul (audmsg, buf, bufleft); + } + else + { + DBusString s; + + _dbus_string_init_const(&s, "Buffer too small for audit message"); + + if (bufleft > (size_t) _dbus_string_get_length(&s)) + _dbus_string_copy_to_buffer_with_nul (&s, buf, bufleft); + } } /** @@ -243,7 +315,7 @@ bus_selinux_pre_init (void) } /** - * Initialize the user space access vector cache (AVC) for D-BUS and set up + * Initialize the user space access vector cache (AVC) for D-Bus and set up * logging callbacks. */ dbus_bool_t @@ -270,7 +342,6 @@ bus_selinux_full_init (void) } else { - openlog ("dbus", LOG_PERROR, LOG_USER); _dbus_verbose ("Access Vector Cache (AVC) started.\n"); } @@ -303,10 +374,8 @@ bus_selinux_full_init (void) freecon (bus_context); - return TRUE; -#else - return TRUE; #endif /* HAVE_SELINUX */ + return TRUE; } /** @@ -366,7 +435,7 @@ bus_selinux_check (BusSELinuxID *sender_sid, { if (!selinux_enabled) return TRUE; - + /* Make the security check. AVC checks enforcing mode here as well. */ if (avc_has_perm (SELINUX_SID_FROM_BUS (sender_sid), override_sid ? @@ -374,8 +443,18 @@ bus_selinux_check (BusSELinuxID *sender_sid, SELINUX_SID_FROM_BUS (bus_sid), target_class, requested, &aeref, auxdata) < 0) { - _dbus_verbose ("SELinux denying due to security policy.\n"); - return FALSE; + switch (errno) + { + case EACCES: + _dbus_verbose ("SELinux denying due to security policy.\n"); + return FALSE; + case EINVAL: + _dbus_verbose ("SELinux denying due to invalid security context.\n"); + return FALSE; + default: + _dbus_verbose ("SELinux denying due to: %s\n", _dbus_strerror (errno)); + return FALSE; + } } else return TRUE; @@ -472,6 +551,7 @@ bus_selinux_allows_send (DBusConnection *sender, unsigned long spid, tpid; DBusString auxdata; dbus_bool_t ret; + dbus_bool_t string_alloced; if (!selinux_enabled) return TRUE; @@ -481,8 +561,10 @@ bus_selinux_allows_send (DBusConnection *sender, if (!proposed_recipient || !dbus_connection_get_unix_process_id (proposed_recipient, &tpid)) tpid = 0; + string_alloced = FALSE; if (!_dbus_string_init (&auxdata)) goto oom; + string_alloced = TRUE; if (!_dbus_string_append (&auxdata, "msgtype=")) goto oom; @@ -558,7 +640,8 @@ bus_selinux_allows_send (DBusConnection *sender, return ret; oom: - _dbus_string_free (&auxdata); + if (string_alloced) + _dbus_string_free (&auxdata); BUS_SET_OOM (error); return FALSE; @@ -569,18 +652,36 @@ bus_selinux_allows_send (DBusConnection *sender, dbus_bool_t bus_selinux_append_context (DBusMessage *message, - BusSELinuxID *context) + BusSELinuxID *sid, + DBusError *error) { #ifdef HAVE_SELINUX - /* Note if you change how the context is marshalled (e.g. to ay), - * you also need to change driver.c for the appropriate return value. - */ - return dbus_message_append_args (message, - DBUS_TYPE_STRING, - SELINUX_SID_FROM_BUS (context), - DBUS_TYPE_INVALID); + char *context; + + if (avc_sid_to_context (SELINUX_SID_FROM_BUS (sid), &context) < 0) + { + if (errno == ENOMEM) + BUS_SET_OOM (error); + else + dbus_set_error (error, DBUS_ERROR_FAILED, + "Error getting context from SID: %s\n", + _dbus_strerror (errno)); + return FALSE; + } + if (!dbus_message_append_args (message, + DBUS_TYPE_ARRAY, + DBUS_TYPE_BYTE, + &context, + strlen (context), + DBUS_TYPE_INVALID)) + { + _DBUS_SET_OOM (error); + return FALSE; + } + freecon (context); + return TRUE; #else - return FALSE; + return TRUE; #endif } @@ -734,7 +835,11 @@ bus_selinux_id_table_insert (DBusHashTable *service_table, if (avc_context_to_sid ((char *) service_context, &sid) < 0) { if (errno == ENOMEM) - return FALSE; + { + dbus_free (key); + return FALSE; + } + _dbus_warn ("Error getting SID from context \"%s\": %s\n", (char *) service_context, _dbus_strerror (errno)); @@ -812,7 +917,7 @@ bus_selinux_id_table_lookup (DBusHashTable *service_table, } /** - * Get the SELinux policy root. This is used to find the D-BUS + * Get the SELinux policy root. This is used to find the D-Bus * specific config file within the policy. */ const char * @@ -831,8 +936,7 @@ bus_selinux_get_policy_root (void) void bus_selinux_id_table_print (DBusHashTable *service_table) { -#ifdef DBUS_ENABLE_VERBOSE_MODE -#ifdef HAVE_SELINUX +#if defined (DBUS_ENABLE_VERBOSE_MODE) && defined (HAVE_SELINUX) DBusHashIter iter; if (!selinux_enabled) @@ -848,19 +952,18 @@ bus_selinux_id_table_print (DBusHashTable *service_table) _dbus_verbose ("The context is %s\n", sid->ctx); _dbus_verbose ("The refcount is %d\n", sid->refcnt); } -#endif /* HAVE_SELINUX */ -#endif /* DBUS_ENABLE_VERBOSE_MODE */ +#endif /* DBUS_ENABLE_VERBOSE_MODE && HAVE_SELINUX */ } -#ifdef DBUS_ENABLE_VERBOSE_MODE -#ifdef HAVE_SELINUX /** * Print out some AVC statistics. */ +#ifdef HAVE_SELINUX static void bus_avc_print_stats (void) { +#ifdef DBUS_ENABLE_VERBOSE_MODE struct avc_cache_stats cstats; if (!selinux_enabled) @@ -878,10 +981,9 @@ bus_avc_print_stats (void) _dbus_verbose ("CAV hits: %d\n", cstats.cav_hits); _dbus_verbose ("CAV probes: %d\n", cstats.cav_probes); _dbus_verbose ("CAV misses: %d\n", cstats.cav_misses); +#endif /* DBUS_ENABLE_VERBOSE_MODE */ } #endif /* HAVE_SELINUX */ -#endif /* DBUS_ENABLE_VERBOSE_MODE */ - /** * Destroy the AVC before we terminate. @@ -893,14 +995,91 @@ bus_selinux_shutdown (void) if (!selinux_enabled) return; - sidput (bus_sid); - bus_sid = SECSID_WILD; - -#ifdef DBUS_ENABLE_VERBOSE_MODE - bus_avc_print_stats (); -#endif /* DBUS_ENABLE_VERBOSE_MODE */ + _dbus_verbose ("AVC shutdown\n"); + + if (bus_sid != SECSID_WILD) + { + sidput (bus_sid); + bus_sid = SECSID_WILD; - avc_destroy (); + bus_avc_print_stats (); + + avc_destroy (); +#ifdef HAVE_LIBAUDIT + audit_close (audit_fd); +#endif /* HAVE_LIBAUDIT */ + } #endif /* HAVE_SELINUX */ } +/* The !HAVE_LIBAUDIT case lives in dbus-sysdeps-util-unix.c */ +#ifdef HAVE_LIBAUDIT +/** + * Changes the user and group the bus is running as. + * + * @param user the user to become + * @param error return location for errors + * @returns #FALSE on failure + */ +dbus_bool_t +_dbus_change_to_daemon_user (const char *user, + DBusError *error) +{ + dbus_uid_t uid; + dbus_gid_t gid; + DBusString u; + + _dbus_string_init_const (&u, user); + + if (!_dbus_get_user_id_and_primary_group (&u, &uid, &gid)) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "User '%s' does not appear to exist?", + user); + return FALSE; + } + + /* If we were root */ + if (_dbus_geteuid () == 0) + { + int rc; + + capng_clear (CAPNG_SELECT_BOTH); + capng_update (CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, + CAP_AUDIT_WRITE); + rc = capng_change_id (uid, gid, CAPNG_DROP_SUPP_GRP); + if (rc) + { + switch (rc) { + default: + dbus_set_error (error, DBUS_ERROR_FAILED, + "Failed to drop capabilities: %s\n", + _dbus_strerror (errno)); + break; + case -4: + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to set GID to %lu: %s", gid, + _dbus_strerror (errno)); + break; + case -5: + _dbus_warn ("Failed to drop supplementary groups: %s\n", + _dbus_strerror (errno)); + break; + case -6: + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to set UID to %lu: %s", uid, + _dbus_strerror (errno)); + break; + case -7: + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to unset keep-capabilities: %s\n", + _dbus_strerror (errno)); + break; + } + return FALSE; + } + } + + return TRUE; +} +#endif