[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Proposed mass bug filing: use and misuse of dbus-launch (dbus-x11)



I'm planning to do a mass-bug-filing against packages that mention
dbus-x11 in their dependencies, or dbus-launch in their code, asking
maintainers to adjust their dependencies to make dbus-x11 optional.
My goal is that users can install the major desktop tasks in stretch
(GNOME, KDE, etc.) with either one of dbus-user-session or dbus-x11,
defaulting to dbus-user-session for new installations.

I'm deliberately not doing a dd-list yet because there's an open
question about the order of preference, but the affected source
packages are basically
<https://codesearch.debian.net/search?q=dbus-%28x11|launch%29>
(minus some false positives that just mention dbus-launch or dbus-x11
without any technical effect). I'll re-post this with a dd-list when
there's something like consensus.

The tl;dr version:

* I think we should default to dbus-user-session for stretch on Linux.
* dbus-launch (dbus-x11) without dbus-user-session should continue to
  be supported, but should be a non-default configuration on Linux.
* On kFreeBSD and Hurd, dbus-launch is still the best we can do.
* Regression tests should use dbus-run-session, not dbus-launch,
  on all kernels.
* Fallback plan: make it possible for early adopters to use
  dbus-user-session instead of dbus-launch, but keep dbus-launch the
  default for new installs even on Linux, and reconsider for stretch+1.

Background: ways you might get a session bus
============================================

As of current stable, the correct way to start a "production"
D-Bus session in Debian was for /etc/X11/Xsession.d to invoke
dbus-launch(1). This would result in a session bus (dbus-daemon) per
X11 display, and is set up by the dbus-x11 package. The dbus-daemon
terminates when the X11 display does.

dbus 1.10 in testing/unstable introduces a new way for systemd users
to get a D-Bus session bus per uid (the *user bus*), shared between
all parallel logins whether they are X11, Wayland, Mir, text or
non-interactive. This is not 100% compatible with traditional practice,
particularly if you have two or more parallel X11 logins with the same uid
(GNOME's gdm won't do that, but some other display managers do), which
is why it is "opt-in". In Debian, this is not done by default, but can be
activated by installing the dbus-user-session package. In this case the
dbus-daemon terminates when "systemd --user" does, which is when the uid
responsible for this dbus-daemon ends their last parallel login session.

Some desktop environment core components, such as GNOME's gnome-session,
will automatically start a session bus per login session using
dbus-launch if there is not already one available. I believe GNOME on
Wayland currently relies on this mechanism if dbus-user-session is not
installed. This session bus terminates when the X11 display does (in the
case of GNOME on Wayland, the X11 display is XWayland, and terminates
when gnome-shell does). Similarly, regression tests sometimes start a
fake X11 display (Xvfb) and run dbus-launch scoped to that X11 display.

Another possible way to get a session bus is to run dbus-run-session(1),
or run dbus-daemon directly (typically using its --print-address
option). This is frequently done by regression tests. In this case,
a dbus-daemon started by dbus-run-session is terminated when
dbus-run-session's child process terminates, and a directly-run
dbus-daemon must be killed by the test script at the appropriate time.

Finally, if you start a program that uses D-Bus with no session bus
running, and you have an X11 display, the D-Bus library (typically
libdbus or GLib's GDBus) will attempt "X11 autolaunching": the program
forks and execs dbus-launch in a special "autolaunching" mode, and the
various dbus-launch processes that were started in this way attempt to
acquire a hidden X11 resource. Whichever dbus-launch process happens to
get there first forks and execs the dbus-daemon for this X11 session,
then continues to run to supervise it; the other dbus-launch processes
just report its address back to their parents and then terminate.
This mode is discouraged, and not particularly reliable: it has
a tendency to start the dbus-daemon in a somewhat precarious situation,
as a child of some random GUI app with arbitrary environment variables,
resource limits, std{in,out,err} fds and so on.

Autolaunching can also get used if you run a graphical program under
su/sudo with access to your X11 display (but seriously, don't do that).

X11 autolaunching may have been important 10 years ago, when people
installed D-Bus into distributions that didn't otherwise integrate it,
and used it to run individual GNOME or KDE apps inside a fvwm session
or something. However, in 2016 and in a well-integrated distribution
like Debian, I would be inclined to treat any use of X11 autolaunching
as a bug.

Why should we prefer dbus-user-session?
=======================================

* If a GUI login session is running (for example you are logged-in
  to a GUI environment but the screen is locked), your cron jobs and ssh
  sessions on the same machine can share the desktop's user-services like
  dconf, Telepathy, fd.o Secrets (gnome-keyring/KWallet).

* It's a good fit for the design of user-services like dconf.
  They can take a bus name on the user bus and be confident that
  this acts as a mutex locking out other instances of the user service
  on the same machine, avoiding "last write wins" data loss for all
  configurations where $HOME is not shared between machines.

* It's also very suitable for taking per-user daemons that use D-Bus
  and would more usually be run in a desktop login session (for example
  exporting media to a UPnP receiver like a PS3 using Rygel, with Tracker
  for indexing) and turning them into pseudo-system-services running as
  a dedicated user: a systemd service with PAMName= and User= is enough
  to get a systemd --user instance and an accompanying dbus-daemon for
  that user, which is enough to support services like Rygel.

* dbus-daemon is not a fully-featured service manager: it can start
  session services on-demand, but it doesn't support resource limiting,
  disabling services, non-D-Bus services and so on (nor should it - that
  isn't in its scope, and it doesn't have enough regular contributors
  to be a good idea to expand its scope to something like that). The
  user bus can use a fully-featured service manager, "systemd --user",
  for service activation.

* As a systemd user service, the user bus is started in a known context
  with predictable/controllable environment variables, resource limits and
  so on.

* The traditional D-Bus session bus uses abstract Unix sockets on
  Linux, to ensure automatic cleanup even if the dbus-daemon is terminated
  uncleanly. These sockets are always shared with container-based
  sandboxes, unless you start a new network namespace (which unshares
  all abstract Unix sockets, and also IP networking). The user bus
  uses a single filesystem-backed socket per uid, which is easy to
  inspect with standard Unix tools ("everything is a file") and is more
  container-friendly: it is not shared by default, but can be shared
  with a simple bind mount.

* dbus-launch is fairly horrible code, complicated by the historical
  need for it to support X11 autolaunching, so the D-Bus maintainers
  would like to move it out of the critical path and minimize its use.

Why should dbus-user-session be optional?
=========================================

* The current implementation[1] requires systemd and systemd-logind.
  This is not portable to non-Linux kernels, and upsets some Linux users.

  [This is not set in stone; there's no reason why someone couldn't
  write a PAM module that started a user bus, but the people doing the
  work so far are happy with systemd taking responsibility for that.]

* Some desktop environments (including many configurations of "build
  your own desktop environment from pieces") do support multiple
  parallel X11 sessions per uid per machine. In these setups, the
  user bus breaks the expectations of software that assumes it can run
  once per X11 session, in parallel, and take the same bus name on the
  session bus corresponding to each X11 session (for example
  gnome-settings-daemon has this behaviour).

  [It is possible to use a bus name like com.example.MyService.X0
  if you want a bus name per X11 display, although this would require
  coordinated code changes in the service and its consumers.]

* The per-X11-session bus would disconnect all background services
  (or at least those that happen to use D-Bus) on each X11 logout;
  well-behaved D-Bus services respond to this by terminating. The user
  bus isn't normally terminated until all processes in the login session
  have exited, which can result in background services lingering
  (more precisely, if a login-session process lingers, then the
  dbus-daemon and other non-GUI processes will too).

  [If this is important to you, for example in a university computer lab,
  consider using systemd-logind's KillUserProcesses option, which is
  the default upstream since 230 but not in Debian; it's more thorough,
  and does not depend on the implementation detail of whether processes
  happen to use D-Bus for IPC.]

Recommendations for libraries
=============================

This recommendation applies to library implementations of D-Bus such
as libdbus, GLib's GDBus, systemd's sd-bus, dbus-sharp and dbus-java,
when connecting to the standard session bus.

If the environment variable DBUS_SESSION_BUS_ADDRESS is set, libraries
must use that address when asked to connect to the session bus.

If DBUS_SESSION_BUS_ADDRESS is unset, but XDG_RUNTIME_DIR is set,
and $XDG_RUNTIME_DIR/bus is a socket owned by the correct uid,
libraries must use that socket (for instance by substituting the
XDG_RUNTIME_DIR, escaped as a D-Bus address component, into
"unix:path=${escaped_xdg_runtime_dir}/bus").

If neither of those is available, libraries may use X11 autolaunching
(the "autolaunch:" pseudo-transport) like libdbus and GDBus do, or
they may simply fail the connection attempt like sd-bus does. I
anticipate that for stretch+1 or stretch+2, we might want to recommend
that libraries like libdbus and GDBus should disable X11 autolaunching,
and fail to connect in the circumstances where they would have used it.

Recommendations for desktop sessions
====================================

This recommendation applies to desktop sessions like GNOME, and desktop
sessions' core infrastructure like gnome-session.

Desktop sessions that make use of D-Bus should depend on

    Depends: dbus-user-session | dbus-x11

(Open question: do we want this way round, or dbus-x11 | d-u-s?)

If a desktop environment works better with the "user bus" (I anticipate
that GNOME might do this in stretch or stretch+1), it may indicate
that with:

    Depends: dbus-user-session | dbus-x11
    Recommends: dbus-user-session

If a desktop environment strictly depends on the "user bus", it may
instead depend on

    Depends: dbus-user-session

but maintainers should note that this eliminates sysadmins' ability to
choose between the "login session bus" and "user bus" models without
patching the software, is an indirect systemd dependency, and in
particular is uninstallable on non-Linux kernels.

Desktop sessions may execute dbus-launch if they are started with
DBUS_SESSION_BUS_ADDRESS absent from the environment, and either
XDG_RUNTIME_DIR unset, or a socket named $XDG_RUNTIME_DIR/bus not
existing or owned by the wrong uid. This code path should not normally
be necessary (and should not be run in practice) in Debian X11 sessions
or with dbus-user-session installed, but might be useful in Wayland
sessions with dbus-user-session not installed, or as part of upstream
support for distributions with less careful X11 integration than Debian.

Recommendations for regression tests
====================================

This recommendation applies to packages that run tests at build time,
packages with autopkgtests, and all similar situations.

Regression tests should either use dbus-run-session, which is an "adverb"
command like sudo or fakeroot:

    Depends: dbus (>= 1.8)

    dbus-run-session -- make check

or if finer control is needed, start a dbus-daemon the hard way, something
like this:

    Depends: dbus

    #!/bin/sh
    dbus-daemon --session --fork --print-address=4 --print-pid=5 4>address.tmp 5>pid.tmp
    trap 'kill $(cat pid.tmp); rm -f address.tmp pid.tmp' EXIT
    export DBUS_SESSION_BUS_ADDRESS="$(cat address.tmp)"
    make check

If a special configuration file for the dbus-daemon is required, use

    dbus-run-session --config=special.conf -- make check

or

    dbus-daemon --config=special.conf --fork --print-address=4 ...

Recommendations for other software that relies on D-Bus
=======================================================

This recommendation applies to ordinary apps that rely on having a
session bus but are not a core part of a desktop environment, such as
the Empathy real-time communications client. These packages should rely
on the distribution and the desktop environment cooperating to ensure
that a session bus is provided.

A hard requirement for a session bus should be indicated like this:

    Depends: dbus-user-session | dbus-x11

(Open question: do we prefer d-x | d-u-s?)

A softer requirement can be indicated by a similar Recommends or Suggests.

These packages should not attempt to run dbus-launch or dbus-daemon,
except as a side-effect of using a library that supports X11
autolaunching - it is not their responsibility.

Discussion/contact
==================

Please discuss this proposed MBF on debian-devel or by contacting
dbus@packages.debian.org.

[1] Please contact the D-Bus upstream mailing list if you are
    interested in implementing a user bus without systemd. You will need
    something resembling pam_xdg_support (which is what Ubuntu used
    before they switched to systemd) to provide the XDG_RUNTIME_DIR,
    plus some way to start the actual dbus-daemon, probably from the
    same or a different PAM module. Note that since Ubuntu does not
    use or maintain pam_xdg_support any more, you will likely need to
    become its new upstream maintainer, or fork it as a basis for your
    new PAM module.

Regards,
    S


Reply to: