diff --git a/bus/bus.c b/bus/bus.c index f892e262..66633470 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -644,6 +644,24 @@ oom: return FALSE; } +static void +raise_file_descriptor_limit (BusContext *context) +{ + + /* 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; + + limit = context->limits.max_completed_connections + + context->limits.max_incomplete_connections + + arbitrary_extra_fds; + + _dbus_request_file_descriptor_limit (limit); +} + static dbus_bool_t process_config_postinit (BusContext *context, BusConfigParser *parser, @@ -652,6 +670,8 @@ process_config_postinit (BusContext *context, DBusHashTable *service_context_table; DBusList *watched_dirs = NULL; + raise_file_descriptor_limit (context); + service_context_table = bus_config_parser_steal_service_context_table (parser); if (!bus_registry_set_service_context_table (context->registry, service_context_table)) diff --git a/configure.in b/configure.in index 08bd962d..e6b0fefa 100644 --- a/configure.in +++ b/configure.in @@ -532,6 +532,8 @@ closedir(dirp); fi fi +AC_CHECK_HEADERS(sys/resource.h) + AC_CHECK_HEADERS(dirent.h) AC_CHECK_HEADERS(execinfo.h, [AC_CHECK_FUNCS(backtrace)]) diff --git a/dbus/dbus-sysdeps-util-unix.c b/dbus/dbus-sysdeps-util-unix.c index 6e092458..02954d5c 100644 --- a/dbus/dbus-sysdeps-util-unix.c +++ b/dbus/dbus-sysdeps-util-unix.c @@ -42,6 +42,9 @@ #include #include #include +#ifdef HAVE_SYS_RESOURCE_H +#include +#endif #include #include #include @@ -369,6 +372,56 @@ _dbus_change_to_daemon_user (const char *user, } #endif /* !HAVE_LIBAUDIT */ + +/** + * 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 + */ +void +_dbus_request_file_descriptor_limit (unsigned int limit) +{ +#ifdef HAVE_SETRLIMIT + struct rlimit lim; + struct rlimit target_lim; + unsigned int current_limit; + + /* 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. + */ + if (getuid () != 0) + return; + + if (getrlimit (RLIMIT_NOFILE, &lim) < 0) + return; + + if (lim.rlim_cur >= limit) + return; + + /* 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); +#endif +} + void _dbus_init_system_log (void) { diff --git a/dbus/dbus-sysdeps-util-win.c b/dbus/dbus-sysdeps-util-win.c index 2f214092..f10100b6 100644 --- a/dbus/dbus-sysdeps-util-win.c +++ b/dbus/dbus-sysdeps-util-win.c @@ -256,6 +256,11 @@ _dbus_change_to_daemon_user (const char *user, return TRUE; } +void +_dbus_request_file_descriptor_limit (unsigned int limit) +{ +} + void _dbus_init_system_log (void) { diff --git a/dbus/dbus-sysdeps.h b/dbus/dbus-sysdeps.h index 3955d829..22d7969e 100644 --- a/dbus/dbus-sysdeps.h +++ b/dbus/dbus-sysdeps.h @@ -517,6 +517,8 @@ 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