Package: release.debian.org Severity: normal Tags: wheezy User: release.debian....@packages.debian.org Usertags: pu
I would like to fix denial-of-service vulnerability CVE-2014-7824 in wheezy. The security team have indicated that they will not be issuing a DSA for this. It's the same vulnerability for which I just requested a 1.8.10 unblock, and basically the same patch (after fixing minor conflicts in a comment). Source debdiff attached. Thanks, S
diffstat for dbus-1.6.8 dbus-1.6.8 changelog | 11 dbus.init | 2 patches/0001-CVE-2014-7824-set-fd-rlimit-to-64k-for-the-system-db.patch | 426 ++++++++++ patches/series | 2 4 files changed, 440 insertions(+), 1 deletion(-) diff -Nru dbus-1.6.8/debian/changelog dbus-1.6.8/debian/changelog --- dbus-1.6.8/debian/changelog 2014-09-15 19:49:38.000000000 +0100 +++ dbus-1.6.8/debian/changelog 2014-11-06 16:36:28.000000000 +0000 @@ -1,3 +1,14 @@ +dbus (1.6.8-1+deb7u5) wheezy; urgency=medium + + * Fix CVE-2014-7824: + - Start 'dbus-daemon --system' as root under sysvinit (it already + starts as root under systemd), so it can increase its file + descriptor limit + - Add patch from upstream to increase dbus-daemon's file descriptor + limit to 65536, completing the incomplete fix for CVE-2014-3636 + + -- Simon McVittie <s...@debian.org> Thu, 06 Nov 2014 16:31:34 +0000 + dbus (1.6.8-1+deb7u4) wheezy-security; urgency=high * Fix several security issues diff -Nru dbus-1.6.8/debian/dbus.init dbus-1.6.8/debian/dbus.init --- dbus-1.6.8/debian/dbus.init 2014-09-15 19:49:38.000000000 +0100 +++ dbus-1.6.8/debian/dbus.init 2014-11-06 16:36:28.000000000 +0000 @@ -69,7 +69,7 @@ log_daemon_msg "Starting $DESC" "$NAME" start-stop-daemon --start --quiet --pidfile $PIDFILE \ - --user $DAEMONUSER --exec $DAEMON -- --system $PARAMS + --exec $DAEMON -- --system $PARAMS log_end_msg $? } diff -Nru dbus-1.6.8/debian/patches/0001-CVE-2014-7824-set-fd-rlimit-to-64k-for-the-system-db.patch dbus-1.6.8/debian/patches/0001-CVE-2014-7824-set-fd-rlimit-to-64k-for-the-system-db.patch --- dbus-1.6.8/debian/patches/0001-CVE-2014-7824-set-fd-rlimit-to-64k-for-the-system-db.patch 1970-01-01 01:00:00.000000000 +0100 +++ dbus-1.6.8/debian/patches/0001-CVE-2014-7824-set-fd-rlimit-to-64k-for-the-system-db.patch 2014-11-06 16:36:28.000000000 +0000 @@ -0,0 +1,426 @@ +From 68cb9ead957314b30e604018f2dd5b0fc3b2127c Mon Sep 17 00:00:00 2001 +From: Simon McVittie <simon.mcvit...@collabora.co.uk> +Date: Tue, 4 Nov 2014 14:41:54 +0000 +Subject: [PATCH] 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 <alban.cre...@collabora.co.uk> +Conflicts: + dbus/dbus-sysdeps-util-unix.c +--- + bus/activation.c | 28 +++++++- + bus/bus.c | 50 ++++++++++++--- + bus/bus.h | 1 + + dbus/dbus-sysdeps-util-unix.c | 145 +++++++++++++++++++++++++++++++++--------- + dbus/dbus-sysdeps-util-win.c | 35 +++++++++- + dbus/dbus-sysdeps.h | 11 +++- + 6 files changed, 227 insertions(+), 43 deletions(-) + +diff --git a/bus/activation.c b/bus/activation.c +index 280cc01..b636868 100644 +--- a/bus/activation.c ++++ b/bus/activation.c +@@ -1683,6 +1683,31 @@ out: + 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 @@ bus_activation_activate_service (BusActivation *activation, + + 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"); +diff --git a/bus/bus.c b/bus/bus.c +index c4eadc2..a8b153b 100644 +--- a/bus/bus.c ++++ b/bus/bus.c +@@ -64,6 +64,7 @@ struct BusContext + BusPolicy *policy; + BusMatchmaker *matchmaker; + BusLimits limits; ++ DBusRLimit *initial_fd_limit; + unsigned int fork : 1; + unsigned int syslog : 1; + unsigned int keep_umask : 1; +@@ -647,19 +648,38 @@ oom: + 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); ++ ++ 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; ++ } + +- _dbus_request_file_descriptor_limit (limit); ++ /* 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 +@@ -1118,6 +1138,10 @@ bus_context_unref (BusContext *context) + + 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); +@@ -1282,6 +1306,12 @@ bus_context_get_reply_timeout (BusContext *context) + 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); + +diff --git a/bus/bus.h b/bus/bus.h +index 7d0b369..dac6ea5 100644 +--- a/bus/bus.h ++++ b/bus/bus.h +@@ -116,6 +116,7 @@ int bus_context_get_max_services_per_connection (BusContext + 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, +diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c +index bbc3f34..4134f2a 100644 +--- a/dbus/dbus-sysdeps-util-unix.c ++++ b/dbus/dbus-sysdeps-util-unix.c +@@ -373,53 +373,140 @@ _dbus_change_to_daemon_user (const char *user, + } + #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; ++ { ++ dbus_set_error (error, _dbus_error_from_errno (errno), ++ "Failed to get fd limit: %s", _dbus_strerror (errno)); ++ return FALSE; ++ } + +- if (lim.rlim_cur >= limit) +- return; ++ 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 +diff --git a/dbus/dbus-sysdeps-util-win.c b/dbus/dbus-sysdeps-util-win.c +index 111db9e..fe29b90 100644 +--- a/dbus/dbus-sysdeps-util-win.c ++++ b/dbus/dbus-sysdeps-util-win.c +@@ -256,9 +256,42 @@ _dbus_change_to_daemon_user (const char *user, + 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 +diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h +index 64b6363..61dd52d 100644 +--- a/dbus/dbus-sysdeps.h ++++ b/dbus/dbus-sysdeps.h +@@ -525,8 +525,6 @@ dbus_bool_t _dbus_change_to_daemon_user (const char *user, + + 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 @@ _dbus_replace_install_prefix (const char *configure_time_path); + */ + #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 +-- +2.1.3 + diff -Nru dbus-1.6.8/debian/patches/series dbus-1.6.8/debian/patches/series --- dbus-1.6.8/debian/patches/series 2014-09-15 19:49:38.000000000 +0100 +++ dbus-1.6.8/debian/patches/series 2014-11-06 16:36:28.000000000 +0000 @@ -13,3 +13,5 @@ 0007-DBusConnection-implements-_dbus_connection_set_pendi.patch 0008-bus-enforce-pending_fd_timeout.patch 0010-_dbus_read_socket_with_unix_fds-do-not-accept-extra-.patch + +0001-CVE-2014-7824-set-fd-rlimit-to-64k-for-the-system-db.patch