D-Bus bus activation is the idea that if a service does not exist on the Desktop Bus, the bus controller dæmon will directly auto-start the service program on demand, when a client first asks for the service. The technical details can be found in the freedesktop.org doco on system bus activation.
It's a bad idea.
The D-Bus bus controller dæmon isn't a service manager, and it has almost no mechanisms for dæmon management, such as resource limit controls, auto-restart control, log management, privilege/account management, and so forth. But common D-Bus services — PolicyKit, PackageKit, ModemManager, NetworkManager, ConsoleKit, DeviceKit (UDisks and UPower), GNOME Terminal, MATE Notification, GNOME Editor, and so forth — are dæmon processes, and require proper dæmon management.
The obvious thing to do is for the bus controller dæmon to hand off the task of starting and managing these dæmons to a dæmon management subsystem. Unfortunately, despite several such management systems having been in wide use since the 1990s and the turn of the century, the writers of D-Bus didn't make it capable of talking to any of them. They didn't even include upstart. The writers of upstart patched D-Bus to know about upstart job files, but the improvements never made it into D-Bus proper. Lennart Poettering explicitly blocked them in 2011.
The system-wide Desktop Bus has but just two modes of operation:
the non-systemd mode, where the bus controller dæmon tries to spawn dæmons itself, with a helper program that goes and looks up the appropriate (D-Bus) .service
file
the systemd mode, where the bus controller dæmon talks the idiosyncratic systemd protocol to systemd and tells it to start the relevant dæmon(s)
Had the writers of D-Bus even merely handed things off to the service
command, we would be in a a far better position, as various dæmon management systems implement either a full service
command or some shim that translates to their own native mechanisms.
Spawning D-Bus services under proper service management would not then be locked in to just one single service management system, as is currently the case.
James Hunt of Canonical, discussing this very same systemd-only problem from an upstart perspective, wrote in 2013 in Ubuntu bug #1238514:
the ideal would be a consistent and generic service activation approach which does not require hard-coding particular init daemon names anywhere.
But instead what happens is that on non-systemd systems where there are properly configured managed services (for NetworkManager, ModemManager, PolicyKit, PackageKit, ConsoleKit, UPower, UDisks, et al.) there are conflicts. The most visible instance of such a conflict is a failure of the properly managed service to start because the D-Bus bus controller has decided that it is in non-systemd mode and directly spawned a prior, conflicting, and unmanaged, instance of the service.
Under nosh service management, the typical case will be one instance of the service that is a child of process #1 and another — repeatedly failing and restarting — instance of the service that is a child of the service manager.
This apparent lack of relationship to the bus controller dæmon is because the hand-rolled service spawning by the D-Bus bus controller also involves the completely unnecessary and wholly unwise step of double-fork()
ing in order to "dæmonize", even though the processes are already dæmonized, since it is a dæmon, the bus controller dæmon, that is starting them in the first place and they are already running in a dæmon execution context.
Other problems include D-Bus services that take it upon themselves to explicitly trigger the activation of other D-Bus services, rather than letting service management configuration under the control of the system administrator determine whether a service is to be started or not; or, worse, attempt to spawn other D-Bus services directly without even going through the bus activation mechanism.
The most prominent example of this is ModemManager. Most people have absolutely no need of this service, because their systems do not have modems. Yet older versions of NetworkManager would attempt to start ModemManager directly. This would conflict with explicit ModemManager services (like the one provided with nosh, or indeed the one provided with systemd) resulting in continual vain attempts by NetworkManager to bring up a second ModemManager service; and on systems where ModemManager is inappropriate (and the managed service, appropriately, disabled) continual vain attempts by NetworkManager to bring up a first ModemManger service.
OpenSUSE's bug list has bugs about this aspect of NetworkManager from 2011. In 2014 the system was changed; NetworkManager now, at least, uses indirect means (bus activation) to spawn ModemManager. See Mageia Bug #11725, GNOME Bug #703040, GNOME Bug #701229, RedHat Bug #948404, RedHat Bug #1018017, and Debian Bug #770871 for the lengthy and muddled details.
Alas, initial fixes were to use bus activation only when systemd is the service manager; even though D-Bus system bus activation is nominally available independent of what service manager is running. But even with that fixed it just brings NetworkManager to the same stage as the other services, where bus activation generates conflicting services everywhere but with systemd.
In the non-systemd mode, where the bus controller dæmon tries to spawn dæmons itself, if no helper program is used the server dæmon is forked and executed directly by the bus controller dæmon. It thus runs in the same service execution context as the bus controller. This context may have per-process or per-service limits that are appropriate to running just the bus controller, possibly spawning the occasional helper process, but inappropriate for the bus controller and all of the dæmons running alongside it to run all in one big service.
This causes surprising and hard to diagnose dæmon failures. For examples:
A failure to create a new thread because a hard maximum tasks limit has been reached is mis-reported as an out-of-memory error (in log messages and suchlike) by some classes of programs. (There was a seven-year-long bug in the GNU C library that did this. Java programs also do this.)
Odd permissions errors are reported.
The system-wide D-Bus controller runs as an unprivileged user, messagebus
(or some such), but the server dæmons may need to run as the superuser, or as a different unprivileged user (which requires that they at least begin running as the superuser).
(The original helper that comes bundled with the Desktop Bus dæmon program is thus marked as a set-UID executable.)
Since the D-Bus bus controller and its helper don't use widely available APIs such as the service
command to talk to service management, there are two approaches remaining on non-systemd systems.
One remaining approach is to just cut out all instances of bus activated D-Bus services and avoid bus activation entirely by making it a no-operation.
One hand-edits the relevant files in /usr/local/share/dbus-1/system-services/
so that the bus controller (helper) either uses service
or systemctl
to start the service indirectly or simply doesn't try to do anything at all.
Files to edit are:
org.freedesktop.ModemManager.service
,
org.freedesktop.PolicyKit1.service
,
org.freedesktop.ConsoleKit.service
,
To make it not try to do anything at all, replace the command that the bus controller runs with
Exec=/bin/true
Interestingly, simply excising D-Bus system bus activation entirely is the route that has already been taken for some D-Bus services, where the vanilla D-Bus .service
configuration files in place of describing how to spawn the service program now read:
Exec=/bin/false
The Avahi D-Bus service definition file, /usr/local/share/dbus-1/system-services/org.freedesktop.Avahi.service
, that the Fedora Project uses as an exemplar of good D-Bus service definition, even gives this very explanation (albeit making the error that the service management in use in non-systemd mode must be System 5 rc
) in a comment:
# This service should not be bus activated if systemd isn't running, # so that activation won't conflict with the init script startup. Exec=/bin/false
Sadly, and somewhat ironically, this approach is incorrect for several service activators, which expect service activation to exit with a success exit code and complain if it does not.
Hence /bin/true
rather than /bin/false
.
The other remaining approach is to replace the helper program that comes bundled with the Desktop Bus dæmon program with a different helper program that does understand service managers other than systemd.
The nosh toolset comes with one such replacement helper program, dbus-daemon-launch-helper
, that can use system-control
to speak to nosh service management, initctl
to speak to upstart service management, or systemctl
to speak to systemd service management.
One hand-edits /usr/local/etc/dbus-1/system.conf
to replace the helper.
Where it reads:
<!-- This is a setuid helper that is used to launch system services --> <servicehelper>/usr/local/libexec/dbus-daemon-launch-helper</servicehelper>
Replace that with:
<!-- This is a non-setuid helper that is used to tell service management to launch system services --> <servicehelper>/usr/local/bin/dbus-daemon-launch-helper</servicehelper>
The dbus-daemon
service bundles provided out-of-the-box in the nosh toolset come pre-configured with per-service configuration files to which this substitution has already been applied.
The user account that the Desktop Bus dæmon process runs as, and hence that the helper runs as, is usually an unprivileged account such as (for example) messagebus
.
This raised two important points:
Unlike the helper pre-packaged with Desktop Bus, this helper does not need, and in fact should not be a set-UID program. It runs with the same user credentials an Desktop Bus dæmon process that spawed it. This helper does not spawn any service processes directly; it tells the service manager to do so.
The messagebus
(or whatever) user account needs permission to tell the service manager to start services.
This does not mean necessarily that it needs superuser permissions, though.
With the nosh service manager, one merely needs to grant the messagebus
(or whatever) account permission to talk via the /run/service-manager/control
socket.
This is a simple exercise in the use of setfacl
.
The dbus-daemon-launch-helper
manual page explains in detail a short-cut that becomes available when one adopts the principles that the helper only deals with starting D-Bus services via service management, and that service management service names have a definite relationship to D-Bus .service
file names.