]> git.ipfire.org Git - thirdparty/dbus.git/commitdiff
bus: Raise file descriptor limit to match configuration
authorColin Walters <walters@verbum.org>
Mon, 31 Jan 2011 20:22:14 +0000 (15:22 -0500)
committerColin Walters <walters@verbum.org>
Thu, 3 Feb 2011 18:25:34 +0000 (13:25 -0500)
The default configuration has hardcoded 2048 complete connections,
and 64 incomplete.  We need at least that number of file descriptors,
plus some for internal use.

In the bus, attempt to call setrlimit() before we drop privileges.
Practically speaking for this means the system bus gets it, the
session bus doesn't.

http://bugs.freedesktop.org/show_bug.cgi?id=33474

Reviewed-By: Simon McVittie <simon.mcvittie@collabora.co.uk>
bus/bus.c
configure.in
dbus/dbus-sysdeps-util-unix.c
dbus/dbus-sysdeps-util-win.c
dbus/dbus-sysdeps.h

index f892e262a79594552746b460d47ff1e68ab8f858..6663347030a005abc4736e1c66ce9ba936e57a76 100644 (file)
--- 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))
index 08bd962dad4ddba02d2fefbe2d5b177ded709b59..e6b0fefa505200f296f54cf376dde0826b975e31 100644 (file)
@@ -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)])
index 6e0924584fa1a43e4abddde58e79991532df5154..02954d5c29388751d9bf91010e910dd1bc9839a8 100644 (file)
@@ -42,6 +42,9 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
 #include <grp.h>
 #include <sys/socket.h>
 #include <dirent.h>
@@ -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)
 {
index 2f21409221a092a310ce035c3c05dbd88b54ca77..f10100b63229a5a6853226c5e05b46a1e1720c36 100644 (file)
@@ -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)
 {
index 3955d82917292110eb7962339f07af204817052a..22d7969e4a60acf50b1ea647031b2b526e626f61 100644 (file)
@@ -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