diff options
Diffstat (limited to 'bus')
-rw-r--r-- | bus/activation.c | 28 | ||||
-rw-r--r-- | bus/bus.c | 50 | ||||
-rw-r--r-- | bus/bus.h | 1 |
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"); @@ -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); @@ -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, |