summaryrefslogtreecommitdiff
path: root/bus
diff options
context:
space:
mode:
authorSimon McVittie <simon.mcvittie@collabora.co.uk>2014-11-04 14:41:54 +0000
committerSimon McVittie <simon.mcvittie@collabora.co.uk>2014-11-06 15:31:07 +0000
commit4e466446d27f1a3991c22307a47a81c9e93e530d (patch)
tree5e5b27972b0246ef93f9baab230cdfb042dba8e6 /bus
parent8874d3a0c57c0cae97cbe426e3686936da53f649 (diff)
downloaddbus-4e466446d27f1a3991c22307a47a81c9e93e530d.tar.gz
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.crequy@collabora.co.uk>
Diffstat (limited to 'bus')
-rw-r--r--bus/activation.c28
-rw-r--r--bus/bus.c50
-rw-r--r--bus/bus.h1
3 files changed, 68 insertions, 11 deletions
diff --git a/bus/activation.c b/bus/activation.c
index 149cca8a..ecd19bb4 100644
--- a/bus/activation.c
+++ b/bus/activation.c
@@ -1688,6 +1688,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,
@@ -2121,7 +2146,8 @@ bus_activation_activate_service (BusActivation *activation,
service_name,
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 35d40754..47cc3452 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;
@@ -659,19 +660,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
@@ -1130,6 +1150,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);
@@ -1294,6 +1318,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 7d0b3697..dac6ea5e 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,