diff options
author | Simon McVittie <smcv@debian.org> | 2016-07-21 08:24:38 +0100 |
---|---|---|
committer | Simon McVittie <smcv@debian.org> | 2016-08-12 10:58:38 +0100 |
commit | f518165b84436db0b3bd856778509f0ce6e93063 (patch) | |
tree | b9e89388325262e6eaf8228bc0d615f5e02f04a5 | |
parent | ed33129fe4a71721d829d0e19286b73f77e747f5 (diff) | |
download | dbus-f518165b84436db0b3bd856778509f0ce6e93063.tar.gz |
dbus-daemon, dbus-launch: cope with callers having closed standard fds
In Debian bug <https://bugs.debian.org/829348>, lightdm appears to
have been starting dbus-launch with at least one of the three
standard fds 0, 1, 2 (stdin, stdout, stderr) closed. This resulted
in the dbus-daemon's epoll_create1() returning a fd less than 3.
Later, _dbus_become_daemon() replaces fds 0-2 with /dev/null. As a
result, a subsequent call to _dbus_loop_add_watch() for the reload
pipe resulted in calling epoll_ctl on the non-epoll fd pointing to
/dev/null, which fails with EINVAL, resulting in the dbus-daemon
exiting unsuccessfully.
Unix programs are not normally expected to behave correctly when
launched with the standard fds not already open; but at the same time,
X11 autolaunching means that dbus-launch (and hence the dbus-daemon)
can get started from an arbitrarily precarious situation.
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=97008
Signed-off-by: Simon McVittie <smcv@debian.org>
Reviewed-by: Thiago Macieira <thiago@kde.org>
(cherry picked from commit c8f73a2a3a9d9d10587f596a62ebb64e8963197e)
-rw-r--r-- | bus/main.c | 25 | ||||
-rw-r--r-- | tools/dbus-launch.c | 19 |
2 files changed, 42 insertions, 2 deletions
@@ -42,6 +42,10 @@ #include "apparmor.h" #include "audit.h" +#ifdef DBUS_UNIX +#include <dbus/dbus-sysdeps-unix.h> +#endif + static BusContext *context; #ifdef DBUS_UNIX @@ -378,6 +382,27 @@ main (int argc, char **argv) dbus_bool_t print_address; dbus_bool_t print_pid; BusContextFlags flags; +#ifdef DBUS_UNIX + const char *error_str; + + /* Redirect stdin from /dev/null since we will never need it, and + * redirect stdout and stderr to /dev/null if not already open. + * + * We should do this as the very first thing, to ensure that when we + * create other file descriptors (for example for epoll, inotify or + * a socket), they never get assigned as fd 0, 1 or 2. If they were, + * which could happen if our caller had (incorrectly) closed those + * standard fds, they'd get closed when we daemonize - for example, + * closing our listening socket would stop us listening, and closing + * a Linux epoll socket would cause the main loop to fail. */ + if (!_dbus_ensure_standard_fds (DBUS_FORCE_STDIN_NULL, &error_str)) + { + fprintf (stderr, + "dbus-daemon: fatal error setting up standard fds: %s: %s\n", + error_str, _dbus_strerror (errno)); + return 1; + } +#endif if (!_dbus_string_init (&config_file)) return 1; diff --git a/tools/dbus-launch.c b/tools/dbus-launch.c index 0f1e6ede..80e4a241 100644 --- a/tools/dbus-launch.c +++ b/tools/dbus-launch.c @@ -842,10 +842,25 @@ main (int argc, char **argv) char *config_file; dbus_bool_t user_bus_supported = FALSE; DBusString user_bus; - + const char *error_str; + exit_with_session = FALSE; config_file = NULL; - + + /* Ensure that the first three fds are open, to ensure that when we + * create other file descriptors (for example for epoll, inotify or + * a socket), they never get assigned as fd 0, 1 or 2. If they were, + * which could happen if our caller had (incorrectly) closed those + * standard fds, then we'd start dbus-daemon with those fds closed, + * which is unexpected and could cause it to misbehave. */ + if (!_dbus_ensure_standard_fds (0, &error_str)) + { + fprintf (stderr, + "dbus-launch: fatal error setting up standard fds: %s: %s\n", + error_str, _dbus_strerror (errno)); + return 1; + } + prev_arg = NULL; i = 1; while (i < argc) |