debian/0000775000000000000000000000000013017644210007166 5ustar debian/control0000664000000000000000000001373512265023057010606 0ustar Source: dbus Section: admin Priority: optional Maintainer: Ubuntu Developers XSBC-Original-Maintainer: Utopia Maintenance Team Uploaders: Sjoerd Simons , Sebastian Dröge , Michael Biebl , Loic Minier , Simon McVittie # The following packages can be omitted for bootstrapping, but provide extra # features: # libsystemd-daemon-dev (circular dependency) # libsystemd-login-dev (circular dependency) # The following packages can be omitted for bootstrapping, but improve test # coverage: # libdbus-glib-1-dev (circular dependency) # libglib2.0-dev # python # python-dbus (circular dependency) # python-gobject Build-Depends: automake (>= 1:1.10), autotools-dev, debhelper (>= 9), dh-autoreconf, doxygen, dpkg-dev (>= 1.16.1), libexpat-dev, libdbus-glib-1-dev, libglib2.0-dev (>= 2.31.4), libselinux1-dev [linux-any], libapparmor-dev (>= 2.8.0-0ubuntu38) [linux-any], libsystemd-daemon-dev (>= 32) [linux-any], libsystemd-login-dev (>= 32) [linux-any], libx11-dev, # python (>= 2.6), # python-dbus, # python-gobject, xmlto, xsltproc Standards-Version: 3.9.3 Vcs-Git: git://anonscm.debian.org/pkg-utopia/dbus.git Vcs-Browser: http://anonscm.debian.org/gitweb/?p=pkg-utopia/dbus.git Homepage: http://dbus.freedesktop.org/ Package: dbus Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, lsb-base (>= 3.2-14), upstart (>= 0.6.3-6), netbase (>= 4.45ubuntu3) Recommends: libpam-systemd Breaks: unity-services (<< 6.0.0-0ubuntu6) Suggests: dbus-x11 Multi-Arch: foreign Description: simple interprocess messaging system (daemon and utilities) D-Bus is a message bus, used for sending messages between applications. Conceptually, it fits somewhere in between raw sockets and CORBA in terms of complexity. . D-Bus supports broadcast messages, asynchronous messages (thus decreasing latency), authentication, and more. It is designed to be low-overhead; messages are sent using a binary protocol, not using XML. D-Bus also supports a method call mapping for its messages, but it is not required; this makes using the system quite simple. . It comes with several bindings, including GLib, Python, Qt and Java. . This package contains the D-Bus daemon and related utilities. . The client-side library can be found in the libdbus-1-3 package, as it is no longer contained in this package. Package: dbus-x11 Architecture: any Section: x11 Depends: ${shlibs:Depends}, ${misc:Depends}, dbus Breaks: x11-common (<< 1:7.5+4) Multi-Arch: foreign Description: simple interprocess messaging system (X11 deps) D-Bus is a message bus, used for sending messages between applications. Conceptually, it fits somewhere in between raw sockets and CORBA in terms of complexity. . This package contains the dbus-launch utility which is necessary for packages using a D-Bus session bus. . See the dbus description for more information about D-Bus in general. Package: libdbus-1-3 Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} Depends: ${shlibs:Depends}, ${misc:Depends} Breaks: kdebase-workspace-bin (<< 4:4.4.5-9), kde-window-manager (<< 4:4.4.5-9) Recommends: dbus Section: libs Description: simple interprocess messaging system (library) D-Bus is a message bus, used for sending messages between applications. Conceptually, it fits somewhere in between raw sockets and CORBA in terms of complexity. . D-Bus supports broadcast messages, asynchronous messages (thus decreasing latency), authentication, and more. It is designed to be low-overhead; messages are sent using a binary protocol, not using XML. D-Bus also supports a method call mapping for its messages, but it is not required; this makes using the system quite simple. . It comes with several bindings, including GLib, Python, Qt and Java. . The daemon can be found in the dbus package. Package: dbus-1-doc Section: doc Architecture: all Depends: ${misc:Depends} Suggests: libdbus-1-dev Description: simple interprocess messaging system (documentation) D-Bus is a message bus, used for sending messages between applications. Conceptually, it fits somewhere in between raw sockets and CORBA in terms of complexity. . This package contains the API documentation for D-Bus, as well as the protocol specification. . See the dbus description for more information about D-Bus in general. Package: libdbus-1-dev Section: libdevel Architecture: any Multi-Arch: same Pre-Depends: ${misc:Pre-Depends} Depends: libdbus-1-3 (= ${binary:Version}), ${misc:Depends}, ${shlibs:Depends}, pkg-config Description: simple interprocess messaging system (development headers) D-Bus is a message bus, used for sending messages between applications. Conceptually, it fits somewhere in between raw sockets and CORBA in terms of complexity. . See the dbus description for more information about D-Bus in general. Package: dbus-1-dbg Section: debug Priority: extra Architecture: any Pre-Depends: ${misc:Pre-Depends} Depends: libdbus-1-3 (= ${binary:Version}), dbus (= ${binary:Version}), dbus-x11 (= ${binary:Version}), ${shlibs:Depends}, ${misc:Depends} Description: simple interprocess messaging system (debug symbols) D-Bus is a message bus, used for sending messages between applications. Conceptually, it fits somewhere in between raw sockets and CORBA in terms of complexity. . This package provides support for debugging programs that use the core D-Bus shared library. . See the dbus package description for more information about D-Bus in general. debian/gbp.conf0000664000000000000000000000014312240207265010605 0ustar [DEFAULT] pristine-tar = True debian-branch = experimental upstream-branch = upstream-experimental debian/dbus-1-doc.doc-base.specification0000664000000000000000000000030112240207265015236 0ustar Document: dbus-specification Title: D-Bus Specification Section: Programming Format: HTML Index: /usr/share/doc/dbus/dbus-specification.html Files: /usr/share/doc/dbus/dbus-specification.html debian/dbus.install0000664000000000000000000000146612240207265011524 0ustar debian/tmp/etc/dbus-1/ debian/tmp/bin/dbus-daemon debian/tmp/bin/dbus-cleanup-sockets debian/tmp/bin/dbus-send usr/bin debian/tmp/bin/dbus-uuidgen debian/tmp/bin/dbus-monitor usr/bin debian/tmp/usr/lib/dbus-1.0/dbus-daemon-launch-helper debian/tmp/usr/share/man/man1/dbus-daemon.1 debian/tmp/usr/share/man/man1/dbus-cleanup-sockets.1 debian/tmp/usr/share/dbus-1/services debian/tmp/usr/share/dbus-1/system-services debian/tmp/usr/share/man/man1/dbus-send.1 debian/tmp/usr/share/man/man1/dbus-uuidgen.1 debian/tmp/usr/share/man/man1/dbus-monitor.1 debian/tmp/lib/systemd/system/dbus.service debian/tmp/lib/systemd/system/dbus.socket debian/tmp/lib/systemd/system/dbus.target.wants/dbus.socket debian/tmp/lib/systemd/system/multi-user.target.wants/dbus.service debian/tmp/lib/systemd/system/sockets.target.wants/dbus.socket debian/patches/0000775000000000000000000000000013017644114010620 5ustar debian/patches/0004-upstart-add-UpstartJob-to-service-desktop-files.patch0000664000000000000000000000616312240207265023377 0ustar From 186818fa7a3af63178f68778555c87321505fd34 Mon Sep 17 00:00:00 2001 From: Scott James Remnant Date: Tue, 21 Dec 2010 16:00:42 +0000 Subject: [PATCH 4/5] upstart: add UpstartJob= to service desktop files Add a field to service desktop files to specify that there is an equivalent Upstart job for this service; unlike the systemd stuff, this doesn't need to name that job so it's just a flag. --- bus/activation.c | 20 ++++++++++++++++++++ bus/desktop-file.h | 1 + 2 files changed, 21 insertions(+), 0 deletions(-) Index: dbus-1.4.16/bus/activation.c =================================================================== --- dbus-1.4.16.orig/bus/activation.c 2011-10-18 18:10:55.214134484 +0200 +++ dbus-1.4.16/bus/activation.c 2011-10-18 18:11:06.414135027 +0200 @@ -74,6 +74,7 @@ unsigned long mtime; BusServiceDirectory *s_dir; char *filename; + unsigned int upstart_job : 1; } BusActivationEntry; typedef struct BusPendingActivationEntry BusPendingActivationEntry; @@ -98,6 +99,7 @@ DBusBabysitter *babysitter; DBusTimeout *timeout; unsigned int timeout_added : 1; + unsigned int upstart_job : 1; } BusPendingActivation; #if 0 @@ -260,6 +262,8 @@ DBusError *error) { char *name, *exec, *user, *exec_tmp, *systemd_service; + const char *upstart_job_raw; + int upstart_job; BusActivationEntry *entry; DBusStat stat_buf; DBusString file_path; @@ -275,6 +279,8 @@ exec_tmp = NULL; entry = NULL; systemd_service = NULL; + upstart_job_raw = NULL; + upstart_job = FALSE; dbus_error_init (&tmp_error); @@ -361,6 +367,16 @@ } } + /* upstart job is never required */ + if (bus_desktop_file_get_raw (desktop_file, + DBUS_SERVICE_SECTION, + DBUS_SERVICE_UPSTART_JOB, + &upstart_job_raw)) + { + if (strchr ("YyTt", upstart_job_raw[0])) + upstart_job = TRUE; + } + _DBUS_ASSERT_ERROR_IS_CLEAR (&tmp_error); entry = _dbus_hash_table_lookup_string (s_dir->entries, @@ -389,6 +405,7 @@ entry->exec = exec; entry->user = user; entry->systemd_service = systemd_service; + entry->upstart_job = upstart_job; entry->refcount = 1; /* ownership has been transferred to entry, do not free separately */ @@ -1847,6 +1864,8 @@ } } + pending_activation->upstart_job = entry->upstart_job; + pending_activation->timeout = _dbus_timeout_new (bus_context_get_activation_timeout (activation->context), pending_activation_timed_out, Index: dbus-1.4.16/bus/desktop-file.h =================================================================== --- dbus-1.4.16.orig/bus/desktop-file.h 2011-09-14 17:58:18.000000000 +0200 +++ dbus-1.4.16/bus/desktop-file.h 2011-10-18 18:11:06.414135027 +0200 @@ -36,6 +36,7 @@ #define DBUS_SERVICE_USER "User" #define DBUS_SERVICE_GROUP "Group" #define DBUS_SERVICE_SYSTEMD_SERVICE "SystemdService" +#define DBUS_SERVICE_UPSTART_JOB "UpstartJob" typedef struct BusDesktopFile BusDesktopFile; debian/patches/81-session.conf-timeout.patch0000664000000000000000000000135112240207265016161 0ustar # Description: Raise the service startup timeout from 25 to 60 seconds. It may be too short on the live CD with slow machines. # UbuntuSpecific: Debian and upstream are not concerned about live CDs --- dbus-1.2.14.orig/bus/session.conf.in 2006-11-19 23:58:47.378368108 +0100 +++ dbus-1.2.14/bus/session.conf.in 2006-11-19 23:59:13.123835260 +0100 @@ -25,6 +25,10 @@ + + 60000 + session.d debian/patches/CVE-2014-3636.patch0000664000000000000000000000653312406315453013252 0ustar Description: fix denial of service via large number of fds Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=346da99f7620e6901e7c7babd4590fcc5aac32bf Bug: https://bugs.freedesktop.org/show_bug.cgi?id=82820 Index: dbus-1.6.18/bus/config-parser.c =================================================================== --- dbus-1.6.18.orig/bus/config-parser.c 2014-09-17 10:13:48.706199807 -0400 +++ dbus-1.6.18/bus/config-parser.c 2014-09-17 10:14:04.102199894 -0400 @@ -414,9 +414,9 @@ maximum number of file descriptors we can receive. Picking a high value here thus translates directly to more memory allocation. */ - parser->limits.max_incoming_unix_fds = 1024*4; - parser->limits.max_outgoing_unix_fds = 1024*4; - parser->limits.max_message_unix_fds = 1024; + parser->limits.max_incoming_unix_fds = DBUS_DEFAULT_MESSAGE_UNIX_FDS*4; + parser->limits.max_outgoing_unix_fds = DBUS_DEFAULT_MESSAGE_UNIX_FDS*4; + parser->limits.max_message_unix_fds = DBUS_DEFAULT_MESSAGE_UNIX_FDS; /* Making this long means the user has to wait longer for an error * message if something screws up, but making it too short means Index: dbus-1.6.18/bus/session.conf.in =================================================================== --- dbus-1.6.18.orig/bus/session.conf.in 2014-09-17 10:13:48.650199807 -0400 +++ dbus-1.6.18/bus/session.conf.in 2014-09-17 10:14:04.102199894 -0400 @@ -53,7 +53,8 @@ 1000000000 250000000 1000000000 - 4096 + 120000 240000 100000 Index: dbus-1.6.18/dbus/dbus-message.c =================================================================== --- dbus-1.6.18.orig/dbus/dbus-message.c 2014-09-17 10:13:48.830199808 -0400 +++ dbus-1.6.18/dbus/dbus-message.c 2014-09-17 10:14:04.102199894 -0400 @@ -35,6 +35,7 @@ #include "dbus-list.h" #include "dbus-threads-internal.h" #ifdef HAVE_UNIX_FD_PASSING +#include "dbus-sysdeps.h" #include "dbus-sysdeps-unix.h" #endif @@ -3802,7 +3803,7 @@ SCM_RIGHTS works we need to preallocate an fd array of the maximum number of unix fds we want to receive in advance. A try-and-reallocate loop is not possible. */ - loader->max_message_unix_fds = 1024; + loader->max_message_unix_fds = DBUS_DEFAULT_MESSAGE_UNIX_FDS; if (!_dbus_string_init (&loader->data)) { Index: dbus-1.6.18/dbus/dbus-sysdeps.h =================================================================== --- dbus-1.6.18.orig/dbus/dbus-sysdeps.h 2014-09-17 10:13:48.802199808 -0400 +++ dbus-1.6.18/dbus/dbus-sysdeps.h 2014-09-17 10:14:04.102199894 -0400 @@ -537,6 +537,14 @@ const char * _dbus_replace_install_prefix (const char *configure_time_path); +/* Do not set this too high: it is a denial-of-service risk. + * See + * + * (This needs to be in the non-Unix-specific header so that + * the config-parser can use it.) + */ +#define DBUS_DEFAULT_MESSAGE_UNIX_FDS 16 + /** @} */ DBUS_END_DECLS debian/patches/aa-mediate-eavesdropping.patch0000664000000000000000000001440712254441351016502 0ustar Description: Deny eavesdropping privileges to confined applications Hook into the AddMatch backend to mediate eavesdropping. . Confined applications can be granted permission to eavesdrop using AppArmor's eavesdrop permission. See the D-Bus rules section of the apparmor.d(5) man page for more information. Author: Tyler Hicks Bug-Ubuntu: https://launchpad.net/bugs/1229280 Bug-Ubuntu: https://launchpad.net/bugs/1262440 Index: dbus-1.6.18/bus/apparmor.c =================================================================== --- dbus-1.6.18.orig/bus/apparmor.c 2013-11-22 10:52:01.808672166 -0800 +++ dbus-1.6.18/bus/apparmor.c 2013-11-22 10:54:07.484671555 -0800 @@ -849,3 +849,97 @@ bus_apparmor_allows_send (DBusConnection #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 */ +} + Index: dbus-1.6.18/bus/apparmor.h =================================================================== --- dbus-1.6.18.orig/bus/apparmor.h 2013-11-22 10:52:01.808672166 -0800 +++ dbus-1.6.18/bus/apparmor.h 2013-11-22 10:54:07.484671555 -0800 @@ -61,5 +61,10 @@ bus_apparmor_allows_send (DBusConnection const char *source, DBusError *error); +dbus_bool_t +bus_apparmor_allows_eavesdropping (DBusConnection *connection, + const char *bustype, + DBusError *error); + #endif /* BUS_APPARMOR_H */ Index: dbus-1.6.18/bus/signals.c =================================================================== --- dbus-1.6.18.orig/bus/signals.c 2013-11-22 10:52:01.808672166 -0800 +++ dbus-1.6.18/bus/signals.c 2013-11-22 10:55:19.232671206 -0800 @@ -379,6 +379,15 @@ bus_match_rule_set_client_is_eavesdroppi } 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) Index: dbus-1.6.18/bus/driver.c =================================================================== --- dbus-1.6.18.orig/bus/driver.c 2013-11-22 10:53:41.000000000 -0800 +++ dbus-1.6.18/bus/driver.c 2013-11-22 10:54:07.484671555 -0800 @@ -957,6 +957,7 @@ bus_driver_handle_add_match (DBusConnect const char *text; DBusString str; BusMatchmaker *matchmaker; + BusContext *context; _DBUS_ASSERT_ERROR_IS_CLEAR (error); @@ -989,6 +990,20 @@ bus_driver_handle_add_match (DBusConnect 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)) Index: dbus-1.6.18/bus/signals.h =================================================================== --- dbus-1.6.18.orig/bus/signals.h 2013-11-22 10:53:41.000000000 -0800 +++ dbus-1.6.18/bus/signals.h 2013-11-22 10:54:07.484671555 -0800 @@ -73,6 +73,8 @@ dbus_bool_t bus_match_rule_set_arg 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); debian/patches/00git_sd_daemon_update.patch0000664000000000000000000000305212240207265016136 0ustar From 751f6783c4e185b05765e7217c782dcb6f0df3e9 Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Thu, 21 Mar 2013 08:37:48 +0000 Subject: Update sd-daemon.[hc] from upstream This fixes sd_booted() to actually mean "have systemd init", which we need for _dbus_init_system_log() to decide whether systemd journal is being used. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=62585 Reviewed-by: Simon McVittie --- Index: dbus-1.6.8/dbus/sd-daemon.c =================================================================== --- dbus-1.6.8.orig/dbus/sd-daemon.c 2013-04-29 11:41:37.876051474 -0700 +++ dbus-1.6.8/dbus/sd-daemon.c 2013-04-29 11:41:37.872051473 -0700 @@ -25,7 +25,7 @@ ***/ #ifndef _GNU_SOURCE -#define _GNU_SOURCE +# define _GNU_SOURCE #endif #include @@ -418,18 +418,15 @@ #if defined(DISABLE_SYSTEMD) || !defined(__linux__) return 0; #else + struct stat st; - struct stat a, b; + /* We test whether the runtime unit file directory has been + * created. This takes place in mount-setup.c, so is + * guaranteed to happen very early during boot. */ - /* We simply test whether the systemd cgroup hierarchy is - * mounted */ - - if (lstat("/sys/fs/cgroup", &a) < 0) - return 0; - - if (lstat("/sys/fs/cgroup/systemd", &b) < 0) + if (lstat("/run/systemd/system/", &st) < 0) return 0; - return a.st_dev != b.st_dev; + return !!S_ISDIR(st.st_mode); #endif } debian/patches/00git_logind_check.patch0000664000000000000000000000236612240207265015263 0ustar From e25938d52731e1dc59b4aeaaec186578f8cd16af Mon Sep 17 00:00:00 2001 From: Martin Pitt Date: Thu, 21 Mar 2013 08:24:21 +0000 Subject: Fix test for logind availability sd_booted() is not an appropriate check for whether we should talk to logind, test for /run/systemd/seats/ instead. For details, see: Bug: https://bugs.freedesktop.org/show_bug.cgi?id=62585 [trivial whitespace fix -smcv] Reviewed-by: Simon McVittie --- diff --git a/dbus/dbus-userdb-util.c b/dbus/dbus-userdb-util.c index 16bf229..5af0092 100644 --- a/dbus/dbus-userdb-util.c +++ b/dbus/dbus-userdb-util.c @@ -21,6 +21,7 @@ * */ #include +#include #define DBUS_USERDB_INCLUDES_PRIVATE 1 #include "dbus-userdb.h" #include "dbus-test.h" @@ -29,7 +30,6 @@ #include #if HAVE_SYSTEMD -#include #include #endif @@ -55,7 +55,8 @@ _dbus_is_console_user (dbus_uid_t uid, dbus_bool_t result = FALSE; #ifdef HAVE_SYSTEMD - if (sd_booted () > 0) + /* check if we have logind */ + if (access ("/run/systemd/seats/", F_OK) >= 0) { int r; -- cgit v0.9.0.2-2-gbebe debian/patches/CVE-2014-7824.patch0000664000000000000000000003112112435155036013245 0ustar From 68cb9ead957314b30e604018f2dd5b0fc3b2127c Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Tue, 4 Nov 2014 14:41:54 +0000 Subject: CVE-2014-7824: set fd rlimit to 64k for the system dbus-daemon This ensures that our rlimit is actually high enough to avoid the denial of service described in CVE-2014-3636 part A. CVE-2014-7824 has been allocated for this incomplete fix. Restore the original rlimit for activated services, to avoid them getting undesired higher limits. (Thanks to Alban Crequy for various adjustments which have been included in this commit.) Bug: https://bugs.freedesktop.org/show_bug.cgi?id=85105 Reviewed-by: Alban Crequy Conflicts: dbus/dbus-sysdeps-util-unix.c Index: dbus-1.6.18/bus/activation.c =================================================================== --- dbus-1.6.18.orig/bus/activation.c 2014-11-25 14:35:56.231133315 -0500 +++ dbus-1.6.18/bus/activation.c 2014-11-25 14:35:56.223133258 -0500 @@ -1683,6 +1683,31 @@ return retval; } +static void +child_setup (void *user_data) +{ +#ifdef DBUS_UNIX + BusActivation *activation = user_data; + DBusRLimit *initial_fd_limit; + DBusError error; + + dbus_error_init (&error); + initial_fd_limit = bus_context_get_initial_fd_limit (activation->context); + + if (initial_fd_limit != NULL && + !_dbus_rlimit_restore_fd_limit (initial_fd_limit, &error)) + { + /* unfortunately we don't actually know the service name here */ + bus_context_log (activation->context, + DBUS_SYSTEM_LOG_INFO, + "Failed to reset fd limit before activating " + "service: %s: %s", + error.name, error.message); + } +#endif +} + + dbus_bool_t bus_activation_activate_service (BusActivation *activation, DBusConnection *connection, @@ -2114,7 +2139,8 @@ if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv, envp, - NULL, activation, + child_setup, + activation, &tmp_error)) { _dbus_verbose ("Failed to spawn child\n"); Index: dbus-1.6.18/bus/bus.c =================================================================== --- dbus-1.6.18.orig/bus/bus.c 2014-11-25 14:35:56.231133315 -0500 +++ dbus-1.6.18/bus/bus.c 2014-11-25 14:35:56.223133258 -0500 @@ -65,6 +65,7 @@ BusPolicy *policy; BusMatchmaker *matchmaker; BusLimits limits; + DBusRLimit *initial_fd_limit; unsigned int fork : 1; unsigned int syslog : 1; unsigned int keep_umask : 1; @@ -648,19 +649,38 @@ static void raise_file_descriptor_limit (BusContext *context) { +#ifdef DBUS_UNIX + DBusError error = DBUS_ERROR_INIT; - /* I just picked this out of thin air; we need some extra - * descriptors for things like any internal pipes we create, - * inotify, connections to SELinux, etc. - */ - unsigned int arbitrary_extra_fds = 32; - unsigned int limit; + /* we only do this once */ + if (context->initial_fd_limit != NULL) + return; - limit = context->limits.max_completed_connections + - context->limits.max_incomplete_connections - + arbitrary_extra_fds; + context->initial_fd_limit = _dbus_rlimit_save_fd_limit (&error); - _dbus_request_file_descriptor_limit (limit); + if (context->initial_fd_limit == NULL) + { + bus_context_log (context, DBUS_SYSTEM_LOG_INFO, + "%s: %s", error.name, error.message); + dbus_error_free (&error); + return; + } + + /* We used to compute a suitable rlimit based on the configured number + * of connections, but that breaks down as soon as we allow fd-passing, + * because each connection is allowed to pass 64 fds to us, and if + * they all did, we'd hit kernel limits. We now hard-code 64k as a + * good limit, like systemd does: that's enough to avoid DoS from + * anything short of multiple uids conspiring against us. + */ + if (!_dbus_rlimit_raise_fd_limit_if_privileged (65536, &error)) + { + bus_context_log (context, DBUS_SYSTEM_LOG_INFO, + "%s: %s", error.name, error.message); + dbus_error_free (&error); + return; + } +#endif } static dbus_bool_t @@ -1137,6 +1157,10 @@ dbus_free (context->pidfile); } + + if (context->initial_fd_limit) + _dbus_rlimit_free (context->initial_fd_limit); + dbus_free (context); dbus_server_free_data_slot (&server_data_slot); @@ -1301,6 +1325,12 @@ return context->limits.reply_timeout; } +DBusRLimit * +bus_context_get_initial_fd_limit (BusContext *context) +{ + return context->initial_fd_limit; +} + void bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char *msg, ...) _DBUS_GNUC_PRINTF (3, 4); Index: dbus-1.6.18/bus/bus.h =================================================================== --- dbus-1.6.18.orig/bus/bus.h 2014-11-25 14:35:56.231133315 -0500 +++ dbus-1.6.18/bus/bus.h 2014-11-25 14:35:56.223133258 -0500 @@ -117,6 +117,7 @@ int bus_context_get_max_match_rules_per_connection (BusContext *context); int bus_context_get_max_replies_per_connection (BusContext *context); int bus_context_get_reply_timeout (BusContext *context); +DBusRLimit * bus_context_get_initial_fd_limit (BusContext *context); void bus_context_log (BusContext *context, DBusSystemLogSeverity severity, const char *msg, Index: dbus-1.6.18/dbus/dbus-sysdeps-util-unix.c =================================================================== --- dbus-1.6.18.orig/dbus/dbus-sysdeps-util-unix.c 2014-11-25 14:35:56.231133315 -0500 +++ dbus-1.6.18/dbus/dbus-sysdeps-util-unix.c 2014-11-25 14:35:56.223133258 -0500 @@ -373,53 +373,140 @@ } #endif /* !HAVE_LIBAUDIT */ +#ifdef HAVE_SETRLIMIT -/** - * Attempt to ensure that the current process can open - * at least @limit file descriptors. - * - * If @limit is lower than the current, it will not be - * lowered. No error is returned if the request can - * not be satisfied. - * - * @limit Number of file descriptors +/* We assume that if we have setrlimit, we also have getrlimit and + * struct rlimit. */ -void -_dbus_request_file_descriptor_limit (unsigned int limit) + +struct DBusRLimit { + struct rlimit lim; +}; + +DBusRLimit * +_dbus_rlimit_save_fd_limit (DBusError *error) +{ + DBusRLimit *self; + + self = dbus_new0 (DBusRLimit, 1); + + if (self == NULL) + { + _DBUS_SET_OOM (error); + return NULL; + } + + if (getrlimit (RLIMIT_NOFILE, &self->lim) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to get fd limit: %s", _dbus_strerror (errno)); + dbus_free (self); + return NULL; + } + + return self; +} + +dbus_bool_t +_dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired, + DBusError *error) { -#ifdef HAVE_SETRLIMIT struct rlimit lim; - struct rlimit target_lim; /* No point to doing this practically speaking * if we're not uid 0. We expect the system * bus to use this before we change UID, and - * the session bus takes the Linux default - * of 1024 for both cur and max. + * the session bus takes the Linux default, + * currently 1024 for cur and 4096 for max. */ if (getuid () != 0) - return; + { + /* not an error, we're probably the session bus */ + return TRUE; + } if (getrlimit (RLIMIT_NOFILE, &lim) < 0) - return; - - if (lim.rlim_cur >= limit) - return; + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to get fd limit: %s", _dbus_strerror (errno)); + return FALSE; + } + + if (lim.rlim_cur == RLIM_INFINITY || lim.rlim_cur >= desired) + { + /* not an error, everything is fine */ + return TRUE; + } /* Ignore "maximum limit", assume we have the "superuser" * privileges. On Linux this is CAP_SYS_RESOURCE. */ - target_lim.rlim_cur = target_lim.rlim_max = limit; - /* Also ignore errors; if we fail, we will at least work - * up to whatever limit we had, which seems better than - * just outright aborting. - * - * However, in the future we should probably log this so OS builders - * have a chance to notice any misconfiguration like dbus-daemon - * being started without CAP_SYS_RESOURCE. - */ - setrlimit (RLIMIT_NOFILE, &target_lim); + lim.rlim_cur = lim.rlim_max = desired; + + if (setrlimit (RLIMIT_NOFILE, &lim) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to set fd limit to %u: %s", + desired, _dbus_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +dbus_bool_t +_dbus_rlimit_restore_fd_limit (DBusRLimit *saved, + DBusError *error) +{ + if (setrlimit (RLIMIT_NOFILE, &saved->lim) < 0) + { + dbus_set_error (error, _dbus_error_from_errno (errno), + "Failed to restore old fd limit: %s", + _dbus_strerror (errno)); + return FALSE; + } + + return TRUE; +} + +#else /* !HAVE_SETRLIMIT */ + +static void +fd_limit_not_supported (DBusError *error) +{ + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "cannot change fd limit on this platform"); +} + +DBusRLimit * +_dbus_rlimit_save_fd_limit (DBusError *error) +{ + fd_limit_not_supported (error); + return NULL; +} + +dbus_bool_t +_dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired, + DBusError *error) +{ + fd_limit_not_supported (error); + return FALSE; +} + +dbus_bool_t +_dbus_rlimit_restore_fd_limit (DBusRLimit *saved, + DBusError *error) +{ + fd_limit_not_supported (error); + return FALSE; +} + #endif + +void +_dbus_rlimit_free (DBusRLimit *lim) +{ + dbus_free (lim); } void Index: dbus-1.6.18/dbus/dbus-sysdeps-util-win.c =================================================================== --- dbus-1.6.18.orig/dbus/dbus-sysdeps-util-win.c 2014-11-25 14:35:56.231133315 -0500 +++ dbus-1.6.18/dbus/dbus-sysdeps-util-win.c 2014-11-25 14:35:56.227133286 -0500 @@ -256,9 +256,42 @@ return TRUE; } +static void +fd_limit_not_supported (DBusError *error) +{ + dbus_set_error (error, DBUS_ERROR_NOT_SUPPORTED, + "cannot change fd limit on this platform"); +} + +DBusRLimit * +_dbus_rlimit_save_fd_limit (DBusError *error) +{ + fd_limit_not_supported (error); + return NULL; +} + +dbus_bool_t +_dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired, + DBusError *error) +{ + fd_limit_not_supported (error); + return FALSE; +} + +dbus_bool_t +_dbus_rlimit_restore_fd_limit (DBusRLimit *saved, + DBusError *error) +{ + fd_limit_not_supported (error); + return FALSE; +} + void -_dbus_request_file_descriptor_limit (unsigned int limit) +_dbus_rlimit_free (DBusRLimit *lim) { + /* _dbus_rlimit_save_fd_limit() cannot return non-NULL on Windows + * so there cannot be anything to free */ + _dbus_assert (lim == NULL); } void Index: dbus-1.6.18/dbus/dbus-sysdeps.h =================================================================== --- dbus-1.6.18.orig/dbus/dbus-sysdeps.h 2014-11-25 14:35:56.231133315 -0500 +++ dbus-1.6.18/dbus/dbus-sysdeps.h 2014-11-25 14:35:56.227133286 -0500 @@ -525,8 +525,6 @@ void _dbus_flush_caches (void); -void _dbus_request_file_descriptor_limit (unsigned int limit); - /* * replaces the term DBUS_PREFIX in configure_time_path by the * current dbus installation directory. On unix this function is a noop @@ -545,6 +543,15 @@ */ #define DBUS_DEFAULT_MESSAGE_UNIX_FDS 16 +typedef struct DBusRLimit DBusRLimit; + +DBusRLimit *_dbus_rlimit_save_fd_limit (DBusError *error); +dbus_bool_t _dbus_rlimit_raise_fd_limit_if_privileged (unsigned int desired, + DBusError *error); +dbus_bool_t _dbus_rlimit_restore_fd_limit (DBusRLimit *saved, + DBusError *error); +void _dbus_rlimit_free (DBusRLimit *lim); + /** @} */ DBUS_END_DECLS debian/patches/02_obsolete_g_thread_api.patch0000664000000000000000000001517412240207265016453 0ustar From: Martin Pitt Date: Tue, 3 Jan 2012 10:57:30 +0100 Subject: [PATCH] Port to glib 2.31.x g_thread API g_thread_init() is deprecated since glib 2.24, call g_type_init() instead. g_thread_create is deprecated since 2.31, use g_thread_new() instead. Bump glib requirement accordingly. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=44413 Bug-Ubuntu: https://launchpad.net/bugs/911125 Index: dbus-1.4.16/test/internals/refs.c =================================================================== --- dbus-1.4.16.orig/test/internals/refs.c 2011-09-21 13:16:16.000000000 +0200 +++ dbus-1.4.16/test/internals/refs.c 2012-01-03 11:07:30.714947587 +0100 @@ -26,6 +26,7 @@ #include +#include #include #define DBUS_COMPILATION /* this test uses libdbus-internal */ @@ -277,10 +278,9 @@ for (i = 0; i < N_THREADS; i++) { if ((i % 2) == 0) - f->threads[i] = g_thread_create (ref_thread, &public_api, TRUE, NULL); + f->threads[i] = g_thread_new (NULL, ref_thread, &public_api); else - f->threads[i] = g_thread_create (ref_thread, &internal_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, ref_thread, &internal_api); g_assert (f->threads[i] != NULL); } @@ -290,11 +290,9 @@ for (i = 0; i < N_THREADS; i++) { if ((i % 2) == 0) - f->threads[i] = g_thread_create (cycle_thread, &public_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api); else - f->threads[i] = g_thread_create (cycle_thread, &internal_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, cycle_thread, &internal_api); g_assert (f->threads[i] != NULL); } @@ -304,11 +302,9 @@ for (i = 0; i < N_THREADS; i++) { if ((i % 2) == 0) - f->threads[i] = g_thread_create (unref_thread, &public_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, unref_thread, &public_api); else - f->threads[i] = g_thread_create (unref_thread, &internal_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, unref_thread, &internal_api); g_assert (f->threads[i] != NULL); } @@ -361,10 +357,9 @@ for (i = 0; i < N_THREADS; i++) { if ((i % 2) == 0) - f->threads[i] = g_thread_create (ref_thread, &public_api, TRUE, NULL); + f->threads[i] = g_thread_new (NULL, ref_thread, &public_api); else - f->threads[i] = g_thread_create (ref_thread, &internal_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, ref_thread, &internal_api); g_assert (f->threads[i] != NULL); } @@ -374,11 +369,9 @@ for (i = 0; i < N_THREADS; i++) { if ((i % 2) == 0) - f->threads[i] = g_thread_create (cycle_thread, &public_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api); else - f->threads[i] = g_thread_create (cycle_thread, &internal_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, cycle_thread, &internal_api); g_assert (f->threads[i] != NULL); } @@ -388,11 +381,9 @@ for (i = 0; i < N_THREADS; i++) { if ((i % 2) == 0) - f->threads[i] = g_thread_create (unref_thread, &public_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, unref_thread, &public_api); else - f->threads[i] = g_thread_create (unref_thread, &internal_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, unref_thread, &internal_api); g_assert (f->threads[i] != NULL); } @@ -427,7 +418,7 @@ for (i = 0; i < N_THREADS; i++) { - f->threads[i] = g_thread_create (ref_thread, &public_api, TRUE, NULL); + f->threads[i] = g_thread_new (NULL, ref_thread, &public_api); g_assert (f->threads[i] != NULL); } @@ -435,7 +426,7 @@ for (i = 0; i < N_THREADS; i++) { - f->threads[i] = g_thread_create (cycle_thread, &public_api, TRUE, NULL); + f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api); g_assert (f->threads[i] != NULL); } @@ -443,7 +434,7 @@ for (i = 0; i < N_THREADS; i++) { - f->threads[i] = g_thread_create (unref_thread, &public_api, TRUE, NULL); + f->threads[i] = g_thread_new (NULL, unref_thread, &public_api); g_assert (f->threads[i] != NULL); } @@ -501,10 +492,9 @@ for (i = 0; i < N_THREADS; i++) { if ((i % 2) == 0) - f->threads[i] = g_thread_create (ref_thread, &public_api, TRUE, NULL); + f->threads[i] = g_thread_new (NULL, ref_thread, &public_api); else - f->threads[i] = g_thread_create (ref_thread, &internal_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, ref_thread, &internal_api); g_assert (f->threads[i] != NULL); } @@ -516,16 +506,14 @@ switch (i % 3) { case 0: - f->threads[i] = g_thread_create (cycle_thread, &public_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, cycle_thread, &public_api); break; case 1: - f->threads[i] = g_thread_create (cycle_thread, &internal_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, cycle_thread, &internal_api); break; default: - f->threads[i] = g_thread_create (cycle_thread, - &unref_and_unlock_api, TRUE, NULL); + f->threads[i] = g_thread_new (NULL, cycle_thread, + &unref_and_unlock_api); } g_assert (f->threads[i] != NULL); @@ -538,16 +526,14 @@ switch (i % 3) { case 0: - f->threads[i] = g_thread_create (unref_thread, &public_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, unref_thread, &public_api); break; case 1: - f->threads[i] = g_thread_create (unref_thread, &internal_api, TRUE, - NULL); + f->threads[i] = g_thread_new (NULL, unref_thread, &internal_api); break; default: - f->threads[i] = g_thread_create (unref_thread, - &unref_and_unlock_api, TRUE, NULL); + f->threads[i] = g_thread_new (NULL, unref_thread, + &unref_and_unlock_api); } g_assert (f->threads[i] != NULL); @@ -596,7 +582,7 @@ main (int argc, char **argv) { - g_thread_init (NULL); + g_type_init (); g_test_init (&argc, &argv, NULL); g_test_bug_base ("https://bugs.freedesktop.org/show_bug.cgi?id="); debian/patches/aa-build-tools.patch0000664000000000000000000001250012240207265014452 0ustar Description: Update build files to support building against libapparmor Author: John Johansen Author: Tyler Hicks Forwarded: no Index: dbus-1.6.12/bus/Makefile.am =================================================================== --- dbus-1.6.12.orig/bus/Makefile.am 2013-08-09 16:16:58.279926031 -0700 +++ dbus-1.6.12/bus/Makefile.am 2013-08-09 16:16:58.275926031 -0700 @@ -4,6 +4,7 @@ dbus_daemon_execdir = $(DBUS_DAEMONDIR) DBUS_BUS_LIBS = \ $(XML_LIBS) \ $(SELINUX_LIBS) \ + $(APPARMOR_LIBS) \ $(THREAD_LIBS) \ $(ADT_LIBS) \ $(NETWORK_libs) \ Index: dbus-1.6.12/configure.ac =================================================================== --- dbus-1.6.12.orig/configure.ac 2013-08-09 16:16:58.279926031 -0700 +++ dbus-1.6.12/configure.ac 2013-08-09 16:16:58.279926031 -0700 @@ -149,6 +149,7 @@ AC_ARG_ENABLE(xml-docs, AS_HELP_STRING([ AC_ARG_ENABLE(doxygen-docs, AS_HELP_STRING([--enable-doxygen-docs],[build DOXYGEN documentation (requires Doxygen)]),enable_doxygen_docs=$enableval,enable_doxygen_docs=auto) AC_ARG_ENABLE(abstract-sockets, AS_HELP_STRING([--enable-abstract-sockets],[use abstract socket namespace (linux only)]),enable_abstract_sockets=$enableval,enable_abstract_sockets=auto) AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],[build with SELinux support]),enable_selinux=$enableval,enable_selinux=auto) +AC_ARG_ENABLE(apparmor, AS_HELP_STRING([--enable-apparmor],[build with AppArmor support]),enable_apparmor=$enableval,enable_apparmor=auto) AC_ARG_ENABLE(libaudit,AS_HELP_STRING([--enable-libaudit],[build audit daemon support for SELinux]),enable_libaudit=$enableval,enable_libaudit=auto) AC_ARG_ENABLE(dnotify, AS_HELP_STRING([--enable-dnotify],[build with dnotify support (linux only)]),enable_dnotify=$enableval,enable_dnotify=auto) AC_ARG_ENABLE(inotify, AS_HELP_STRING([--enable-inotify],[build with inotify support (linux only)]),enable_inotify=$enableval,enable_inotify=auto) @@ -1034,6 +1035,48 @@ else SELINUX_LIBS= fi +# AppArmor detection +if test x$enable_apparmor = xno ; then + have_apparmor=no; +else + # See if we have Apparmor library + AC_CHECK_LIB(apparmor, aa_is_enabled, + have_apparmor=yes, have_apparmor=no) + + # see if we have the Apparmor header with the new D-Bus stuff in it + if test x$have_apparmor = xyes ; then + AC_MSG_CHECKING([for DBUS apparmor permissions in sys/apparmor.h]) + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include ]], + [[#ifdef AA_CLASS_DBUS return 0; + #else + #error AA_CLASS_DBUS not defined + #endif]])], + [have_apparmor=yes], + [have_apparmor=no]) + AC_MSG_RESULT($have_apparmor) + fi + + if test x$enable_apparmor = xauto ; then + if test x$have_apparmor = xno ; then + AC_MSG_WARN([Sufficiently new Apparmor library not found]) + fi + else + if test x$have_apparmor = xno ; then + AC_MSG_ERROR([Apparmor explicitly required, and Apparmor library not found]) + fi + fi +fi + +AM_CONDITIONAL(HAVE_APPARMOR, test x$have_apparmor = xyes) + +if test x$have_apparmor = xyes ; then + APPARMOR_LIBS="-lapparmor" + AC_DEFINE(HAVE_APPARMOR,1,[Apparmor support]) +else + APPARMOR_LIBS= +fi +AC_SUBST([APPARMOR_LIBS]) + # inotify checks if test x$enable_inotify = xno ; then have_inotify=no; @@ -1781,6 +1824,7 @@ echo " Building checks: ${enable_checks} Building bus stats API: ${enable_stats} Building SELinux support: ${have_selinux} + Building AppArmor support: ${have_apparmor} Building inotify support: ${have_inotify} Building dnotify support: ${have_dnotify} Building kqueue support: ${have_kqueue} Index: dbus-1.6.12/cmake/CMakeLists.txt =================================================================== --- dbus-1.6.12.orig/cmake/CMakeLists.txt 2013-08-09 16:00:46.000000000 -0700 +++ dbus-1.6.12/cmake/CMakeLists.txt 2013-08-09 16:23:25.075935224 -0700 @@ -277,6 +277,9 @@ endif(NOT MSVC) #AC_ARG_ENABLE(selinux, AS_HELP_STRING([--enable-selinux],[build with SELinux support]),enable_selinux=$enableval,enable_selinux=auto) #selinux missing +#AC_ARG_ENABLE(apparmor, AS_HELP_STRING([--enable-apparmor],[build with AppArmor support]),enable_apparmor=$enableval,enable_apparmor=auto) +#apparmor missing + #AC_ARG_ENABLE(dnotify, AS_HELP_STRING([--enable-dnotify],[build with dnotify support (linux only)]),enable_dnotify=$enableval,enable_dnotify=auto) if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") option (DBUS_BUS_ENABLE_DNOTIFY_ON_LINUX "build with dnotify support (linux only)" ON) # add a check ! @@ -554,6 +557,7 @@ message(" Building w/o checks: message(" Building bus stats API: ${DBUS_ENABLE_STATS} ") message(" installing system libs: ${DBUS_INSTALL_SYSTEM_LIBS} ") #message(" Building SELinux support: ${have_selinux} ") +#message(" Building AppArmor support: ${have_apparmor} ") #message(" Building dnotify support: ${have_dnotify} ") message(" Building Doxygen docs: ${DBUS_ENABLE_DOXYGEN_DOCS} ") message(" Building XML docs: ${DBUS_ENABLE_XML_DOCS} ") debian/patches/CVE-2014-3639-regression.patch0000664000000000000000000000366612435155321015435 0ustar Description: fix authentication timeout on certain slower systems Bug: https://bugs.freedesktop.org/show_bug.cgi?id=86431 Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=39f4b36ba546818a7dc00bfdcde9b21bb8abcaac Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=d1ab5857287430766837c63643d143ba434160b2 Index: dbus-1.6.18/bus/config-parser.c =================================================================== --- dbus-1.6.18.orig/bus/config-parser.c 2014-11-25 14:36:01.407170417 -0500 +++ dbus-1.6.18/bus/config-parser.c 2014-11-25 14:36:23.575329426 -0500 @@ -428,7 +428,7 @@ * and legitimate auth will fail. If interactive auth (ask user for * password) is allowed, then potentially it has to be quite long. */ - parser->limits.auth_timeout = 5000; /* 5 seconds */ + parser->limits.auth_timeout = 30000; /* 30 seconds */ /* Do not allow a fd to stay forever in dbus-daemon * https://bugs.freedesktop.org/show_bug.cgi?id=80559 Index: dbus-1.6.18/bus/connection.c =================================================================== --- dbus-1.6.18.orig/bus/connection.c 2014-11-25 14:36:01.407170417 -0500 +++ dbus-1.6.18/bus/connection.c 2014-11-25 14:36:20.963310682 -0500 @@ -882,6 +882,14 @@ if (elapsed >= (double) auth_timeout) { + /* Unfortunately, we can't identify the connection: it doesn't + * have a unique name yet, we don't know its uid/pid yet, + * and so on. */ + bus_context_log (connections->context, DBUS_SYSTEM_LOG_INFO, + "Connection has not authenticated soon enough, closing it " + "(auth_timeout=%dms, elapsed: %.0fms)", + auth_timeout, elapsed); + _dbus_verbose ("Timing out authentication for connection %p\n", connection); dbus_connection_close (connection); } debian/patches/CVE-2014-3639.patch0000664000000000000000000002753512406316720013260 0ustar Description: fix denial of service via incomplete connections Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=a3477feb7aa8658602cceb8d29ae370a83002172 Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=89219baab0bf6ff05142518110f45c8159be8092 Bug: https://bugs.freedesktop.org/show_bug.cgi?id=80919 Index: dbus-1.6.18/bus/bus.c =================================================================== --- dbus-1.6.18.orig/bus/bus.c 2014-09-17 10:15:47.530200478 -0400 +++ dbus-1.6.18/bus/bus.c 2014-09-17 10:16:32.678200733 -0400 @@ -40,6 +40,7 @@ #include #include #include +#include #ifdef DBUS_CYGWIN #include @@ -69,6 +70,7 @@ unsigned int keep_umask : 1; unsigned int allow_anonymous : 1; unsigned int systemd_activation : 1; + dbus_bool_t watches_enabled; }; static dbus_int32_t server_data_slot = -1; @@ -747,6 +749,8 @@ goto failed; } + context->watches_enabled = TRUE; + context->registry = bus_registry_new (context); if (context->registry == NULL) { @@ -1698,3 +1702,36 @@ _dbus_verbose ("security policy allowing message\n"); return TRUE; } + +void +bus_context_check_all_watches (BusContext *context) +{ + DBusList *link; + dbus_bool_t enabled = TRUE; + + if (bus_connections_get_n_incomplete (context->connections) >= + bus_context_get_max_incomplete_connections (context)) + { + enabled = FALSE; + } + + if (context->watches_enabled == enabled) + return; + + context->watches_enabled = enabled; + + for (link = _dbus_list_get_first_link (&context->servers); + link != NULL; + link = _dbus_list_get_next_link (&context->servers, link)) + { + /* A BusContext might contains several DBusServer (if there are + * several configuration items) and a DBusServer might + * contain several DBusWatch in its DBusWatchList (if getaddrinfo + * returns several addresses on a dual IPv4-IPv6 stack or if + * systemd passes several fds). + * We want to enable/disable them all. + */ + DBusServer *server = link->data; + _dbus_server_toggle_all_watches (server, enabled); + } +} Index: dbus-1.6.18/bus/bus.h =================================================================== --- dbus-1.6.18.orig/bus/bus.h 2014-09-17 10:15:47.530200478 -0400 +++ dbus-1.6.18/bus/bus.h 2014-09-17 10:16:32.678200733 -0400 @@ -128,5 +128,6 @@ DBusConnection *proposed_recipient, DBusMessage *message, DBusError *error); +void bus_context_check_all_watches (BusContext *context); #endif /* BUS_BUS_H */ Index: dbus-1.6.18/bus/config-parser.c =================================================================== --- dbus-1.6.18.orig/bus/config-parser.c 2014-09-17 10:15:47.562200478 -0400 +++ dbus-1.6.18/bus/config-parser.c 2014-09-17 10:16:21.602200670 -0400 @@ -428,7 +428,7 @@ * and legitimate auth will fail. If interactive auth (ask user for * password) is allowed, then potentially it has to be quite long. */ - parser->limits.auth_timeout = 30000; /* 30 seconds */ + parser->limits.auth_timeout = 5000; /* 5 seconds */ /* Do not allow a fd to stay forever in dbus-daemon * https://bugs.freedesktop.org/show_bug.cgi?id=80559 Index: dbus-1.6.18/bus/connection.c =================================================================== --- dbus-1.6.18.orig/bus/connection.c 2014-09-17 10:15:47.534200478 -0400 +++ dbus-1.6.18/bus/connection.c 2014-09-17 10:16:32.678200733 -0400 @@ -307,6 +307,10 @@ _dbus_list_remove_link (&d->connections->incomplete, d->link_in_connection_list); d->link_in_connection_list = NULL; d->connections->n_incomplete -= 1; + + /* If we have dropped below the max. number of incomplete + * connections, start accept()ing again */ + bus_context_check_all_watches (d->connections->context); } _dbus_assert (d->connections->n_incomplete >= 0); @@ -770,31 +774,17 @@ dbus_connection_ref (connection); - /* Note that we might disconnect ourselves here, but it only takes - * effect on return to the main loop. We call this to free up - * expired connections if possible, and to queue the timeout for our - * own expiration. - */ bus_connections_expire_incomplete (connections); - /* And we might also disconnect ourselves here, but again it - * only takes effect on return to main loop. - */ - if (connections->n_incomplete > - bus_context_get_max_incomplete_connections (connections->context)) - { - _dbus_verbose ("Number of incomplete connections exceeds max, dropping oldest one\n"); - - _dbus_assert (connections->incomplete != NULL); - /* Disconnect the oldest unauthenticated connection. FIXME - * would it be more secure to drop a *random* connection? This - * algorithm seems to mean that if someone can create new - * connections quickly enough, they can keep anyone else from - * completing authentication. But random may or may not really - * help with that, a more elaborate solution might be required. - */ - dbus_connection_close (connections->incomplete->data); - } + /* The listening socket is removed from the main loop, + * i.e. does not accept(), while n_incomplete is at its + * maximum value; so we shouldn't get here in that case */ + _dbus_assert (connections->n_incomplete <= + bus_context_get_max_incomplete_connections (connections->context)); + + /* If we have the maximum number of incomplete connections, + * stop accept()ing any more, to avert a DoS. See fd.o #80919 */ + bus_context_check_all_watches (d->connections->context); retval = TRUE; @@ -1525,6 +1515,10 @@ _dbus_assert (d->connections->n_incomplete >= 0); _dbus_assert (d->connections->n_completed > 0); + /* If we have dropped below the max. number of incomplete + * connections, start accept()ing again */ + bus_context_check_all_watches (d->connections->context); + /* See if we can remove the timeout */ bus_connections_expire_incomplete (d->connections); @@ -2422,7 +2416,6 @@ return TRUE; } -#ifdef DBUS_ENABLE_STATS int bus_connections_get_n_active (BusConnections *connections) { @@ -2435,6 +2428,7 @@ return connections->n_incomplete; } +#ifdef DBUS_ENABLE_STATS int bus_connections_get_total_match_rules (BusConnections *connections) { Index: dbus-1.6.18/bus/connection.h =================================================================== --- dbus-1.6.18.orig/bus/connection.h 2014-09-17 10:15:47.302200477 -0400 +++ dbus-1.6.18/bus/connection.h 2014-09-17 10:16:32.678200733 -0400 @@ -139,9 +139,10 @@ void *data, DBusFreeFunction free_data_function); -/* called by stats.c, only present if DBUS_ENABLE_STATS */ int bus_connections_get_n_active (BusConnections *connections); int bus_connections_get_n_incomplete (BusConnections *connections); + +/* called by stats.c, only present if DBUS_ENABLE_STATS */ int bus_connections_get_total_match_rules (BusConnections *connections); int bus_connections_get_peak_match_rules (BusConnections *connections); int bus_connections_get_peak_match_rules_per_conn (BusConnections *connections); Index: dbus-1.6.18/dbus/dbus-server-protected.h =================================================================== --- dbus-1.6.18.orig/dbus/dbus-server-protected.h 2012-06-06 06:45:55.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-server-protected.h 2014-09-17 10:16:32.678200733 -0400 @@ -99,9 +99,8 @@ DBusWatch *watch); void _dbus_server_remove_watch (DBusServer *server, DBusWatch *watch); -void _dbus_server_toggle_watch (DBusServer *server, - DBusWatch *watch, - dbus_bool_t enabled); +void _dbus_server_toggle_all_watches (DBusServer *server, + dbus_bool_t enabled); dbus_bool_t _dbus_server_add_timeout (DBusServer *server, DBusTimeout *timeout); void _dbus_server_remove_timeout (DBusServer *server, Index: dbus-1.6.18/dbus/dbus-server.c =================================================================== --- dbus-1.6.18.orig/dbus/dbus-server.c 2013-04-22 10:10:32.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-server.c 2014-09-17 10:16:32.678200733 -0400 @@ -312,26 +312,17 @@ } /** - * Toggles a watch and notifies app via server's - * DBusWatchToggledFunction if available. It's an error to call this - * function on a watch that was not previously added. + * Toggles all watch and notifies app via server's + * DBusWatchToggledFunction if available. * * @param server the server. - * @param watch the watch to toggle. * @param enabled whether to enable or disable */ void -_dbus_server_toggle_watch (DBusServer *server, - DBusWatch *watch, - dbus_bool_t enabled) +_dbus_server_toggle_all_watches (DBusServer *server, + dbus_bool_t enabled) { - _dbus_assert (watch != NULL); - - HAVE_LOCK_CHECK (server); - protected_change_watch (server, watch, - NULL, NULL, - _dbus_watch_list_toggle_watch, - enabled); + _dbus_watch_list_toggle_all_watches (server->watches, enabled); } /** Function to be called in protected_change_timeout() with refcount held */ Index: dbus-1.6.18/dbus/dbus-watch.c =================================================================== --- dbus-1.6.18.orig/dbus/dbus-watch.c 2012-06-06 06:45:55.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-watch.c 2014-09-17 10:16:32.678200733 -0400 @@ -454,6 +454,27 @@ } /** + * Sets all watches to the given enabled state, invoking the + * application's DBusWatchToggledFunction if appropriate. + * + * @param watch_list the watch list. + * @param enabled #TRUE to enable + */ +void +_dbus_watch_list_toggle_all_watches (DBusWatchList *watch_list, + dbus_bool_t enabled) +{ + DBusList *link; + + for (link = _dbus_list_get_first_link (&watch_list->watches); + link != NULL; + link = _dbus_list_get_next_link (&watch_list->watches, link)) + { + _dbus_watch_list_toggle_watch (watch_list, link->data, enabled); + } +} + +/** * Sets the handler for the watch. * * @todo this function only exists because of the weird Index: dbus-1.6.18/dbus/dbus-watch.h =================================================================== --- dbus-1.6.18.orig/dbus/dbus-watch.h 2012-06-06 06:45:55.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-watch.h 2014-09-17 10:16:32.678200733 -0400 @@ -76,6 +76,8 @@ void _dbus_watch_list_toggle_watch (DBusWatchList *watch_list, DBusWatch *watch, dbus_bool_t enabled); +void _dbus_watch_list_toggle_all_watches (DBusWatchList *watch_list, + dbus_bool_t enabled); dbus_bool_t _dbus_watch_get_enabled (DBusWatch *watch); dbus_bool_t _dbus_watch_get_oom_last_time (DBusWatch *watch); debian/patches/CVE-2014-3637.patch0000664000000000000000000004460712406316123013252 0ustar Description: fix denial of service via persistent file descriptiors Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=e17a921be676bcc89373ec1a9f368fe8b36f1073 Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=52abb5172f7426bb3f1dbe63a2b3a2d2ea7e7ac2 Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=01e32d6ddcfdcbd63cf1c8053f6e5d2ffdfbaa91 Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=b027c421de0bc3858cc1139149c613958100c2bd Bug: https://bugs.freedesktop.org/show_bug.cgi?id=80559 Index: dbus-1.6.18/bus/bus.c =================================================================== --- dbus-1.6.18.orig/bus/bus.c 2014-09-17 10:14:10.466199930 -0400 +++ dbus-1.6.18/bus/bus.c 2014-09-17 10:14:20.718199988 -0400 @@ -1244,6 +1244,12 @@ } int +bus_context_get_pending_fd_timeout (BusContext *context) +{ + return context->limits.pending_fd_timeout; +} + +int bus_context_get_max_completed_connections (BusContext *context) { return context->limits.max_completed_connections; Index: dbus-1.6.18/bus/bus.h =================================================================== --- dbus-1.6.18.orig/bus/bus.h 2014-09-17 10:14:10.466199930 -0400 +++ dbus-1.6.18/bus/bus.h 2014-09-17 10:14:20.718199988 -0400 @@ -55,6 +55,7 @@ long max_message_unix_fds; /**< Max number of unix fds of a single message*/ int activation_timeout; /**< How long to wait for an activation to time out */ int auth_timeout; /**< How long to wait for an authentication to time out */ + int pending_fd_timeout; /**< How long to wait for a D-Bus message with a fd to time out */ int max_completed_connections; /**< Max number of authorized connections */ int max_incomplete_connections; /**< Max number of incomplete connections */ int max_connections_per_user; /**< Max number of connections auth'd as same user */ @@ -107,6 +108,7 @@ DBusError *error); int bus_context_get_activation_timeout (BusContext *context); int bus_context_get_auth_timeout (BusContext *context); +int bus_context_get_pending_fd_timeout (BusContext *context); int bus_context_get_max_completed_connections (BusContext *context); int bus_context_get_max_incomplete_connections (BusContext *context); int bus_context_get_max_connections_per_user (BusContext *context); Index: dbus-1.6.18/bus/config-parser.c =================================================================== --- dbus-1.6.18.orig/bus/config-parser.c 2014-09-17 10:14:10.650199931 -0400 +++ dbus-1.6.18/bus/config-parser.c 2014-09-17 10:14:54.758200180 -0400 @@ -429,6 +429,11 @@ * password) is allowed, then potentially it has to be quite long. */ parser->limits.auth_timeout = 30000; /* 30 seconds */ + + /* Do not allow a fd to stay forever in dbus-daemon + * https://bugs.freedesktop.org/show_bug.cgi?id=80559 + */ + parser->limits.pending_fd_timeout = 150000; /* 2.5 minutes */ parser->limits.max_incomplete_connections = 64; parser->limits.max_connections_per_user = 256; @@ -1913,6 +1918,12 @@ must_be_int = TRUE; parser->limits.auth_timeout = value; } + else if (strcmp (name, "pending_fd_timeout") == 0) + { + must_be_positive = TRUE; + must_be_int = TRUE; + parser->limits.pending_fd_timeout = value; + } else if (strcmp (name, "reply_timeout") == 0) { must_be_positive = TRUE; @@ -3121,6 +3132,7 @@ || a->max_message_unix_fds == b->max_message_unix_fds || a->activation_timeout == b->activation_timeout || a->auth_timeout == b->auth_timeout + || a->pending_fd_timeout == b->pending_fd_timeout || a->max_completed_connections == b->max_completed_connections || a->max_incomplete_connections == b->max_incomplete_connections || a->max_connections_per_user == b->max_connections_per_user Index: dbus-1.6.18/bus/connection.c =================================================================== --- dbus-1.6.18.orig/bus/connection.c 2014-09-17 10:14:10.466199930 -0400 +++ dbus-1.6.18/bus/connection.c 2014-09-17 10:15:13.574200286 -0400 @@ -34,6 +34,7 @@ #include #include #include +#include /* Trim executed commands to this length; we want to keep logs readable */ #define MAX_LOG_COMMAND_LEN 50 @@ -104,6 +105,8 @@ int peak_match_rules; int peak_bus_names; #endif + int n_pending_unix_fds; + DBusTimeout *pending_unix_fds_timeout; } BusConnectionData; static dbus_bool_t bus_pending_reply_expired (BusExpireList *list, @@ -270,6 +273,15 @@ dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); + + if (d->pending_unix_fds_timeout) + { + _dbus_loop_remove_timeout (bus_context_get_loop (d->connections->context), + d->pending_unix_fds_timeout); + _dbus_timeout_unref (d->pending_unix_fds_timeout); + } + d->pending_unix_fds_timeout = NULL; + _dbus_connection_set_pending_fds_function (connection, NULL, NULL); bus_connection_remove_transactions (connection); @@ -593,6 +605,42 @@ return FALSE; } +static void +check_pending_fds_cb (DBusConnection *connection) +{ + BusConnectionData *d = BUS_CONNECTION_DATA (connection); + int n_pending_unix_fds_old = d->n_pending_unix_fds; + int n_pending_unix_fds_new; + + n_pending_unix_fds_new = _dbus_connection_get_pending_fds_count (connection); + + _dbus_verbose ("Pending fds count changed on connection %p: %d -> %d\n", + connection, n_pending_unix_fds_old, n_pending_unix_fds_new); + + if (n_pending_unix_fds_old == 0 && n_pending_unix_fds_new > 0) + { + _dbus_timeout_set_interval (d->pending_unix_fds_timeout, + bus_context_get_pending_fd_timeout (d->connections->context)); + _dbus_timeout_set_enabled (d->pending_unix_fds_timeout, TRUE); + } + + if (n_pending_unix_fds_old > 0 && n_pending_unix_fds_new == 0) + { + _dbus_timeout_set_enabled (d->pending_unix_fds_timeout, FALSE); + } + + + d->n_pending_unix_fds = n_pending_unix_fds_new; +} + +static dbus_bool_t +pending_unix_fds_timeout_cb (void *data) +{ + DBusConnection *connection = data; + dbus_connection_close (connection); + return TRUE; +} + dbus_bool_t bus_connections_setup_connection (BusConnections *connections, DBusConnection *connection) @@ -701,6 +749,22 @@ } } + /* Setup pending fds timeout (see #80559) */ + d->pending_unix_fds_timeout = _dbus_timeout_new (100, /* irrelevant */ + pending_unix_fds_timeout_cb, + connection, NULL); + if (d->pending_unix_fds_timeout == NULL) + goto out; + + _dbus_timeout_set_enabled (d->pending_unix_fds_timeout, FALSE); + if (!_dbus_loop_add_timeout (bus_context_get_loop (connections->context), + d->pending_unix_fds_timeout)) + goto out; + + _dbus_connection_set_pending_fds_function (connection, + (DBusPendingFdsChangeFunction) check_pending_fds_cb, + connection); + _dbus_list_append_link (&connections->incomplete, d->link_in_connection_list); connections->n_incomplete += 1; @@ -766,6 +830,13 @@ dbus_connection_set_dispatch_status_function (connection, NULL, NULL, NULL); + if (d->pending_unix_fds_timeout) + _dbus_timeout_unref (d->pending_unix_fds_timeout); + + d->pending_unix_fds_timeout = NULL; + + _dbus_connection_set_pending_fds_function (connection, NULL, NULL); + if (d->link_in_connection_list != NULL) { _dbus_assert (d->link_in_connection_list->next == NULL); Index: dbus-1.6.18/bus/session.conf.in =================================================================== --- dbus-1.6.18.orig/bus/session.conf.in 2014-09-17 10:14:10.650199931 -0400 +++ dbus-1.6.18/bus/session.conf.in 2014-09-17 10:14:20.718199988 -0400 @@ -57,6 +57,7 @@ limit is also relatively low --> 120000 240000 + 150000 100000 10000 100000 Index: dbus-1.6.18/cmake/bus/dbus-daemon.xml =================================================================== --- dbus-1.6.18.orig/cmake/bus/dbus-daemon.xml 2012-08-13 14:08:25.000000000 -0400 +++ dbus-1.6.18/cmake/bus/dbus-daemon.xml 2014-09-17 10:14:20.718199988 -0400 @@ -401,7 +401,11 @@ "auth_timeout" : milliseconds (thousandths) a connection is given to authenticate - "max_completed_connections" : max number of authenticated connections + "pending_fd_timeout" : milliseconds (thousandths) a + fd is given to be transmitted to + dbus-daemon before disconnecting the + connection + "max_completed_connections" : max number of authenticated connections "max_incomplete_connections" : max number of unauthenticated connections "max_connections_per_user" : max number of completed connections from Index: dbus-1.6.18/dbus/dbus-connection-internal.h =================================================================== --- dbus-1.6.18.orig/dbus/dbus-connection-internal.h 2012-08-13 14:08:25.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-connection-internal.h 2014-09-17 10:15:11.270200273 -0400 @@ -44,6 +44,8 @@ /** default timeout value when waiting for a message reply, 25 seconds */ #define _DBUS_DEFAULT_TIMEOUT_VALUE (25 * 1000) +typedef void (* DBusPendingFdsChangeFunction) (void *data); + void _dbus_connection_lock (DBusConnection *connection); void _dbus_connection_unlock (DBusConnection *connection); DBusConnection * _dbus_connection_ref_unlocked (DBusConnection *connection); @@ -100,6 +102,10 @@ DBusMutex **io_path_mutex_loc, DBusCondVar **dispatch_cond_loc, DBusCondVar **io_path_cond_loc); +int _dbus_connection_get_pending_fds_count (DBusConnection *connection); +void _dbus_connection_set_pending_fds_function (DBusConnection *connection, + DBusPendingFdsChangeFunction callback, + void *data); /* if DBUS_ENABLE_STATS */ void _dbus_connection_get_stats (DBusConnection *connection, Index: dbus-1.6.18/dbus/dbus-connection.c =================================================================== --- dbus-1.6.18.orig/dbus/dbus-connection.c 2013-09-13 07:34:53.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-connection.c 2014-09-17 10:15:11.274200273 -0400 @@ -2532,6 +2532,33 @@ dbus_pending_call_unref (pending); } +/** + * Return how many file descriptors are pending in the loader + * + * @param connection the connection + */ +int +_dbus_connection_get_pending_fds_count (DBusConnection *connection) +{ + return _dbus_transport_get_pending_fds_count (connection->transport); +} + +/** + * Register a function to be called whenever the number of pending file + * descriptors in the loader change. + * + * @param connection the connection + * @param callback the callback + */ +void +_dbus_connection_set_pending_fds_function (DBusConnection *connection, + DBusPendingFdsChangeFunction callback, + void *data) +{ + _dbus_transport_set_pending_fds_function (connection->transport, + callback, data); +} + /** @} */ /** Index: dbus-1.6.18/dbus/dbus-message-internal.h =================================================================== --- dbus-1.6.18.orig/dbus/dbus-message-internal.h 2012-06-06 06:45:55.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-message-internal.h 2014-09-17 10:15:11.274200273 -0400 @@ -97,6 +97,10 @@ void _dbus_message_loader_set_max_message_unix_fds(DBusMessageLoader *loader, long n); long _dbus_message_loader_get_max_message_unix_fds(DBusMessageLoader *loader); +int _dbus_message_loader_get_pending_fds_count (DBusMessageLoader *loader); +void _dbus_message_loader_set_pending_fds_function (DBusMessageLoader *loader, + void (* callback) (void *), + void *data); typedef struct DBusInitialFDs DBusInitialFDs; DBusInitialFDs *_dbus_check_fdleaks_enter (void); Index: dbus-1.6.18/dbus/dbus-message-private.h =================================================================== --- dbus-1.6.18.orig/dbus/dbus-message-private.h 2012-06-06 06:45:55.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-message-private.h 2014-09-17 10:15:11.274200273 -0400 @@ -80,6 +80,8 @@ int *unix_fds; /**< File descriptors that have been read from the transport but not yet been handed to any message. Array will be allocated at first use. */ unsigned n_unix_fds_allocated; /**< Number of file descriptors this array has space for */ unsigned n_unix_fds; /**< Number of valid file descriptors in array */ + void (* unix_fds_change) (void *); /**< Notify when the pending fds change */ + void *unix_fds_change_data; #endif }; Index: dbus-1.6.18/dbus/dbus-message.c =================================================================== --- dbus-1.6.18.orig/dbus/dbus-message.c 2014-09-17 10:14:10.650199931 -0400 +++ dbus-1.6.18/dbus/dbus-message.c 2014-09-17 10:15:11.274200273 -0400 @@ -3984,6 +3984,9 @@ loader->n_unix_fds += n_fds; loader->unix_fds_outstanding = FALSE; + + if (n_fds && loader->unix_fds_change) + loader->unix_fds_change (loader->unix_fds_change_data); #else _dbus_assert_not_reached("Platform doesn't support unix fd passing"); #endif @@ -4131,6 +4134,9 @@ message->n_unix_fds_allocated = message->n_unix_fds = n_unix_fds; loader->n_unix_fds -= n_unix_fds; memmove (loader->unix_fds, loader->unix_fds + n_unix_fds, loader->n_unix_fds * sizeof (loader->unix_fds[0])); + + if (loader->unix_fds_change) + loader->unix_fds_change (loader->unix_fds_change_data); } else message->unix_fds = NULL; @@ -4428,6 +4434,40 @@ _DBUS_DEFINE_GLOBAL_LOCK (message_slots); /** + * Return how many file descriptors are pending in the loader + * + * @param loader the loader + */ +int +_dbus_message_loader_get_pending_fds_count (DBusMessageLoader *loader) +{ +#ifdef HAVE_UNIX_FD_PASSING + return loader->n_unix_fds; +#else + return 0; +#endif +} + +/** + * Register a function to be called whenever the number of pending file + * descriptors in the loader change. + * + * @param loader the loader + * @param callback the callback + * @param data the data for the callback + */ +void +_dbus_message_loader_set_pending_fds_function (DBusMessageLoader *loader, + void (* callback) (void *), + void *data) +{ +#ifdef HAVE_UNIX_FD_PASSING + loader->unix_fds_change = callback; + loader->unix_fds_change_data = data; +#endif +} + +/** * Allocates an integer ID to be used for storing application-specific * data on any DBusMessage. The allocated ID may then be used * with dbus_message_set_data() and dbus_message_get_data(). Index: dbus-1.6.18/dbus/dbus-transport.c =================================================================== --- dbus-1.6.18.orig/dbus/dbus-transport.c 2012-08-13 14:08:25.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-transport.c 2014-09-17 10:15:11.278200273 -0400 @@ -1491,6 +1491,33 @@ transport->allow_anonymous = value != FALSE; } +/** + * Return how many file descriptors are pending in the loader + * + * @param transport the transport + */ +int +_dbus_transport_get_pending_fds_count (DBusTransport *transport) +{ + return _dbus_message_loader_get_pending_fds_count (transport->loader); +} + +/** + * Register a function to be called whenever the number of pending file + * descriptors in the loader change. + * + * @param transport the transport + * @param callback the callback + */ +void +_dbus_transport_set_pending_fds_function (DBusTransport *transport, + void (* callback) (void *), + void *data) +{ + _dbus_message_loader_set_pending_fds_function (transport->loader, + callback, data); +} + #ifdef DBUS_ENABLE_STATS void _dbus_transport_get_stats (DBusTransport *transport, Index: dbus-1.6.18/dbus/dbus-transport.h =================================================================== --- dbus-1.6.18.orig/dbus/dbus-transport.h 2012-06-06 06:45:55.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-transport.h 2014-09-17 10:15:11.278200273 -0400 @@ -96,6 +96,10 @@ const char **mechanisms); void _dbus_transport_set_allow_anonymous (DBusTransport *transport, dbus_bool_t value); +int _dbus_transport_get_pending_fds_count (DBusTransport *transport); +void _dbus_transport_set_pending_fds_function (DBusTransport *transport, + void (* callback) (void *), + void *data); /* if DBUS_ENABLE_STATS */ void _dbus_transport_get_stats (DBusTransport *transport, debian/patches/CVE-2014-3532.patch0000664000000000000000000001053612355246766013260 0ustar From 8c7176019fbc2e8fee41d93ce82ac2603fe57d67 Mon Sep 17 00:00:00 2001 From: Alban Crequy Date: Tue, 24 Jun 2014 16:57:14 +0000 Subject: Handle ETOOMANYREFS when sending recursive fds (SCM_RIGHTS) Since Linux commit 25888e (from 2.6.37-rc4, Nov 2010), sendmsg() on Unix sockets returns -1 errno=ETOOMANYREFS ("Too many references: cannot splice") when the passfd mechanism (SCM_RIGHTS) is "abusively" used recursively by applications. A malicious client could use this to force a victim system service to be disconnected from the system bus; the victim would likely respond by exiting. This is a denial of service (fd.o #80163, CVE-2014-3532). This patch silently drops the D-Bus message on ETOOMANYREFS and does not close the connection. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=80163 Reviewed-by: Thiago Macieira [altered commit message to explain DoS significance -smcv] Reviewed-by: Simon McVittie --- diff --git a/dbus/dbus-sysdeps.c b/dbus/dbus-sysdeps.c index 04fb8d7..8ed7da9 100644 --- a/dbus/dbus-sysdeps.c +++ b/dbus/dbus-sysdeps.c @@ -760,6 +760,20 @@ _dbus_get_is_errno_epipe (void) } /** + * See if errno is ETOOMANYREFS + * @returns #TRUE if errno == ETOOMANYREFS + */ +dbus_bool_t +_dbus_get_is_errno_etoomanyrefs (void) +{ +#ifdef ETOOMANYREFS + return errno == ETOOMANYREFS; +#else + return FALSE; +#endif +} + +/** * Get error message from errno * @returns _dbus_strerror(errno) */ diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index eee9160..df4c5e0 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -373,6 +373,7 @@ dbus_bool_t _dbus_get_is_errno_eagain_or_ewouldblock (void); dbus_bool_t _dbus_get_is_errno_enomem (void); dbus_bool_t _dbus_get_is_errno_eintr (void); dbus_bool_t _dbus_get_is_errno_epipe (void); +dbus_bool_t _dbus_get_is_errno_etoomanyrefs (void); const char* _dbus_strerror_from_errno (void); void _dbus_disable_sigpipe (void); diff --git a/dbus/dbus-transport-socket.c b/dbus/dbus-transport-socket.c index 544d00a..26d2b73 100644 --- a/dbus/dbus-transport-socket.c +++ b/dbus/dbus-transport-socket.c @@ -646,12 +646,44 @@ do_writing (DBusTransport *transport) { /* EINTR already handled for us */ - /* For some discussion of why we also ignore EPIPE here, see + /* If the other end closed the socket with close() or shutdown(), we + * receive EPIPE here but we must not close the socket yet: there + * might still be some data to read. See: * http://lists.freedesktop.org/archives/dbus/2008-March/009526.html */ if (_dbus_get_is_errno_eagain_or_ewouldblock () || _dbus_get_is_errno_epipe ()) goto out; + + /* Since Linux commit 25888e (from 2.6.37-rc4, Nov 2010), sendmsg() + * on Unix sockets returns -1 errno=ETOOMANYREFS when the passfd + * mechanism (SCM_RIGHTS) is used recursively with a recursion level + * of maximum 4. The kernel does not have an API to check whether + * the passed fds can be forwarded and it can change asynchronously. + * See: + * https://bugs.freedesktop.org/show_bug.cgi?id=80163 + */ + + else if (_dbus_get_is_errno_etoomanyrefs ()) + { + /* We only send fds in the first byte of the message. + * ETOOMANYREFS cannot happen after. + */ + _dbus_assert (socket_transport->message_bytes_written == 0); + + _dbus_verbose (" discard message of %d bytes due to ETOOMANYREFS\n", + total_bytes_to_write); + + socket_transport->message_bytes_written = 0; + _dbus_string_set_length (&socket_transport->encoded_outgoing, 0); + _dbus_string_compact (&socket_transport->encoded_outgoing, 2048); + + /* The message was not actually sent but it needs to be removed + * from the outgoing queue + */ + _dbus_connection_message_sent_unlocked (transport->connection, + message); + } else { _dbus_verbose ("Error writing to remote app: %s\n", -- cgit v0.9.0.2-2-gbebe debian/patches/CVE-2014-3477.patch0000664000000000000000000001421512355246760013260 0ustar From cab1c56bb9d70469128d2ae1c40539c0d3b30f13 Mon Sep 17 00:00:00 2001 From: Alban Crequy Date: Tue, 20 May 2014 13:37:37 +0000 Subject: CVE-2014-3477: deliver activation errors correctly, fixing Denial of Service How it should work: When a D-Bus message activates a service, LSMs (SELinux or AppArmor) check whether the message can be delivered after the service has been activated. The service is considered activated when its well-known name is requested with org.freedesktop.DBus.RequestName. When the message delivery is denied, the service stays activated but should not receive the activating message (the message which triggered the activation). dbus-daemon is supposed to drop the activating message and reply to the sender with a D-Bus error message. However, it does not work as expected: 1. The error message is delivered to the service instead of being delivered to the sender. As an example, the error message could be something like: An SELinux policy prevents this sender from sending this message to this recipient, [...] member="MaliciousMethod" If the sender and the service are malicious confederates and agree on a protocol to insert information in the member name, the sender can leak information to the service, even though the LSM attempted to block the communication between the sender and the service. 2. The error message is delivered as a reply to the RequestName call from service. It means the activated service will believe it cannot request the name and might exit. The sender could activate the service frequently and systemd will give up activating it. Thus the denial of service. The following changes fix the bug: - bus_activation_send_pending_auto_activation_messages() only returns an error in case of OOM. The prototype is changed to return TRUE, or FALSE on OOM (and its only caller sets the OOM error). - When a client is not allowed to talk to the service, a D-Bus error message is pre-allocated to be delivered to the client as part of the transaction. The error is not propagated to the caller so RequestName will not fail (except on OOM). [fixed a misleading comment -smcv] Bug: https://bugs.freedesktop.org/show_bug.cgi?id=78979 Reviewed-by: Simon McVittie Reviewed-by: Colin Walters --- Index: dbus-1.6.18/bus/activation.c =================================================================== --- dbus-1.6.18.orig/bus/activation.c 2014-07-03 08:28:01.617558968 -0400 +++ dbus-1.6.18/bus/activation.c 2014-07-03 08:28:01.613558968 -0400 @@ -1162,14 +1162,11 @@ dbus_bool_t bus_activation_send_pending_auto_activation_messages (BusActivation *activation, BusService *service, - BusTransaction *transaction, - DBusError *error) + BusTransaction *transaction) { BusPendingActivation *pending_activation; DBusList *link; - _DBUS_ASSERT_ERROR_IS_CLEAR (error); - /* Check if it's a pending activation */ pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, bus_service_get_name (service)); @@ -1186,6 +1183,9 @@ if (entry->auto_activation && (entry->connection == NULL || dbus_connection_get_is_connected (entry->connection))) { DBusConnection *addressed_recipient; + DBusError error; + + dbus_error_init (&error); addressed_recipient = bus_service_get_primary_owners_connection (service); @@ -1193,8 +1193,22 @@ if (!bus_dispatch_matches (transaction, entry->connection, addressed_recipient, - entry->activation_message, error)) - goto error; + entry->activation_message, &error)) + { + /* If permission is denied, we just want to return the error + * to the original method invoker; in particular, we don't + * want to make the RequestName call fail with that error + * (see fd.o #78979, CVE-2014-3477). */ + if (!bus_transaction_send_error_reply (transaction, entry->connection, + &error, entry->activation_message)) + { + bus_connection_send_oom_error (entry->connection, + entry->activation_message); + } + + link = next; + continue; + } } link = next; @@ -1203,7 +1217,6 @@ if (!add_restore_pending_to_transaction (transaction, pending_activation)) { _dbus_verbose ("Could not add cancel hook to transaction to revert removing pending activation\n"); - BUS_SET_OOM (error); goto error; } Index: dbus-1.6.18/bus/activation.h =================================================================== --- dbus-1.6.18.orig/bus/activation.h 2014-07-03 08:28:01.617558968 -0400 +++ dbus-1.6.18/bus/activation.h 2014-07-03 08:28:01.613558968 -0400 @@ -62,8 +62,7 @@ dbus_bool_t bus_activation_send_pending_auto_activation_messages (BusActivation *activation, BusService *service, - BusTransaction *transaction, - DBusError *error); + BusTransaction *transaction); #endif /* BUS_ACTIVATION_H */ Index: dbus-1.6.18/bus/services.c =================================================================== --- dbus-1.6.18.orig/bus/services.c 2014-07-03 08:28:01.617558968 -0400 +++ dbus-1.6.18/bus/services.c 2014-07-03 08:28:01.613558968 -0400 @@ -611,8 +611,9 @@ activation = bus_context_get_activation (registry->context); retval = bus_activation_send_pending_auto_activation_messages (activation, service, - transaction, - error); + transaction); + if (!retval) + BUS_SET_OOM (error); out: return retval; debian/patches/CVE-2014-3638.patch0000664000000000000000000000143112406316327013245 0ustar Description: fix denial of service via large number of pending replies Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=6060aaa0ea1e9bbe1dd7a1864c8df52e333a45ee Bug: https://bugs.freedesktop.org/show_bug.cgi?id=81053 Index: dbus-1.6.18/bus/config-parser.c =================================================================== --- dbus-1.6.18.orig/bus/config-parser.c 2014-09-17 10:15:27.914200367 -0400 +++ dbus-1.6.18/bus/config-parser.c 2014-09-17 10:15:40.358200437 -0400 @@ -462,7 +462,7 @@ /* this is effectively a limit on message queue size for messages * that require a reply */ - parser->limits.max_replies_per_connection = 1024*8; + parser->limits.max_replies_per_connection = 128; } parser->refcount = 1; debian/patches/0001-activation-allow-for-more-variation-than-just-system.patch0000664000000000000000000001535712240207265024461 0ustar From 28b76a197d13fefa9a89e1ba9ca402130247c6c9 Mon Sep 17 00:00:00 2001 From: Scott James Remnant Date: Tue, 21 Dec 2010 15:41:16 +0000 Subject: [PATCH 1/5] activation: allow for more variation than just "systemd" Implementing systemd_activation as a bool means we'd end up with dozens of bools here if every init daemon decided to take over bus activation. Turn it into an enum instead. --- bus/activation.c | 2 +- bus/bus.c | 16 ++++++++-------- bus/bus.h | 12 +++++++++--- bus/main.c | 8 ++++---- 4 files changed, 22 insertions(+), 16 deletions(-) Index: dbus-1.4.16/bus/activation.c =================================================================== --- dbus-1.4.16.orig/bus/activation.c 2011-09-21 13:16:15.000000000 +0200 +++ dbus-1.4.16/bus/activation.c 2011-10-18 18:10:55.214134484 +0200 @@ -1916,7 +1916,7 @@ if (was_pending_activation) return TRUE; - if (bus_context_get_systemd_activation (activation->context)) + if (bus_context_get_activation_type (activation->context) == ACTIVATION_SYSTEMD) { if (strcmp (service_name, "org.freedesktop.systemd1") == 0) /* systemd itself is missing apparently. That can happen Index: dbus-1.4.16/bus/bus.c =================================================================== --- dbus-1.4.16.orig/bus/bus.c 2011-09-21 13:16:15.000000000 +0200 +++ dbus-1.4.16/bus/bus.c 2011-10-18 18:10:55.214134484 +0200 @@ -55,6 +55,7 @@ char *pidfile; char *user; char *log_prefix; + ActivationType activation_type; DBusLoop *loop; DBusList *servers; BusConnections *connections; @@ -67,7 +68,6 @@ unsigned int syslog : 1; unsigned int keep_umask : 1; unsigned int allow_anonymous : 1; - unsigned int systemd_activation : 1; }; static dbus_int32_t server_data_slot = -1; @@ -284,7 +284,7 @@ process_config_first_time_only (BusContext *context, BusConfigParser *parser, const DBusString *address, - dbus_bool_t systemd_activation, + ActivationType activation_type, DBusError *error) { DBusString log_prefix; @@ -303,7 +303,7 @@ _dbus_init_system_log (); - context->systemd_activation = systemd_activation; + context->activation_type = activation_type; /* Check for an existing pid file. Of course this is a race; * we'd have to use fcntl() locks on the pid file to @@ -712,7 +712,7 @@ DBusPipe *print_addr_pipe, DBusPipe *print_pid_pipe, const DBusString *address, - dbus_bool_t systemd_activation, + ActivationType activation_type, DBusError *error) { DBusString log_prefix; @@ -767,7 +767,7 @@ goto failed; } - if (!process_config_first_time_only (context, parser, address, systemd_activation, error)) + if (!process_config_first_time_only (context, parser, address, activation_type, error)) { _DBUS_ASSERT_ERROR_IS_SET (error); goto failed; @@ -1146,9 +1146,9 @@ } dbus_bool_t -bus_context_get_systemd_activation (BusContext *context) +bus_context_get_activation_type (BusContext *context) { - return context->systemd_activation; + return context->activation_type; } BusRegistry* Index: dbus-1.4.16/bus/bus.h =================================================================== --- dbus-1.4.16.orig/bus/bus.h 2011-09-14 17:58:18.000000000 +0200 +++ dbus-1.4.16/bus/bus.h 2011-10-18 18:10:55.218134485 +0200 @@ -71,12 +71,18 @@ FORK_NEVER } ForceForkSetting; +typedef enum +{ + ACTIVATION_DEFAULT, + ACTIVATION_SYSTEMD +} ActivationType; + BusContext* bus_context_new (const DBusString *config_file, ForceForkSetting force_fork, DBusPipe *print_addr_pipe, DBusPipe *print_pid_pipe, const DBusString *address, - dbus_bool_t systemd_activation, + ActivationType activation_type, DBusError *error); dbus_bool_t bus_context_reload_config (BusContext *context, DBusError *error); @@ -88,7 +94,7 @@ const char* bus_context_get_type (BusContext *context); const char* bus_context_get_address (BusContext *context); const char* bus_context_get_servicehelper (BusContext *context); -dbus_bool_t bus_context_get_systemd_activation (BusContext *context); +ActivationType bus_context_get_activation_type (BusContext *context); BusRegistry* bus_context_get_registry (BusContext *context); BusConnections* bus_context_get_connections (BusContext *context); BusActivation* bus_context_get_activation (BusContext *context); Index: dbus-1.4.16/bus/main.c =================================================================== --- dbus-1.4.16.orig/bus/main.c 2011-09-21 13:16:15.000000000 +0200 +++ dbus-1.4.16/bus/main.c 2011-10-18 18:10:55.218134485 +0200 @@ -361,7 +361,7 @@ dbus_bool_t print_pid; dbus_bool_t is_session_bus; int force_fork; - dbus_bool_t systemd_activation; + ActivationType activation_type; if (!_dbus_string_init (&config_file)) return 1; @@ -379,7 +379,7 @@ print_pid = FALSE; is_session_bus = FALSE; force_fork = FORK_FOLLOW_CONFIG_FILE; - systemd_activation = FALSE; + activation_type = ACTIVATION_DEFAULT; prev_arg = NULL; i = 1; @@ -400,7 +400,7 @@ else if (strcmp (arg, "--fork") == 0) force_fork = FORK_ALWAYS; else if (strcmp (arg, "--systemd-activation") == 0) - systemd_activation = TRUE; + activation_type = ACTIVATION_SYSTEMD; else if (strcmp (arg, "--system") == 0) { check_two_config_files (&config_file, "system"); @@ -579,7 +579,7 @@ context = bus_context_new (&config_file, force_fork, &print_addr_pipe, &print_pid_pipe, _dbus_string_get_length(&address) > 0 ? &address : NULL, - systemd_activation, + activation_type, &error); _dbus_string_free (&config_file); if (context == NULL) debian/patches/series0000664000000000000000000000151713012370151012031 0ustar 00git_logind_check.patch 00git_sd_daemon_update.patch 01_no-fatal-warnings.patch 20_system_conf_limit.patch 81-session.conf-timeout.patch #0001-activation-allow-for-more-variation-than-just-system.patch #0002-bus-change-systemd-activation-to-activation-systemd.patch #0003-upstart-add-upstart-as-a-possible-activation-type.patch #0004-upstart-add-UpstartJob-to-service-desktop-files.patch #0005-activation-implement-upstart-activation.patch aa-build-tools.patch aa-mediation.patch aa-get-connection-apparmor-security-context.patch aa-mediate-eavesdropping.patch CVE-2014-3477.patch CVE-2014-3532.patch CVE-2014-3533.patch CVE-2014-3635.patch CVE-2014-3636.patch CVE-2014-3637.patch CVE-2014-3638.patch CVE-2014-3639.patch CVE-2014-7824.patch CVE-2014-3639-regression.patch CVE-2015-0245.patch format_string.patch unrequested-reply-mediation.patch debian/patches/20_system_conf_limit.patch0000664000000000000000000000111512240207265015666 0ustar Index: dbus-1.2.16/bus/system.conf.in =================================================================== --- dbus-1.2.16.orig/bus/system.conf.in 2009-10-23 20:06:56.000000000 +0200 +++ dbus-1.2.16/bus/system.conf.in 2009-10-23 20:09:53.000000000 +0200 @@ -80,4 +80,7 @@ contexts/dbus_contexts + + 5000 debian/patches/aa-mediation.patch0000664000000000000000000012642212240207265014177 0ustar Description: Add support for AppArmor mediation of D-Bus AppArmor D-Bus rules are contained in the centralized, system AppArmor policy. See the apparmor.d(5) man page for details. . AppArmor performs mediation of messages and when applications attempt to bind to a well-known connection name. Unconfined applications can generally do as they please. Applications confined by AppArmor will require D-Bus rules in the AppArmor profiles to use D-Bus. To grant all permissions, simply add the following rule to the AppArmor profile: dbus, The apparmor.d(5) man page describes, in detail, the syntax for tightly confining D-Bus communications. Author: John Johansen Author: Tyler Hicks Index: dbus-1.6.12/bus/Makefile.am =================================================================== --- dbus-1.6.12.orig/bus/Makefile.am 2013-10-10 09:52:39.000000000 -0700 +++ dbus-1.6.12/bus/Makefile.am 2013-10-10 09:52:39.000000000 -0700 @@ -68,6 +68,8 @@ BUS_SOURCES= \ activation.c \ activation.h \ activation-exit-codes.h \ + apparmor.h \ + apparmor.c \ bus.c \ bus.h \ config-parser.c \ Index: dbus-1.6.12/bus/apparmor.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ dbus-1.6.12/bus/apparmor.c 2013-10-10 10:39:51.177375349 -0700 @@ -0,0 +1,837 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * apparmor.c AppArmor security checks for D-Bus + * + * Authors: John Johansen + * Tyler Hicks + * Based on: selinux.c by Matthew Rickard + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#include +#include +#include + +#include "policy.h" +#include "services.h" +#include "utils.h" + + +#ifdef HAVE_APPARMOR + +#ifdef HAVE_ERRNO_H +#include +#endif /* HAVE_ERRNO_H */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "apparmor.h" +#endif /* HAVE_APPARMOR */ +#ifdef HAVE_LIBAUDIT +#include +#include +#endif /* HAVE_LIBAUDIT */ + + +#ifdef HAVE_APPARMOR +/* Store the value telling us if AppArmor is enabled in the kernel. */ +static dbus_bool_t apparmor_enabled = FALSE; + +typedef enum { + APPARMOR_DISABLED, + APPARMOR_ENABLED, + APPARMOR_REQUIRED +} AppArmorConfigMode; + +/* 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 + +struct BusAppArmorConfinement +{ + int refcount; /* Reference count */ + + char *context; /* AppArmor confinement context (label) */ + char *mode; /* AppArmor confinement mode */ +}; + +static BusAppArmorConfinement *bus_con = NULL; + +static BusAppArmorConfinement* +bus_apparmor_confinement_new (char *context, char *mode) +{ + BusAppArmorConfinement *confinement; + + confinement = dbus_new0 (BusAppArmorConfinement, 1); + if (confinement != NULL) + { + confinement->refcount = 1; + confinement->context = context; + confinement->mode = mode; + } + + return confinement; +} + +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 +modestr_to_complain(const char *mode) +{ + if (mode && strcmp(mode, "complain") == 0) + return TRUE; + return FALSE; +} + +static void +log_message (dbus_bool_t allow, const char *op, DBusString *data) +{ + const char *mstr; + + if (allow) + mstr = "ALLOWED"; + else + mstr = "DENIED"; + +#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 */ + snprintf(buf, sizeof(buf), "apparmor=\"%s\" operation=\"dbus_%s\" %s\n", + mstr, op, _dbus_string_get_const_data(data)); + audit_log_user_avc_message(audit_fd, AUDIT_USER_AVC, buf, NULL, NULL, + NULL, getuid()); + return; + } + } +#endif /* HAVE_LIBAUDIT */ + + syslog (LOG_USER | LOG_INFO, "apparmor=\"%s\" operation=\"dbus_%s\" %s\n", + mstr, op,_dbus_string_get_const_data(data)); +} + +static dbus_bool_t +_dbus_append_pair_uint(DBusString *auxdata, const char *name, + unsigned long value) +{ + if (!_dbus_string_append (auxdata, " ")) + return FALSE; + if (!_dbus_string_append (auxdata, name)) + return FALSE; + if (!_dbus_string_append (auxdata, "=")) + return FALSE; + if (!_dbus_string_append_uint (auxdata, value)) + return FALSE; + + return TRUE; +} + +static dbus_bool_t +_dbus_append_pair_str(DBusString *auxdata, const char *name, const char *value) +{ + if (!_dbus_string_append (auxdata, " ")) + return FALSE; + if (!_dbus_string_append (auxdata, name)) + return FALSE; + if (!_dbus_string_append (auxdata, "=\"")) + return FALSE; + if (!_dbus_string_append (auxdata, value)) + return FALSE; + if (!_dbus_string_append (auxdata, "\"")) + return FALSE; + + return TRUE; +} + +static dbus_bool_t +_dbus_append_mask(DBusString *auxdata, uint32_t mask) +{ + if (mask & AA_DBUS_SEND) + return _dbus_append_pair_str(auxdata, "mask", "send"); + else if (mask & AA_DBUS_RECEIVE) + return _dbus_append_pair_str(auxdata, "mask", "receive"); + else if (mask & AA_DBUS_BIND) + return _dbus_append_pair_str(auxdata, "mask", "bind"); + + return FALSE; +} + +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) +{ +#ifdef HAVE_APPARMOR + if (mode != NULL) + { + if (strcmp (mode, "disabled") == 0) + apparmor_config_mode = APPARMOR_DISABLED; + else if (strcmp (mode, "enabled") == 0) + apparmor_config_mode = APPARMOR_ENABLED; + else if (strcmp (mode, "required") == 0) + apparmor_config_mode = APPARMOR_REQUIRED; + else + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Mode attribute on must have value " + "\"required\", \"enabled\" or \"disabled\", " + "not \"%s\"", mode); + return FALSE; + } + } + + return TRUE; +#else + if (mode != NULL && strcmp (mode, "required") == 0) + { + dbus_set_error (error, DBUS_ERROR_FAILED, + "Mode attribute \"required\" on is not valid " + "when D-Bus is built without AppArmor support"); + return FALSE; + } + + return TRUE; +#endif +} + +/** + * Initialize user space + */ +dbus_bool_t +bus_apparmor_full_init (void) +{ +#ifdef HAVE_APPARMOR + char *context, *mode; + + if (apparmor_enabled) + { + if (apparmor_config_mode == APPARMOR_DISABLED) + { + apparmor_enabled = FALSE; + return TRUE; + } + + if (bus_con == NULL) + { + if (aa_getcon (&context, &mode) == -1) + { + _dbus_warn ("Error getting AppArmor context of bus: %s\n", + _dbus_strerror (errno)); + return FALSE; + } + + bus_con = bus_apparmor_confinement_new (context, mode); + if (bus_con == NULL) + { + _dbus_warn ("Error allocating bus AppArmor confinement\n"); + free (context); + return FALSE; + } + } + } + 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"); + + bus_apparmor_confinement_unref (bus_con); + bus_con = NULL; + +#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; +} + +#ifdef HAVE_APPARMOR +static dbus_bool_t +is_unconfined(const char *con, const char *mode) +{ + /* treat con == NULL as confined as it is going to result in a denial */ + if ((!mode && con && strcmp(con, "unconfined") == 0) || + strcmp(mode, "unconfined") == 0) + { + return TRUE; + } + + return FALSE; +} + +static ssize_t (build_query)(char **qstr, const char *con, int count, ...) +{ + va_list ap; + int size, con_size, i; + char *buffer, *to; + + con_size = strlen(con); + size = con_size + 1; + va_start(ap, count); + for (i = 0; i < count; i++) + { + char *s = va_arg(ap, char *); + if (s) + size += strlen(s); + } + va_end(ap); + + buffer = malloc(size + count + 1 + AA_QUERY_CMD_LABEL_SIZE); + if (!buffer) + return -1; + + to = buffer + AA_QUERY_CMD_LABEL_SIZE; + strcpy(to, con); + to += con_size; + *(to)++ = '\0'; + *(to)++ = AA_CLASS_DBUS; + + va_start(ap, count); + for (i = 0; i < count; to++, i++) + { + char *arg = va_arg(ap, char *); + if (!arg) + arg = ""; + to = stpcpy(to, arg); + } + va_end(ap); + *qstr = buffer; + + /* don't include trailing \0 in size */ + return size + count + AA_QUERY_CMD_LABEL_SIZE; +} +#endif /* HAVE_APPARMOR */ + +#define build_query(T, C, X...) \ + (build_query)(T, C, __macroarg_counter(X), X) + +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 /* HAVE_APPARMOR */ +} + +void +bus_apparmor_confinement_ref (BusAppArmorConfinement *confinement) +{ +#ifdef HAVE_APPARMOR + if (!apparmor_enabled) + return; + + _dbus_assert (confinement != NULL); + _dbus_assert (confinement->refcount > 0); + + confinement->refcount += 1; +#endif /* HAVE_APPARMOR */ +} + +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 */ +} + +/** + * Returns true if the given connection can acquire a service, + * using the tasks security context + * + * @param connection connection that wants to own the service + * @param service_sid the SID of the service from the table + * @returns #TRUE if acquire is permitted. + */ +dbus_bool_t +bus_apparmor_allows_acquire_service (DBusConnection *connection, + BusSELinuxID *service_sid, + const char *bustype, + const char *service_name, + DBusError *error) +{ + +#ifdef HAVE_APPARMOR + BusAppArmorConfinement *con = NULL; + DBusString auxdata; + dbus_bool_t string_alloced = FALSE; + dbus_bool_t allow = FALSE, audit = TRUE; + unsigned long pid; + int res, serrno = 0; + char *qstr = NULL; + ssize_t qsize; + + if (!apparmor_enabled) + return TRUE; + + _dbus_assert (connection != NULL); + + 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, service_name); + if (qsize == -1) + goto oom; + + res = aa_query_label(AA_DBUS_BIND, 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 (!_dbus_append_pair_str(&auxdata, "name", service_name)) + goto oom; + + if (serrno && !_dbus_append_pair_str(&auxdata, "info", strerror(serrno))) + goto oom; + + if (!_dbus_append_mask(&auxdata, AA_DBUS_BIND)) + 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, "bind", &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 */ +} + +#include +/** + * Check if Apparmor security controls allow the message to be sent to a + * particular connection based on the security context of the sender and + * that of the receiver. The destination connection need not be the + * addressed recipient, it could be an "eavesdropper" + * + * @param sender the sender of the message. + * @param proposed_recipient the connection the message is to be sent to. + * @returns whether to allow the send + */ +dbus_bool_t +bus_apparmor_allows_send (DBusConnection *sender, + DBusConnection *proposed_recipient, + const char *bustype, + const char *msgtype, + const char *path, + const char *interface, + const char *method, + const char *error_name, + const char *destination, + const char *source, + DBusError *error) +{ +#ifdef HAVE_APPARMOR + BusAppArmorConfinement *scon = NULL, *tcon = NULL; + DBusString auxdata; + dbus_bool_t sallow = FALSE, tallow = FALSE, saudit = TRUE, taudit = TRUE; + dbus_bool_t string_alloced = FALSE; + unsigned long pid; + int len, res, serrno = 0, terrno = 0; + char *qstr = NULL; + ssize_t qsize; + uint32_t sperm = AA_DBUS_SEND, tperm = AA_DBUS_RECEIVE; + + if (!apparmor_enabled) + return TRUE; + + _dbus_assert (sender != NULL); + + scon = bus_connection_get_apparmor_confinement (sender); + + if (proposed_recipient) + tcon = bus_connection_get_apparmor_confinement (proposed_recipient); + else + { + tcon = bus_con; + bus_apparmor_confinement_ref (tcon); + } + + /* map reply messages: "error" and "method_return" to initial send and + * receive. That is permission to receive a message from X grants + * permission to reply to X. And permission to send a message to Y + * grants permission to receive a reply from Y + */ + if (strcmp(msgtype, "error") == 0 || strcmp(msgtype, "method_return") == 0) + { + /* ignore reply messages and let dbus reply mapping handle them + * as the send was already allowed + */ + sallow = TRUE; + tallow = TRUE; + goto out; + } + + /* do we want to include the msgtype in the encoding ??? what of tpid + * so we can do conditional object owner perms + */ + if (is_unconfined(scon->context, scon->mode)) + { + sallow = TRUE; + saudit = FALSE; + } + else + { + qsize = build_query (&qstr, scon->context, bustype, destination, + tcon->context, path, interface, method); + if (qsize == -1) + goto oom; + + res = aa_query_label (sperm, qstr, qsize, &sallow, &saudit); + free(qstr); + if (res == -1) + { + serrno = errno; + goto audit; + } + } + + if (is_unconfined(tcon->context, tcon->mode)) + { + tallow = TRUE; + taudit = FALSE; + } + else + { + qsize = build_query (&qstr, tcon->context, bustype, source, + scon->context, path, interface, method); + if (qsize == -1) + goto oom; + + res = aa_query_label (tperm, qstr, qsize, &tallow, &taudit); + free(qstr); + if (res == -1) + { + terrno = errno; + goto audit; + } + } + + /* Don't fail operations on profiles in complain mode */ + if (modestr_to_complain(scon->mode)) + sallow = TRUE; + if (modestr_to_complain(tcon->mode)) + tallow = TRUE; + + if (!saudit && !taudit) + 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 (path && !_dbus_append_pair_str(&auxdata, "path", path)) + goto oom; + + if (interface && !_dbus_append_pair_str(&auxdata, "interface", interface)) + goto oom; + + if (method && !_dbus_append_pair_str(&auxdata, "member", method)) + goto oom; + + if (error_name && !_dbus_append_pair_str(&auxdata, "error_name", error_name)) + goto oom; + + len = _dbus_string_get_length(&auxdata); + + if (saudit) + { + if (!_dbus_append_mask(&auxdata, sperm)) + goto oom; + + if (destination && !_dbus_append_pair_str(&auxdata, "name", destination)) + goto oom; + + if (sender && dbus_connection_get_unix_process_id (sender, &pid) && + !_dbus_append_pair_uint(&auxdata, "pid", pid)) + goto oom; + + if (scon->context && + !_dbus_append_pair_str(&auxdata, "profile", scon->context)) + goto oom; + + if (proposed_recipient && + dbus_connection_get_unix_process_id (proposed_recipient, &pid) && + !_dbus_append_pair_uint(&auxdata, "peer_pid", pid)) + goto oom; + + if (tcon->context && + !_dbus_append_pair_str(&auxdata, "peer_profile", tcon->context)) + goto oom; + + if (serrno && !_dbus_append_pair_str(&auxdata, "info", strerror(serrno))) + goto oom; + + if (terrno && + !_dbus_append_pair_str(&auxdata, "peer_info", strerror(terrno))) + goto oom; + + log_message(sallow, msgtype, &auxdata); + } + if (taudit) + { + _dbus_string_set_length(&auxdata, len); + + if (source && !_dbus_append_pair_str(&auxdata, "name", source)) + goto oom; + + if (!_dbus_append_mask(&auxdata, tperm)) + goto oom; + + if (proposed_recipient && + dbus_connection_get_unix_process_id (proposed_recipient, &pid) && + !_dbus_append_pair_uint(&auxdata, "pid", pid)) + goto oom; + + if (tcon->context && + !_dbus_append_pair_str(&auxdata, "profile", tcon->context)) + goto oom; + + if (sender && dbus_connection_get_unix_process_id (sender, &pid) && + !_dbus_append_pair_uint(&auxdata, "peer_pid", pid)) + goto oom; + + if (scon->context && + !_dbus_append_pair_str(&auxdata, "peer_profile", scon->context)) + goto oom; + + if (terrno && !_dbus_append_pair_str(&auxdata, "info", strerror(terrno))) + goto oom; + + if (serrno && + !_dbus_append_pair_str(&auxdata, "peer_info", strerror(serrno))) + goto oom; + + log_message(tallow, msgtype, &auxdata); + } + + out: + if (scon != NULL) + bus_apparmor_confinement_unref (scon); + if (tcon != NULL) + bus_apparmor_confinement_unref (tcon); + if (string_alloced) + _dbus_string_free (&auxdata); + + return sallow && tallow; + + oom: + BUS_SET_OOM (error); + sallow = FALSE; + tallow = FALSE; + goto out; + +#else + return TRUE; +#endif /* HAVE_APPARMOR */ +} + Index: dbus-1.6.12/bus/apparmor.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ dbus-1.6.12/bus/apparmor.h 2013-10-10 10:38:55.000000000 -0700 @@ -0,0 +1,63 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * apparmor.c AppArmor security checks for D-Bus + * + * Authors: John Johansen + * Tyler Hicks + * Based on: selinux.c by Matthew Rickard + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef BUS_APPARMOR_H +#define BUS_APPARMOR_H + +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); + +void bus_apparmor_confinement_unref (BusAppArmorConfinement *confinement); +void bus_apparmor_confinement_ref (BusAppArmorConfinement *confinement); +BusAppArmorConfinement* +bus_apparmor_init_connection_confinement (DBusConnection *connection, + DBusError *error); + +dbus_bool_t +bus_apparmor_allows_acquire_service (DBusConnection *connection, + BusSELinuxID *service_sid, + const char *bustype, + const char *service_name, + DBusError *error); +dbus_bool_t +bus_apparmor_allows_send (DBusConnection *sender, + DBusConnection *proposed_recipient, + const char *msgtype, + const char *bustype, + const char *path, + const char *interface, + const char *member, + const char *error_name, + const char *destination, + const char *source, + DBusError *error); + + +#endif /* BUS_APPARMOR_H */ Index: dbus-1.6.12/bus/bus.c =================================================================== --- dbus-1.6.12.orig/bus/bus.c 2012-06-06 03:45:55.000000000 -0700 +++ dbus-1.6.12/bus/bus.c 2013-10-10 09:52:39.000000000 -0700 @@ -34,6 +34,7 @@ #include "config-parser.h" #include "signals.h" #include "selinux.h" +#include "apparmor.h" #include "dir-watch.h" #include #include @@ -897,6 +898,21 @@ bus_context_new (const DBusString *confi bus_context_log (context, DBUS_SYSTEM_LOG_FATAL, "SELinux enabled but AVC 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); @@ -924,6 +940,9 @@ bus_context_new (const DBusString *confi /* 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); @@ -1407,7 +1426,7 @@ bus_context_check_security_policy (BusCo DBusMessage *message, DBusError *error) { - const char *dest; + const char *src, *dest; BusClientPolicy *sender_policy; BusClientPolicy *recipient_policy; dbus_int32_t toggles; @@ -1416,6 +1435,7 @@ bus_context_check_security_policy (BusCo dbus_bool_t requested_reply; type = dbus_message_get_type (message); + src = dbus_message_get_sender (message); dest = dbus_message_get_destination (message); /* dispatch.c was supposed to ensure these invariants */ @@ -1470,6 +1490,32 @@ bus_context_check_security_policy (BusCo } return FALSE; + } + /* next verify AppArmor access controls. If allowed then + * go on with the standard checks. + */ + if (!bus_apparmor_allows_send (sender, proposed_recipient, + bus_context_get_type(context), + dbus_message_type_to_string (dbus_message_get_type (message)), + dbus_message_get_path (message), + dbus_message_get_interface (message), + dbus_message_get_member (message), + dbus_message_get_error_name (message), + dest ? dest : DBUS_SERVICE_DBUS, + src ? src : DBUS_SERVICE_DBUS, + error)) + { + if (error != NULL && !dbus_error_is_set (error)) + { + /* apparmor should have written to audit log or syslog */ + complain_about_message (context, DBUS_ERROR_ACCESS_DENIED, + "An AppArmor policy prevents this sender from sending this " + "message to this recipient", + 0, message, sender, proposed_recipient, FALSE, FALSE, error); + _dbus_verbose ("AppArmor security check denying send to service\n"); + } + + return FALSE; } if (bus_connection_is_active (sender)) Index: dbus-1.6.12/bus/main.c =================================================================== --- dbus-1.6.12.orig/bus/main.c 2013-06-05 09:40:34.000000000 -0700 +++ dbus-1.6.12/bus/main.c 2013-10-10 09:52:39.000000000 -0700 @@ -39,6 +39,7 @@ #include /* for write() and STDERR_FILENO */ #endif #include "selinux.h" +#include "apparmor.h" static BusContext *context; @@ -602,6 +603,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, @@ -642,6 +649,7 @@ main (int argc, char **argv) bus_context_shutdown (context); bus_context_unref (context); bus_selinux_shutdown (); + bus_apparmor_shutdown (); return 0; } Index: dbus-1.6.12/bus/services.c =================================================================== --- dbus-1.6.12.orig/bus/services.c 2012-08-13 11:08:25.000000000 -0700 +++ dbus-1.6.12/bus/services.c 2013-10-10 09:52:39.000000000 -0700 @@ -36,6 +36,7 @@ #include "policy.h" #include "bus.h" #include "selinux.h" +#include "apparmor.h" struct BusService { @@ -455,6 +456,28 @@ bus_registry_acquire_service (BusRegistr bus_connection_is_active (connection) ? bus_connection_get_name (connection) : "(inactive)", + _dbus_string_get_const_data (service_name)); + goto out; + } + + if (!bus_apparmor_allows_acquire_service (connection, sid, + (registry->context ? + bus_context_get_type(registry->context) : NULL), + _dbus_string_get_const_data (service_name), error)) + { + + if (dbus_error_is_set (error) && + dbus_error_has_name (error, DBUS_ERROR_NO_MEMORY)) + { + goto out; + } + + dbus_set_error (error, DBUS_ERROR_ACCESS_DENIED, + "Connection \"%s\" is not allowed to own the service \"%s\" due " + "to AppArmor policy", + bus_connection_is_active (connection) ? + bus_connection_get_name (connection) : + "(inactive)", _dbus_string_get_const_data (service_name)); goto out; } Index: dbus-1.6.12/bus/connection.c =================================================================== --- dbus-1.6.12.orig/bus/connection.c 2012-08-13 11:08:25.000000000 -0700 +++ dbus-1.6.12/bus/connection.c 2013-10-10 09:52:39.000000000 -0700 @@ -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 (BusCon 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 (BusCon 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, @@ -1107,6 +1129,19 @@ bus_connection_get_selinux_id (DBusConne return d->selinux_id; } +BusAppArmorConfinement* +bus_connection_get_apparmor_confinement (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + _dbus_assert (d != NULL); + + bus_apparmor_confinement_ref (d->apparmor_confinement); + return d->apparmor_confinement; +} + /** * Checks whether the connection is registered with the message bus. * Index: dbus-1.6.12/bus/bus.h =================================================================== --- dbus-1.6.12.orig/bus/bus.h 2012-06-06 03:45:55.000000000 -0700 +++ dbus-1.6.12/bus/bus.h 2013-10-10 09:52:39.000000000 -0700 @@ -38,6 +38,7 @@ typedef struct BusClientPolicy BusClien 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; Index: dbus-1.6.12/bus/connection.h =================================================================== --- dbus-1.6.12.orig/bus/connection.h 2012-06-06 03:45:55.000000000 -0700 +++ dbus-1.6.12/bus/connection.h 2013-10-10 09:52:39.000000000 -0700 @@ -52,6 +52,7 @@ BusActivation* bus_connection_get_activ BusMatchmaker* bus_connection_get_matchmaker (DBusConnection *connection); const char * bus_connection_get_loginfo (DBusConnection *connection); BusSELinuxID* bus_connection_get_selinux_id (DBusConnection *connection); +BusAppArmorConfinement* bus_connection_get_apparmor_confinement (DBusConnection *connection); dbus_bool_t bus_connections_check_limits (BusConnections *connections, DBusConnection *requesting_completion, DBusError *error); Index: dbus-1.6.12/cmake/bus/CMakeLists.txt =================================================================== --- dbus-1.6.12.orig/cmake/bus/CMakeLists.txt 2013-02-05 06:37:48.000000000 -0800 +++ dbus-1.6.12/cmake/bus/CMakeLists.txt 2013-10-10 09:52:39.000000000 -0700 @@ -42,6 +42,8 @@ set (DIR_WATCH_SOURCE ) set (BUS_SOURCES ${BUS_DIR}/activation.c ${BUS_DIR}/activation.h + ${BUS_DIR}/apparmor.h + ${BUS_DIR}/apparmor.c ${BUS_DIR}/bus.c ${BUS_DIR}/bus.h ${BUS_DIR}/config-parser.c Index: dbus-1.6.12/bus/config-parser.c =================================================================== --- dbus-1.6.12.orig/bus/config-parser.c 2013-02-12 03:45:32.000000000 -0800 +++ dbus-1.6.12/bus/config-parser.c 2013-10-10 09:52:39.000000000 -0700 @@ -28,6 +28,7 @@ #include "utils.h" #include "policy.h" #include "selinux.h" +#include "apparmor.h" #include #include #include @@ -1120,6 +1121,27 @@ start_busconfig_child (BusConfigParser return TRUE; } + else if (element_type == ELEMENT_APPARMOR) + { + Element *e; + const char *mode; + + if ((e = push_element (parser, ELEMENT_APPARMOR)) == NULL) + { + BUS_SET_OOM (error); + return FALSE; + } + + if (!locate_attributes (parser, "apparmor", + attribute_names, + attribute_values, + error, + "mode", &mode, + NULL)) + return FALSE; + + return bus_apparmor_set_mode_from_config (mode, error); + } else { dbus_set_error (error, DBUS_ERROR_FAILED, @@ -2052,6 +2074,7 @@ bus_config_parser_end_element (BusConfig case ELEMENT_STANDARD_SESSION_SERVICEDIRS: case ELEMENT_STANDARD_SYSTEM_SERVICEDIRS: case ELEMENT_ALLOW_ANONYMOUS: + case ELEMENT_APPARMOR: break; } @@ -2351,6 +2374,7 @@ bus_config_parser_content (BusConfigPars case ELEMENT_ALLOW_ANONYMOUS: case ELEMENT_SELINUX: case ELEMENT_ASSOCIATE: + case ELEMENT_APPARMOR: if (all_whitespace (content)) return TRUE; else Index: dbus-1.6.12/bus/config-parser-common.c =================================================================== --- dbus-1.6.12.orig/bus/config-parser-common.c 2012-06-06 03:45:55.000000000 -0700 +++ dbus-1.6.12/bus/config-parser-common.c 2013-10-10 09:52:39.000000000 -0700 @@ -127,6 +127,10 @@ bus_config_parser_element_name_to_type ( { return ELEMENT_ALLOW_ANONYMOUS; } + else if (strcmp (name, "apparmor") == 0) + { + return ELEMENT_APPARMOR; + } return ELEMENT_NONE; } @@ -181,6 +185,8 @@ bus_config_parser_element_type_to_name ( return "keep_umask"; case ELEMENT_ALLOW_ANONYMOUS: return "allow_anonymous"; + case ELEMENT_APPARMOR: + return "apparmor"; } _dbus_assert_not_reached ("bad element type"); Index: dbus-1.6.12/bus/config-parser-common.h =================================================================== --- dbus-1.6.12.orig/bus/config-parser-common.h 2012-06-06 03:45:55.000000000 -0700 +++ dbus-1.6.12/bus/config-parser-common.h 2013-10-10 09:52:39.000000000 -0700 @@ -49,7 +49,8 @@ typedef enum ELEMENT_STANDARD_SYSTEM_SERVICEDIRS, ELEMENT_KEEP_UMASK, ELEMENT_SYSLOG, - ELEMENT_ALLOW_ANONYMOUS + ELEMENT_ALLOW_ANONYMOUS, + ELEMENT_APPARMOR, } ElementType; ElementType bus_config_parser_element_name_to_type (const char *element_name); Index: dbus-1.6.12/doc/busconfig.dtd =================================================================== --- dbus-1.6.12.orig/doc/busconfig.dtd 2012-06-06 03:45:55.000000000 -0700 +++ dbus-1.6.12/doc/busconfig.dtd 2013-10-10 09:52:39.000000000 -0700 @@ -11,7 +11,8 @@ include | policy | limit | - selinux)*> + selinux | + apparmor)*> @@ -63,3 +64,7 @@ + + + Index: dbus-1.6.12/doc/dbus-daemon.1.in =================================================================== --- dbus-1.6.12.orig/doc/dbus-daemon.1.in 2012-08-13 11:08:25.000000000 -0700 +++ dbus-1.6.12/doc/dbus-daemon.1.in 2013-10-10 09:52:39.000000000 -0700 @@ -648,6 +648,20 @@ Right now the default will be the securi If two elements specify the same name, the element appearing later in the configuration file will be used. +.TP +.I "" + +.PP +The element is used to configure AppArmor mediation of D\-Bus +messages. It can contain one attibute that specifies if mediation is enabled: +.nf + +.fi +The default mode is is "enabled". In "enabled" mode, AppArmor mediation will be +enabled if AppArmor support is available. In "disabled" mode, AppArmor +mediation is disabled. In "required" mode, AppArmor mediation will be enabled +if AppArmor support is available, otherwise D\-Bus will not start. + .SH SELinux .PP @@ -713,6 +727,36 @@ If a name has no security context associ configuration file, the security context of the bus daemon itself will be used. +.SH AppArmor + +.PP +The AppArmor confinement context is stored when applications connect to D\-Bus. +The confinement context consists of a label and a confinement mode. When a +security decision is required, D\-Bus uses the label to query the AppArmor +policy to determine if the action should be allowed, denied, and/or audited. + +.PP +D\-Bus performs AppArmor security checks in two places. + +.PP +First, any time a message is routed from one connection to another +connection, the bus daemon will check permissions with the label of the first +connection as source, label and/or connection name of the second connection as +target, along with the bus name, the path name, the interface name, and the +member name. Reply messages, such as method_return and error messages, are +implicity allowed if they are in response to a message that has already been +allowed. + +.PP +Second, any time a connection asks to own a name, the bus daemon will check +permissions with the label of the connection as source, the requested name as +target, along with the bus name. + +.PP +AppArmor rules for D\-Bus mediation are not stored in the bus configuration +files. They are stored in the application's AppArmor profile. Please see the +AppArmor documentation for more details. + .SH DEBUGGING .PP Index: dbus-1.6.12/bus/test-main.c =================================================================== --- dbus-1.6.12.orig/bus/test-main.c 2012-06-06 03:45:55.000000000 -0700 +++ dbus-1.6.12/bus/test-main.c 2013-10-10 09:52:39.000000000 -0700 @@ -30,6 +30,7 @@ #include #include #include "selinux.h" +#include "apparmor.h" #ifdef DBUS_BUILD_TESTS static void @@ -65,6 +66,11 @@ test_pre_hook (void) || !bus_selinux_full_init ())) die ("could not init selinux support"); + if (_dbus_getenv ("DBUS_TEST_APPARMOR") + && (!bus_apparmor_pre_init () + || !bus_apparmor_full_init ())) + die ("could not init apparmor support"); + initial_fds = _dbus_check_fdleaks_enter (); } @@ -75,6 +81,10 @@ test_post_hook (void) { if (_dbus_getenv ("DBUS_TEST_SELINUX")) bus_selinux_shutdown (); + + if (_dbus_getenv ("DBUS_TEST_APPARMOR")) + bus_apparmor_shutdown (); + check_memleaks (progname); _dbus_check_fdleaks_leave (initial_fds); debian/patches/CVE-2014-3635.patch0000664000000000000000000001133312406314460013240 0ustar Description: fix buffer overrun via odd max_message_unix_fds Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=b1e9a2b4bd858b37c0bc02aa102b97530083a703 Origin: upstream, http://cgit.freedesktop.org/dbus/dbus/commit/?h=dbus-1.6&id=94b8d5e7a85bfb6c9a92b8e22e382b2e0ded2b59 Bug: https://bugs.freedesktop.org/show_bug.cgi?id=83622 Index: dbus-1.6.18/dbus/dbus-internals.h =================================================================== --- dbus-1.6.18.orig/dbus/dbus-internals.h 2013-04-22 10:10:32.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-internals.h 2014-09-17 10:13:38.930199752 -0400 @@ -372,7 +372,7 @@ #define _DBUS_PASTE(a, b) _DBUS_PASTE2 (a, b) #define _DBUS_STATIC_ASSERT(expr) \ typedef struct { char _assertion[(expr) ? 1 : -1]; } \ - _DBUS_PASTE (_DBUS_STATIC_ASSERT_, __LINE__) + _DBUS_PASTE (_DBUS_STATIC_ASSERT_, __LINE__) _DBUS_GNUC_UNUSED DBUS_END_DECLS Index: dbus-1.6.18/dbus/dbus-macros.h =================================================================== --- dbus-1.6.18.orig/dbus/dbus-macros.h 2013-04-22 10:10:32.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-macros.h 2014-09-17 10:13:38.930199752 -0400 @@ -69,9 +69,12 @@ __attribute__((__format__ (__printf__, format_idx, arg_idx))) #define _DBUS_GNUC_NORETURN \ __attribute__((__noreturn__)) +#define _DBUS_GNUC_UNUSED \ + __attribute__((__unused__)) #else /* !__GNUC__ */ #define _DBUS_GNUC_PRINTF( format_idx, arg_idx ) #define _DBUS_GNUC_NORETURN +#define _DBUS_GNUC_UNUSED #endif /* !__GNUC__ */ #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) Index: dbus-1.6.18/dbus/dbus-sysdeps-unix.c =================================================================== --- dbus-1.6.18.orig/dbus/dbus-sysdeps-unix.c 2013-09-16 08:57:59.000000000 -0400 +++ dbus-1.6.18/dbus/dbus-sysdeps-unix.c 2014-09-17 10:13:41.986199769 -0400 @@ -315,6 +315,12 @@ m.msg_control = alloca(m.msg_controllen); memset(m.msg_control, 0, m.msg_controllen); + /* Do not include the padding at the end when we tell the kernel + * how much we're willing to receive. This avoids getting + * the padding filled with additional fds that we weren't expecting, + * if a (potentially malicious) sender included them. (fd.o #83622) */ + m.msg_controllen = CMSG_LEN (*n_fds * sizeof(int)); + again: bytes_read = recvmsg(fd, &m, 0 @@ -354,18 +360,49 @@ for (cm = CMSG_FIRSTHDR(&m); cm; cm = CMSG_NXTHDR(&m, cm)) if (cm->cmsg_level == SOL_SOCKET && cm->cmsg_type == SCM_RIGHTS) { - unsigned i; - - _dbus_assert(cm->cmsg_len <= CMSG_LEN(*n_fds * sizeof(int))); - *n_fds = (cm->cmsg_len - CMSG_LEN(0)) / sizeof(int); + size_t i; + int *payload = (int *) CMSG_DATA (cm); + size_t payload_len_bytes = (cm->cmsg_len - CMSG_LEN (0)); + size_t payload_len_fds = payload_len_bytes / sizeof (int); + size_t fds_to_use; + + /* Every non-negative int fits in a size_t without truncation, + * and we already know that *n_fds is non-negative, so + * casting (size_t) *n_fds is OK */ + _DBUS_STATIC_ASSERT (sizeof (size_t) >= sizeof (int)); + + if (_DBUS_LIKELY (payload_len_fds <= (size_t) *n_fds)) + { + /* The fds in the payload will fit in our buffer */ + fds_to_use = payload_len_fds; + } + else + { + /* Too many fds in the payload. This shouldn't happen + * any more because we're setting m.msg_controllen to + * the exact number we can accept, but be safe and + * truncate. */ + fds_to_use = (size_t) *n_fds; + + /* Close the excess fds to avoid DoS: if they stayed open, + * someone could send us an extra fd per message + * and we'd eventually run out. */ + for (i = fds_to_use; i < payload_len_fds; i++) + { + close (payload[i]); + } + } - memcpy(fds, CMSG_DATA(cm), *n_fds * sizeof(int)); + memcpy (fds, payload, fds_to_use * sizeof (int)); found = TRUE; + /* This cannot overflow because we have chosen fds_to_use + * to be <= *n_fds */ + *n_fds = (int) fds_to_use; /* Linux doesn't tell us whether MSG_CMSG_CLOEXEC actually worked, hence we need to go through this list and set CLOEXEC everywhere in any case */ - for (i = 0; i < *n_fds; i++) + for (i = 0; i < fds_to_use; i++) _dbus_fd_set_close_on_exec(fds[i]); break; debian/patches/CVE-2015-0245.patch0000664000000000000000000000270612777426635013262 0ustar From f9697e04f1c9871cb54a99f087e97e4bb9e41e06 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 26 Jan 2015 20:09:56 +0000 Subject: CVE-2015-0245: prevent forged ActivationFailure from non-root processes Without either this rule or better checking in dbus-daemon, non-systemd processes can make dbus-daemon think systemd failed to activate a system service, resulting in an error reply back to the requester. This is redundant with the fix in the C code (which I consider to be the real solution), but is likely to be easier to backport. Bug: https://bugs.freedesktop.org/show_bug.cgi?id=88811 Reviewed-by: Alban Crequy Reviewed-by: David King Reviewed-by: Philip Withnall diff --git a/bus/system.conf.in b/bus/system.conf.in index 92f4cc4..851b9e6 100644 --- a/bus/system.conf.in +++ b/bus/system.conf.in @@ -68,6 +68,14 @@ + + + + + +