Discussion:
[systemd-devel] User sessions, session buses, user buses
Simon McVittie
2015-01-30 08:30:19 UTC
Permalink
[For those who are there, I'll be at the system hackfest today and at
FOSDEM this weekend, so if you are interested in these topics, please
talk to me about them; I'll try to summarize discussion to these lists.
For those not there, I'll try to keep up with responses via email and
raise any interesting points in person.]

I've recently been looking into D-Bus' interaction with X session
startup, systemd --user, upstart --user, and the definition of a
session. Every few months or years there is an attempt to sort out
whether D-Bus has a user bus or a session bus or what. Here is another,
with particular reference to systemd and potentially kdbus.

Terminology
===========

login session
-------------

A *login session* is as follows: when you log in to *dm, that starts a
*graphical login session* which lasts until you log out. When you log in
on a virtual console or via ssh or something, that starts a
*non-graphical login session*. Background processes like cron or screen
might also be non-graphical login sessions. A non-graphical login
session might become graphical by running startx or similar.

In a systemd-logind environment, login sessions have an ID which is
made available to in-session processes in the XDG_SESSION_ID environment
variable. If the Linux "auditing" feature is enabled, the XDG_SESSION_ID
equals the audit session ID (/proc/self/sessionid). If not,
there is no audit session ID, so systemd-logind makes up a sequential
XDG_SESSION_ID and uses that.

seat
----

A seat is a set of displays, input devices etc. attached to a machine.
Most machines have one seat "seat0", which occupies all the devices.
By attaching additional devices via something like
http://plugable.com/products/ud-160-m you can construct a
multi-seat machine.

user-session
------------

I don't think there is a standard term for this so I'm making one up.
The XDG_RUNTIME_DIR specification says that there is at most one
XDG_RUNTIME_DIR per uid per machine, that it is created at the beginning
of the user's first login session, and that it is removed at the end of
a login session if no other login sessions remain for that uid.
systemd-logind implements those semantics, and also runs a `systemd --user`
for the lifetime of the user-session. Ubuntu previously used
libpam-xdg-runtime to provide compatible semantics without systemd.
The resulting situation looks something like this (assume all the
sessions shown are under the same uid):

--------\ ========\\
login | user- ||
session | --------\ session || <- overlapping login session c42
23 | login | || shares the user-session with 23
--------/ session | || <- 23 ends but c42 keeps u.-session
c42 | || alive
--------\ | || <- 57 begins, shares u.-sess.
login | --------/ || <- c42 ends, 57 keeps user-session
session | || alive
57 | ||
--------/ ========// no more l.sessions, u.-session ends

--------\ ========\\ new l.session, u.-session starts
login | user- ||
session | session ||
... . ... ..

user-sessions do not have any meaningful identifier apart from their
owner's uid (strictly speaking, the owner's "loginuid", i.e. the user
who initially logged in, even if they su). They do not need another
identifier, because by definition there is only one per uid at a time.

Impact on D-Bus
===============

There are two models for how the D-Bus session bus, which is designed to
be per "high-level session" (whatever that means), can work in a world
with user-sessions.

Last time this was discussed, Havoc had the useful insight that this is
not really a question about D-Bus, it's a question about how you build
OSs, and in particular how you model sessions.

(Up to) one high-level session per login
----------------------------------------

The first model, which is how it traditionally worked (before there was
such a thing as a user-session), is that each graphical login session is
declared to be a "session", and non-graphical login sessions are pretty
much swept under the carpet and forgotten about.

In graphical sessions, vaguely modern Unix OSs typically know how to
start up a dbus-daemon during the creation of a graphical session (e.g.
in Debian and derivatives it's started by /etc/X11/Xsession.d, and
Fedora derivatives have a similar setup under a different name). If they
don't, modern desktop environments also know how to start a dbus-daemon
if they need one (e.g. gnome-session does this for GNOME), and if *that*
doesn't start one (the "I use Firefox under fvwm" use-case), we have a
slightly shaky but functional "autolaunch" mechanism based on X11
properties.

In principle, a PAM module or something could ensure that we have a
dbus-daemon per login session, even tty/ssh/cron login sessions
(which all go through PAM). In practice, nobody has ever cared enough to
implement this, so we're left with D-Bus autolaunch, which can't
actually work for tty sessions and had bad side-effects from its
attempts to do so, so I disabled it 3 years ago in favour of
recommending that users requiring a D-Bus session should start their own
and manage its lifetime themselves e.g. with dbus-run-session(1).

If people want to put work into this model, we could do a lot better
than we do now; for instance, the bus socket could be
unix:path=${XDG_RUNTIME_DIR}/sessions/${XDG_SESSION_ID}/bus (but with
the necessary escaping) on systems where those variables are set, rather
than messing about with $TMPDIR.

However, the people doing the work have a somewhat strong correlation
with the people who want a different model, for which read on...

Digression: (at least some) users and developers don't want that
----------------------------------------------------------------

One major issue with one high-level session (and hence one session bus)
per login session is that it places an artifical barrier between login
sessions. It's difficult for cron jobs, ssh logins, tty logins to share
non-GUI backend services such as dconf, Rygel, Telepathy: on my NAS box,
which runs Rygel with no GUI to export my music in a way the
notoriously picky PS3 system software can understand, I had to
construct a D-Bus session to let Rygel and Tracker components talk
to each other. Happily, I had already written dbus-run-session(1),
but I shouldn't need to do this rubbish to let non-GUI daemons talk
to each other - it should just work.

Similarly, if you leave a screen/tmux session detached and running
in the background, systemd is fine with that: its view of the world
is that there are processes left over from your previous login session,
keeping the login session alive in "closing" state, with the consequence
that the user-session remains alive too (unless you have configured
systemd-logind to kill leftover processes, as required by the sysadmins
of computer labs and other massively multi-user machines, in which case
you don't get to run screen sessions and that's by design).
However, the login-session-centric model can't cope with that:
the dbus-daemon dies with the X server, the D-Bus services die with
the dbus-daemon, and now the duplicity(1) process in your screen session
can't use gvfs to upload your backups to a server (or whatever).

Another issue is that it is an extremely poor match for how
`systemd --user` works (although apparently a better match for
how Ubuntu uses `upstart --user`, which I hope to discuss with Ubuntu
people at the systemd hackfest today / at FOSDEM) - you can't use
systemd to manage your login-session-bound D-Bus services, because they
all share a systemd, which doesn't know which login session wants which
service.

I think it's telling that, in recent discussion with Ubuntu developers
about their use of one `upstart --user` per login session, they
clarified that they only actually do this for *graphical* login
sessions, and they provide tools to let a developer copy the environment
variables from what, conceptually, should be another session,
effectively "joining" that session for a subtree of processes. I think
this proves the point that Robert McQueen made on the subject back in 2006:

"It's already been discussed multiple times on the list and
apparently a user bus is too confusing or not really useful unless
you make it a user bus shared across a network cluster. I don't
agree, and I think that the consequence of this stance will be a
proliferation of hacks like the one I just sketched out (not to
mention even grosser hacks like Ubuntu's ACPI scripts grepping the
environment of the user's processes in /proc to find their session
bus to tell their screensaver to lock)."

One high-level session per user-session
---------------------------------------

As a result of the problems noted above, various people, most vocally
the systemd and GNOME developers, have advocated a different model
for how to model sessions in the OS - what I called "user-sessions"
above. A typical implementation of that idea forbids multiple graphical
login sessions altogether: if you type your username and password into
gdm while already logged in on another virtual console, it will just
vt-switch to your existing graphical login session and unlock it.

Under X11, that might well be the best we can do, because typical
X11 applications can't cope with being asked to put windows on more
than one $DISPLAY (although I've heard rumours that Emacs can, which
would make Emacs an ideal candidate to be a user-session service).
Under Wayland or similar future cleverness, hopefully there'll be
some way for a new login on a new seat to "steal" all the windows
from the inactive seat, or some way to merge both seats into
one big virtual display if the same person is using both (AIUI this
is what GNOME designers want to do), or some other clever solution.

What this means for D-Bus
-------------------------

This leaves the problem that, if you have chosen the
user-session-centric model, current D-Bus doesn't actually work very
well: we have dbus-launch and dbus-run-session for login-session-centric
D-Bus, but if you want to make D-Bus user-session-centric, you need to
resort to third-party user bus units like user-session-units, which
float around Github and somehow never make it upstream. I'm now on my
third unrelated work project that contains a copypaste of dbus.socket
and dbus.service, and I'm sure my colleagues have others - this is not
the flying car future I signed up for. So I would like to get this stuff
upstream into dbus.git.

So that the people who are happy with the complexities of the current
arrangement can remain happy, here is how I intend it to work:

* ./configure --disable-user-bus: you get a login-session-centric world
* ./configure --enable-user-bus: you get a user-session-centric world
* configure either way and selectively install/delete files: you can
either have a login-session-centric or user-session-centric world,
depending what you install. (This is so I can have dbus-user-bus and
dbus-x11 binary packages in Debian, where the answer to "do A or do
B?" is always "both!", without having to compile everything twice;
the GNOME metapackage could eventually depend on dbus-user-bus.)

I think in practice that design will mean that by default, libdbus tries
to connect to both user-session- and login-session-centric locations for
the bus (but the "wrong one" for this OS will fail and the "right one"
will succeed), while dbus-user-bus and dbus-x11 would arrange for the
bus to listen in the appropriate place for one option or the other so
that the appropriate version succeeds.

Conveniently, this is what I've already implemented (in two
different ways): "try the user-session-centric path first, and if that
fails, fall back to login-session-centric autolaunch". There is the
slight nit that the server side of user-session-centric operation
requires systemd, although that could be argued to be a feature: the
other reasonable implementation is libpam-xdg-runtime, which AIUI is
unmaintained now that Ubuntu has switched to systemd-logind, and the
people who are avoiding systemd on general principles (hello Devuan!)
are probably the sort of people who are sufficiently change-averse to
prefer D-Bus to work the way it worked in 2005 (if they install it at
all). I'd be willing to consider implementations that work with other
service managers if their authors are willing to help maintain them.

The glorious(?) kdbus future
============================

kdbus is a proposed Linux kernel module providing
somewhat-D-Bus-compatible message-passing semantics (I'm being vague
because it's been 4 months since I last looked at it in detail - I hope
to return to it soon). To provide complete dbus-daemon-like
functionality, you also need a user-space process to create the bus and
manage activations; the
reference implementation, and so far the only implementation, is in
systemd.

The systemd developers who are working on the user-space counterpart
for kdbus have indicated that they have zero interest in supporting a
login-session-centric setup for session kdbus. In practice, I think
this means that the proponents of a login-session-centric world either
can't use kdbus in their sessions, or need to convince the relevant
developers that the added complexity of their model is worth it, or need
to write their own user-space for kdbus sessions and
disable systemd's. (It's not all bad - they can still use kdbus for
the system bus, which is already an improvement.)

Remaining issue: environment variables
======================================

Sadly, not all the issues have been resolved yet. The biggest is
environment variables: on existing systems there is an expectation
that environment variables set by *dm, PAM, or /etc/X11/Xsession.d
(or the non-Debian equivalent) will be propagated into every process
in the session. In a brief survey of about half the Xsession.d scripts
in Debian, I identified these environment variables:

* PULSE_SERVER
* ESPEAKER
* XDG_DATA_HOME, XDG_DATA_DIRS
* each variable printed by locale(1)
* VDPAU_DRIVER
* GTK_IM_MODULE, QT_IM_MODULE, QT4_IM_MODULE, CLUTTER_IM_MODULE,
XMODIFIERS
* GTK_MODULES

plus the obvious ones set by *dm, such as DISPLAY, or by PAM. Similarly,
a user's ~/.xsession can set arbitrary variables - mine sets CCACHE_DIR,
EDITOR, MPD_HOST and XDG_CONFIG_DIRS, among others.

The naive implementation would be to run a tool at the end of
/etc/X11/Xsession.d that uploads all of these into `dbus-daemon
--session` (if used) and into `systemd --user` (if used). However, not
all environment variables set in such scripts are suitable for that use:
notably, XDG_SESSION_ID from the login session should not be copied into
activated processes that exist outside any login session.

As a short-term solution, I'm tempted to write that tool, but make it
only upload a whitelisted set of variables automatically, and say "if
you install dbus-user-bus, you are expected to run this tool from your
~/.xsession if you need it".

Thoughts?

S
Elias Probst
2015-01-30 21:53:44 UTC
Permalink
Post by Simon McVittie
Remaining issue: environment variables
======================================
[
]
As a short-term solution, I'm tempted to write that tool, but make it
only upload a whitelisted set of variables automatically, and say "if
you install dbus-user-bus, you are expected to run this tool from your
~/.xsession if you need it".
IMHO, env variables are something we should get rid of in the long term.
It might be fine for now to provide some legacy-compatibility mechanisms
(like your not-yet-written tool), but to me environment variables are
something straight out of the dark ages.

The long-term goal (also in a world where a graphical session is managed
as a systemd user-session), the information provided until now by an
environment variable should be queried dynamically by e.g. a D-Bus call
to the component responsible for providing the relevant information.

I know that there are huge numbers of applications/toolkits/
 out there
making use of environment variables for various use cases, but this
shouldn't keep us from looking into the distant future where environment
variables are a thing of the past.

- Elias
Simon McVittie
2015-01-31 08:43:27 UTC
Permalink
Post by Elias Probst
IMHO, env variables are something we should get rid of in the long term.
It might be fine for now to provide some legacy-compatibility mechanisms
(like your not-yet-written tool), but to me environment variables are
something straight out of the dark ages.
Environment variables are specified by POSIX, also available in Windows,
and one of the few easy ways for information to inherit from a parent
process to a child process without the child process needing to do
anything explicitly. I don't think they're going to go away, however
much you might want them to - the "long tail" of (mostly TUI) programs
that use them is very long indeed.

I do agree that the number of them that are necessary should go down
over time (and my distro of choice, Debian, has a policy of "everything
we ship should be usable without manually setting magic environment
variables"), but I don't think it is likely to go down to zero.
Post by Elias Probst
The long-term goal (also in a world where a graphical session is managed
as a systemd user-session), the information provided until now by an
environment variable should be queried dynamically by e.g. a D-Bus call
to the component responsible for providing the relevant information.
Environment variables do several different things.

Having a quick skim through my `env` output, here are some distinct
categories:

We talked about LANG a bit at the hackfest, and the consensus seemed to
be that something better should happen, but nobody was sure exactly
what. I don't set LC_* but if I did, they'd be in the same category.

Losing DBUS_SESSION_BUS_ADDRESS was part of the point of this thread.
:-) Similarly, DISPLAY, GPG_AGENT_INFO, SSH_AUTH_SOCK should be able to
go away one day, when those things grow support for
XDG_RUNTIME_DIR-based socket-activation. XAUTHORITY can go away
eventually too, even in X11 environments, in favour of "xhost
+SI:localuser:smcv" (which in fact gdm already does).

DEBEMAIL, LESS, LS_COLORS, PYTHONSTARTUP, SHELL, SSH_ASKPASS, VISUAL are
configuration, and could in principle be read from a dotfile instead
(although good luck porting every last consumer of EDITOR, SHELL and
VISUAL to your new world order - e.g. Debian has more than 37k packages).

XDG_SEAT, XDG_SESSION_ID, XDG_VTNR are properties of my login-session,
not my user-session or my home directory, so you can't write them to
either XDG_RUNTIME_DIR or a dotfile because both would be the wrong scope.

XDG_RUNTIME_DIR has to be an environment variable because you can't very
well read it from the XDG_RUNTIME_DIR :-)

S
Lennart Poettering
2015-02-02 22:11:07 UTC
Permalink
Post by Simon McVittie
Losing DBUS_SESSION_BUS_ADDRESS was part of the point of this
thread.
BTW: DBUS_SESSION_BUS_ADDRESS we currently set on kdbus systems from
pam_systemd. That way we can be sure it is set for all the user's
sessions.

Lennart
--
Lennart Poettering, Red Hat
Lennart Poettering
2015-02-02 22:06:34 UTC
Permalink
Post by Elias Probst
Post by Simon McVittie
Remaining issue: environment variables
======================================
[…]
As a short-term solution, I'm tempted to write that tool, but make it
only upload a whitelisted set of variables automatically, and say "if
you install dbus-user-bus, you are expected to run this tool from your
~/.xsession if you need it".
IMHO, env variables are something we should get rid of in the long term.
It might be fine for now to provide some legacy-compatibility mechanisms
(like your not-yet-written tool), but to me environment variables are
something straight out of the dark ages.
I think in the long-run we should not use environment variables for
all these things in the default codepaths. However, the user always
needs the ability to set some if he desires to do so.

Lennart
--
Lennart Poettering, Red Hat
Simon McVittie
2015-01-31 08:53:33 UTC
Permalink
Post by Simon McVittie
user-session
------------
I don't think there is a standard term for this so I'm making one up.
Notes from the hackfest: A few people called these "super-sessions" when
we discussed them. I preferred user-session tbh, but if people want to
standardize on calling them super-sessions that's fine.
Post by Simon McVittie
If people want to put work into this model, we could do a lot better
than we do now; for instance, the bus socket could be
unix:path=${XDG_RUNTIME_DIR}/sessions/${XDG_SESSION_ID}/bus (but with
the necessary escaping) on systems where those variables are set, rather
than messing about with $TMPDIR.
Please open an "enhancement"-severity bug against dbus if you want this,
and I can talk you through the right places to patch; it would not be
rocket science, and if people have use-cases for it, I would be OK with
merging it even though I personally prefer the user-session model.
Post by Simon McVittie
Similarly, if you leave a screen/tmux session detached and running
in the background, systemd is fine with that: its view of the world
is that there are processes left over from your previous login session,
keeping the login session alive in "closing" state, with the consequence
that the user-session remains alive too
Notes from the hackfest: Everyone seems to think screen/tmux/... should
use PAM to register themselves as first-class login sessions in their
own right, if allowed by the sysadmin. That would also work fine.
Post by Simon McVittie
Under X11, that might well be the best we can do, because typical
X11 applications can't cope with being asked to put windows on more
than one $DISPLAY (although I've heard rumours that Emacs can, which
would make Emacs an ideal candidate to be a user-session service).
Under Wayland or similar future cleverness, hopefully there'll be
some way for a new login on a new seat to "steal" all the windows
from the inactive seat, or some way to merge both seats into
one big virtual display if the same person is using both (AIUI this
is what GNOME designers want to do), or some other clever solution.
Notes from the hackfest: Lennart's long-term idea is to have a singleton
X server (or Wayland equivalent) per uid, and "hotplug" output devices
to it as the user logs in/out on different seats (or remotely via RFB or
whatever), with the ability to clone the same window layout onto all
displays, or have distinct displays and move windows between them, a lot
like the way we currently deal with multiple monitors per seat. This
also solves the $DISPLAY problem rather nicely.

Regards,
S
Dimitri John Ledkov
2015-02-02 10:22:08 UTC
Permalink
On 30 January 2015 at 08:30, Simon McVittie
Post by Simon McVittie
Remaining issue: environment variables
======================================
Sadly, not all the issues have been resolved yet. The biggest is
environment variables: on existing systems there is an expectation
that environment variables set by *dm, PAM, or /etc/X11/Xsession.d
(or the non-Debian equivalent) will be propagated into every process
in the session. In a brief survey of about half the Xsession.d scripts
* PULSE_SERVER
* ESPEAKER
* XDG_DATA_HOME, XDG_DATA_DIRS
* each variable printed by locale(1)
* VDPAU_DRIVER
* GTK_IM_MODULE, QT_IM_MODULE, QT4_IM_MODULE, CLUTTER_IM_MODULE,
XMODIFIERS
* GTK_MODULES
And one shall not forget GNOME_DESKTOP_SESSION_ID=this-is-deprecated
for a certain C++ toolkit to not look like it's 1995. ;-)
Post by Simon McVittie
plus the obvious ones set by *dm, such as DISPLAY, or by PAM. Similarly,
a user's ~/.xsession can set arbitrary variables - mine sets CCACHE_DIR,
EDITOR, MPD_HOST and XDG_CONFIG_DIRS, among others.
The naive implementation would be to run a tool at the end of
/etc/X11/Xsession.d that uploads all of these into `dbus-daemon
--session` (if used) and into `systemd --user` (if used). However, not
notably, XDG_SESSION_ID from the login session should not be copied into
activated processes that exist outside any login session.
The rest of the email thread is adequate.

I would like to experiment with a user-bus, potentially in a transient
manner to have 3 buses: system, user, session busses. And migrate
things from session to user bus & experiment as to how much stuff
breaks. I think being explicit about session vs user bus would avoid
confusion, and will help manifest bugs & have a clear migration plan.
E.g. when org.freedesktop.Telepathy / ca.desrt.dconf moves to user
bus, things should know how to start talking to Telepathy/dconf over
user bus.

Looking at the stuff that I have on my session dbus, I see quite a few
things that do interract with DISPLAY=:0, or rather create GUI windows
and expect them to appear in the right place, as in on the currently
active seat. Similarly they would need to be migrated/restarted if we
ever allow multiple graphical search for a single UID. I wonder if
this is at all an actual problem, maybe all current/sophisticated
dbus-heavy DEs cannot in fact have multiple graphical sessions for the
same UID, in which case switching to user bus today is non-regressing
(given that current active graphical session cannot migrate a seat (?!
not sure if this)).

Going down this rabbit-hole, the only difference between current
session-bus (e.g. where under gdm only one graphical login is allowed
per UID) and the user-bus seems to be the life-time of the bus (tied
from first login until last login V.S. X11 started and finished). That
means that dbus-activated services have to simply become seat aware,
and know that if they were started on a non-graphical seat, later on
active seat might be graphical and thus they should
migrate/recreate/create GUI windows on currently active seat - or
across all seats if that's appropriate.
--
Regards,

Dimitri.

Intel Corporation (UK) Ltd. - Co. Reg. #1134945 - Pipers Way, Swindon SN3 1RJ.
Simon McVittie
2015-02-02 11:15:33 UTC
Permalink
Post by Dimitri John Ledkov
I would like to experiment with a user-bus, potentially in a transient
manner to have 3 buses: system, user, session busses.
I still think it's a bad idea to have both a user bus and a session bus.
Having things "on the wrong bus" is definitely an API break, and having
processes' messages be out-of-order will break application expectations
(message order is guaranteed to be a consistent "total ordering" within
one bus, but you can't even rely on "causal ordering" across multiple
buses).
Post by Dimitri John Ledkov
E.g. when org.freedesktop.Telepathy / ca.desrt.dconf moves to user
bus, things should know how to start talking to Telepathy/dconf over
user bus.
If you have both buses, this is a flag-day API break for each thing that
moves. Please don't go there if you want to reach a user bus in a finite
time.

If you only have a session bus, where "session" is taken to mean either
login session or user-session/super-session depending on a choice made
by the OS integrator and/or sysadmin, you don't get that problem.
Post by Dimitri John Ledkov
I wonder if
this is at all an actual problem, maybe all current/sophisticated
dbus-heavy DEs cannot in fact have multiple graphical sessions for the
same UID, in which case switching to user bus today is non-regressing
(given that current active graphical session cannot migrate a seat (?!
not sure if this)).
GNOME (at least, if you have the full GNOME suite including gdm)
specifically does not support more than one graphical session per seat:
if you are logged in (with screen locked) on tty7, and you type your
username and password into a "Switch User" gdm prompt on tty8, gdm will
just switch to tty7 and unlock your screen. I think this is a perfectly
reasonable model. I don't know about multiple seats as the same user,
but I suspect that, in practice, it doesn't work very well (if at all)
and in any case, why would you? You are only physically in one place
after all :-)

I believe the situation last time we discussed this was that KDE does
support more than one simultaneous graphical session, but Thiago was
unsure whether that was by policy or coincidence.
Post by Dimitri John Ledkov
Going down this rabbit-hole, the only difference between current
session-bus (e.g. where under gdm only one graphical login is allowed
per UID) and the user-bus seems to be the life-time of the bus (tied
from first login until last login V.S. X11 started and finished).
Yes. This is part of the reasoning behind the mental model that Havoc
proposed last time this was discussed: this is not about the D-Bus
maintainers deciding how long a D-Bus bus lasts, but about OS
integrators deciding how long a session lasts (or to put it another way,
which of the multiple possible definitions of session should be the one
used for D-Bus).

When you think of it like that, the decision point becomes whether the
OS integrator wants:

* dbus-launch manages one session bus per X11 session (current
reality, and apparently some people strongly prefer it this way)

* dbus.socket/dbus.service manages one session bus per
user-session/super-session (I anticipate that e.g. Fedora and
GNOME-Continuous will probably make this simplification mandatory)

* punt the decision to the sysadmin via whether an optional
dbus-user-bus.deb, or RPM equivalent, is installed (I suspect I will
have to support both ways for Debian for a while)

Over time, as GUI things adjust to the 'systemd --user'-style model, I
anticipate that the disadvantages of the user-session bus will decrease
and its advantages will increase; maybe one day nobody will use
dbus-launch and it can be deleted.

S
Lennart Poettering
2015-02-02 22:16:24 UTC
Permalink
Post by Dimitri John Ledkov
Post by Simon McVittie
plus the obvious ones set by *dm, such as DISPLAY, or by PAM. Similarly,
a user's ~/.xsession can set arbitrary variables - mine sets CCACHE_DIR,
EDITOR, MPD_HOST and XDG_CONFIG_DIRS, among others.
The naive implementation would be to run a tool at the end of
/etc/X11/Xsession.d that uploads all of these into `dbus-daemon
--session` (if used) and into `systemd --user` (if used). However, not
notably, XDG_SESSION_ID from the login session should not be copied into
activated processes that exist outside any login session.
The rest of the email thread is adequate.
I would like to experiment with a user-bus, potentially in a transient
manner to have 3 buses: system, user, session busses. And migrate
things from session to user bus & experiment as to how much stuff
breaks. I think being explicit about session vs user bus would avoid
confusion, and will help manifest bugs & have a clear migration plan.
E.g. when org.freedesktop.Telepathy / ca.desrt.dconf moves to user
bus, things should know how to start talking to Telepathy/dconf over
user bus.
I'd be very careful with running things with three instead of two
busses, since most user services only open one bus connection, and
they assume they find all the user's services on that one
connection. If you now intrdouce a seperate user and session bus, you
will have to patch all those apps to keep connections open to both
busses, and individually check for each bus call they make which bus
they need to do that on.

I am pretty sure the going for 3 busses, instead of 2 is not worth the
effort and much much more work than just redefining "session" to
"user", the way we currently try to do in the kdbus context.

Note that we test this per-user bus daily, since its the default mode
of operation if you boot with kdbus turned on. For that, simply build
the kdbus kernel modules as well as systemd with kdbus. Then boot with
"kdbus" on the kernel cmdline and all should be good. We now ship with
all the necessary bits in systemd git to make this just work.

Lennart
--
Lennart Poettering, Red Hat
Lennart Poettering
2015-02-02 22:04:17 UTC
Permalink
Post by Simon McVittie
user-session
------------
I don't think there is a standard term for this so I'm making one up.
The XDG_RUNTIME_DIR specification says that there is at most one
XDG_RUNTIME_DIR per uid per machine, that it is created at the beginning
of the user's first login session, and that it is removed at the end of
a login session if no other login sessions remain for that uid.
systemd-logind implements those semantics, and also runs a `systemd --user`
for the lifetime of the user-session. Ubuntu previously used
libpam-xdg-runtime to provide compatible semantics without systemd.
The resulting situation looks something like this (assume all the
--------\ ========\\
login | user- ||
session | --------\ session || <- overlapping login session c42
23 | login | || shares the user-session with 23
--------/ session | || <- 23 ends but c42 keeps u.-session
c42 | || alive
--------\ | || <- 57 begins, shares u.-sess.
login | --------/ || <- c42 ends, 57 keeps user-session
session | || alive
57 | ||
--------/ ========// no more l.sessions, u.-session ends
--------\ ========\\ new l.session, u.-session starts
login | user- ||
session | session ||
... . ... ..
user-sessions do not have any meaningful identifier apart from their
owner's uid (strictly speaking, the owner's "loginuid", i.e. the user
who initially logged in, even if they su). They do not need another
identifier, because by definition there is only one per uid at a time.
Small addition: these "super-sessions" are slightly modulated by the
"linger" boolean setting that logind manages per-user. If that boolean
is true the user's "super-session" stays alive from boot to shutdown.
Post by Simon McVittie
Digression: (at least some) users and developers don't want that
----------------------------------------------------------------
Adding in here: note that firefox and some other apps actually lock
thheir configuration directory, so that it effectively a singleton
program per-user anyway. One of the most important apps of the user is
hence per-use anyway, even if started in a per-session context.
Post by Simon McVittie
"It's already been discussed multiple times on the list and
apparently a user bus is too confusing or not really useful unless
you make it a user bus shared across a network cluster. I don't
agree, and I think that the consequence of this stance will be a
proliferation of hacks like the one I just sketched out (not to
mention even grosser hacks like Ubuntu's ACPI scripts grepping the
environment of the user's processes in /proc to find their session
bus to tell their screensaver to lock)."
Not convinced that the ACPI thing is a good example. It's not a
confusion about session/user contexts, but more a confusion about
privileged code calling into unprvileged code, which should never
happen.
Post by Simon McVittie
This leaves the problem that, if you have chosen the
user-session-centric model, current D-Bus doesn't actually work very
well: we have dbus-launch and dbus-run-session for login-session-centric
D-Bus, but if you want to make D-Bus user-session-centric, you need to
resort to third-party user bus units like user-session-units, which
float around Github and somehow never make it upstream. I'm now on my
third unrelated work project that contains a copypaste of dbus.socket
and dbus.service, and I'm sure my colleagues have others - this is not
the flying car future I signed up for. So I would like to get this stuff
upstream into dbus.git.
So that the people who are happy with the complexities of the current
* ./configure --disable-user-bus: you get a login-session-centric world
* ./configure --enable-user-bus: you get a user-session-centric world
* configure either way and selectively install/delete files: you can
either have a login-session-centric or user-session-centric world,
depending what you install. (This is so I can have dbus-user-bus and
dbus-x11 binary packages in Debian, where the answer to "do A or do
B?" is always "both!", without having to compile everything twice;
the GNOME metapackage could eventually depend on dbus-user-bus.)
So far our logic in systemd was to simply set the $DBUS_SESSION_BUS_ADDRESS
to the user bus address, to redirect all access to the session bus to
the user bus.
Post by Simon McVittie
Sadly, not all the issues have been resolved yet. The biggest is
environment variables: on existing systems there is an expectation
that environment variables set by *dm, PAM, or /etc/X11/Xsession.d
(or the non-Debian equivalent) will be propagated into every process
in the session. In a brief survey of about half the Xsession.d scripts
* PULSE_SERVER
Note that PA can actually derive the PA server address from the X11
server, hence this is not strictly necessary.
Post by Simon McVittie
* ESPEAKER
* XDG_DATA_HOME, XDG_DATA_DIRS
* each variable printed by locale(1)
* VDPAU_DRIVER
* GTK_IM_MODULE, QT_IM_MODULE, QT4_IM_MODULE, CLUTTER_IM_MODULE,
XMODIFIERS
* GTK_MODULES
plus the obvious ones set by *dm, such as DISPLAY, or by PAM. Similarly,
a user's ~/.xsession can set arbitrary variables - mine sets CCACHE_DIR,
EDITOR, MPD_HOST and XDG_CONFIG_DIRS, among others.
At the hackfest Ryan suggested we should simply intrdouce a
~/.config/environment file or so, that is always sources in at the
beginning of each super-session. It wouldn't be a real shell script,
but only support the most basic environment assignments.
Post by Simon McVittie
The naive implementation would be to run a tool at the end of
/etc/X11/Xsession.d that uploads all of these into `dbus-daemon
--session` (if used) and into `systemd --user` (if used). However, not
notably, XDG_SESSION_ID from the login session should not be copied into
activated processes that exist outside any login session.
Note that as a tool to make this easy for the case of $DISPLAY, we
added "systemctl --user import-environent DISPLAY" which uploads specific
client env vars into the systemd instance. In fact, Kay recently added
to systemd a script that installs $(sysconfdir)/X11/xinit/xinitrc.d/50-systemd-user.sh
containing this

#!/bin/sh
systemctl --user import-environment DISPLAY XAUTHORITY

With this in place GNOME works pretty much flawlessly with kdbus and a
per-user bus.
Post by Simon McVittie
As a short-term solution, I'm tempted to write that tool, but make it
only upload a whitelisted set of variables automatically, and say "if
you install dbus-user-bus, you are expected to run this tool from your
~/.xsession if you need it".
I figure that tool already exists ;-)

Lennart
--
Lennart Poettering, Red Hat
David Herrmann
2015-02-03 09:28:56 UTC
Permalink
Hi

On Fri, Jan 30, 2015 at 9:30 AM, Simon McVittie
Post by Simon McVittie
[For those who are there, I'll be at the system hackfest today and at
FOSDEM this weekend, so if you are interested in these topics, please
talk to me about them; I'll try to summarize discussion to these lists.
For those not there, I'll try to keep up with responses via email and
raise any interesting points in person.]
I've recently been looking into D-Bus' interaction with X session
startup, systemd --user, upstart --user, and the definition of a
session. Every few months or years there is an attempt to sort out
whether D-Bus has a user bus or a session bus or what. Here is another,
with particular reference to systemd and potentially kdbus.
Terminology
===========
login session
-------------
A *login session* is as follows: when you log in to *dm, that starts a
*graphical login session* which lasts until you log out. When you log in
on a virtual console or via ssh or something, that starts a
*non-graphical login session*. Background processes like cron or screen
might also be non-graphical login sessions. A non-graphical login
session might become graphical by running startx or similar.
We don't support turning text-sessions into graphical sessions (like
'startx' and friends). It works in some scenarios, but is strongly
frowned upon. Furthermore, VT sessions should really be treated like
graphical sessions. From a technical viewpoint, there is no
difference. And with things like kmscon or systemd-console, you really
*have* to treat it the same as graphical logins.
Post by Simon McVittie
In a systemd-logind environment, login sessions have an ID which is
made available to in-session processes in the XDG_SESSION_ID environment
variable. If the Linux "auditing" feature is enabled, the XDG_SESSION_ID
equals the audit session ID (/proc/self/sessionid). If not,
there is no audit session ID, so systemd-logind makes up a sequential
XDG_SESSION_ID and uses that.
seat
----
A seat is a set of displays, input devices etc. attached to a machine.
Most machines have one seat "seat0", which occupies all the devices.
'all the devices' is not exactly right. We still distinguish between
'seated' devices and 'non-seated' devices. That is, some devices are
always global and never assigned to a seat (like power-buttons, though
that particular example might even be broken right now).

But yes, all 'seated' devices are assigned to 'seat0' implicitly, if
not set otherwise.
Post by Simon McVittie
By attaching additional devices via something like
http://plugable.com/products/ud-160-m you can construct a
multi-seat machine.
user-session
------------
I don't think there is a standard term for this so I'm making one up.
The XDG_RUNTIME_DIR specification says that there is at most one
XDG_RUNTIME_DIR per uid per machine, that it is created at the beginning
of the user's first login session, and that it is removed at the end of
a login session if no other login sessions remain for that uid.
systemd-logind implements those semantics, and also runs a `systemd --user`
for the lifetime of the user-session. Ubuntu previously used
libpam-xdg-runtime to provide compatible semantics without systemd.
The resulting situation looks something like this (assume all the
--------\ ========\\
login | user- ||
session | --------\ session || <- overlapping login session c42
23 | login | || shares the user-session with 23
--------/ session | || <- 23 ends but c42 keeps u.-session
c42 | || alive
--------\ | || <- 57 begins, shares u.-sess.
login | --------/ || <- c42 ends, 57 keeps user-session
session | || alive
57 | ||
--------/ ========// no more l.sessions, u.-session ends
--------\ ========\\ new l.session, u.-session starts
login | user- ||
session | session ||
... . ... ..
user-sessions do not have any meaningful identifier apart from their
owner's uid (strictly speaking, the owner's "loginuid", i.e. the user
who initially logged in, even if they su). They do not need another
identifier, because by definition there is only one per uid at a time.
Impact on D-Bus
===============
There are two models for how the D-Bus session bus, which is designed to
be per "high-level session" (whatever that means), can work in a world
with user-sessions.
Last time this was discussed, Havoc had the useful insight that this is
not really a question about D-Bus, it's a question about how you build
OSs, and in particular how you model sessions.
(Up to) one high-level session per login
----------------------------------------
The first model, which is how it traditionally worked (before there was
such a thing as a user-session), is that each graphical login session is
declared to be a "session", and non-graphical login sessions are pretty
much swept under the carpet and forgotten about.
In graphical sessions, vaguely modern Unix OSs typically know how to
start up a dbus-daemon during the creation of a graphical session (e.g.
in Debian and derivatives it's started by /etc/X11/Xsession.d, and
Fedora derivatives have a similar setup under a different name). If they
don't, modern desktop environments also know how to start a dbus-daemon
if they need one (e.g. gnome-session does this for GNOME), and if *that*
doesn't start one (the "I use Firefox under fvwm" use-case), we have a
slightly shaky but functional "autolaunch" mechanism based on X11
properties.
In principle, a PAM module or something could ensure that we have a
dbus-daemon per login session, even tty/ssh/cron login sessions
(which all go through PAM). In practice, nobody has ever cared enough to
implement this, so we're left with D-Bus autolaunch, which can't
actually work for tty sessions and had bad side-effects from its
attempts to do so, so I disabled it 3 years ago in favour of
recommending that users requiring a D-Bus session should start their own
and manage its lifetime themselves e.g. with dbus-run-session(1).
If people want to put work into this model, we could do a lot better
than we do now; for instance, the bus socket could be
unix:path=${XDG_RUNTIME_DIR}/sessions/${XDG_SESSION_ID}/bus (but with
the necessary escaping) on systems where those variables are set, rather
than messing about with $TMPDIR.
However, the people doing the work have a somewhat strong correlation
with the people who want a different model, for which read on...
Digression: (at least some) users and developers don't want that
----------------------------------------------------------------
One major issue with one high-level session (and hence one session bus)
per login session is that it places an artifical barrier between login
sessions. It's difficult for cron jobs, ssh logins, tty logins to share
non-GUI backend services such as dconf, Rygel, Telepathy: on my NAS box,
which runs Rygel with no GUI to export my music in a way the
notoriously picky PS3 system software can understand, I had to
construct a D-Bus session to let Rygel and Tracker components talk
to each other. Happily, I had already written dbus-run-session(1),
but I shouldn't need to do this rubbish to let non-GUI daemons talk
to each other - it should just work.
Similarly, if you leave a screen/tmux session detached and running
in the background, systemd is fine with that: its view of the world
is that there are processes left over from your previous login session,
keeping the login session alive in "closing" state, with the consequence
that the user-session remains alive too (unless you have configured
systemd-logind to kill leftover processes, as required by the sysadmins
of computer labs and other massively multi-user machines, in which case
you don't get to run screen sessions and that's by design).
the dbus-daemon dies with the X server, the D-Bus services die with
the dbus-daemon, and now the duplicity(1) process in your screen session
can't use gvfs to upload your backups to a server (or whatever).
Another issue is that it is an extremely poor match for how
`systemd --user` works (although apparently a better match for
how Ubuntu uses `upstart --user`, which I hope to discuss with Ubuntu
people at the systemd hackfest today / at FOSDEM) - you can't use
systemd to manage your login-session-bound D-Bus services, because they
all share a systemd, which doesn't know which login session wants which
service.
I think it's telling that, in recent discussion with Ubuntu developers
about their use of one `upstart --user` per login session, they
clarified that they only actually do this for *graphical* login
sessions, and they provide tools to let a developer copy the environment
variables from what, conceptually, should be another session,
effectively "joining" that session for a subtree of processes. I think
"It's already been discussed multiple times on the list and
apparently a user bus is too confusing or not really useful unless
you make it a user bus shared across a network cluster. I don't
agree, and I think that the consequence of this stance will be a
proliferation of hacks like the one I just sketched out (not to
mention even grosser hacks like Ubuntu's ACPI scripts grepping the
environment of the user's processes in /proc to find their session
bus to tell their screensaver to lock)."
One high-level session per user-session
---------------------------------------
As a result of the problems noted above, various people, most vocally
the systemd and GNOME developers, have advocated a different model
for how to model sessions in the OS - what I called "user-sessions"
above. A typical implementation of that idea forbids multiple graphical
login sessions altogether: if you type your username and password into
gdm while already logged in on another virtual console, it will just
vt-switch to your existing graphical login session and unlock it.
Under X11, that might well be the best we can do, because typical
X11 applications can't cope with being asked to put windows on more
than one $DISPLAY (although I've heard rumours that Emacs can, which
would make Emacs an ideal candidate to be a user-session service).
Under Wayland or similar future cleverness, hopefully there'll be
some way for a new login on a new seat to "steal" all the windows
from the inactive seat, or some way to merge both seats into
one big virtual display if the same person is using both (AIUI this
is what GNOME designers want to do), or some other clever solution.
What this means for D-Bus
-------------------------
This leaves the problem that, if you have chosen the
user-session-centric model, current D-Bus doesn't actually work very
well: we have dbus-launch and dbus-run-session for login-session-centric
D-Bus, but if you want to make D-Bus user-session-centric, you need to
resort to third-party user bus units like user-session-units, which
float around Github and somehow never make it upstream. I'm now on my
third unrelated work project that contains a copypaste of dbus.socket
and dbus.service, and I'm sure my colleagues have others - this is not
the flying car future I signed up for. So I would like to get this stuff
upstream into dbus.git.
So that the people who are happy with the complexities of the current
* ./configure --disable-user-bus: you get a login-session-centric world
* ./configure --enable-user-bus: you get a user-session-centric world
* configure either way and selectively install/delete files: you can
either have a login-session-centric or user-session-centric world,
depending what you install. (This is so I can have dbus-user-bus and
dbus-x11 binary packages in Debian, where the answer to "do A or do
B?" is always "both!", without having to compile everything twice;
the GNOME metapackage could eventually depend on dbus-user-bus.)
I think in practice that design will mean that by default, libdbus tries
to connect to both user-session- and login-session-centric locations for
the bus (but the "wrong one" for this OS will fail and the "right one"
will succeed), while dbus-user-bus and dbus-x11 would arrange for the
bus to listen in the appropriate place for one option or the other so
that the appropriate version succeeds.
Conveniently, this is what I've already implemented (in two
different ways): "try the user-session-centric path first, and if that
fails, fall back to login-session-centric autolaunch". There is the
slight nit that the server side of user-session-centric operation
requires systemd, although that could be argued to be a feature: the
other reasonable implementation is libpam-xdg-runtime, which AIUI is
unmaintained now that Ubuntu has switched to systemd-logind, and the
people who are avoiding systemd on general principles (hello Devuan!)
are probably the sort of people who are sufficiently change-averse to
prefer D-Bus to work the way it worked in 2005 (if they install it at
all). I'd be willing to consider implementations that work with other
service managers if their authors are willing to help maintain them.
The glorious(?) kdbus future
============================
kdbus is a proposed Linux kernel module providing
somewhat-D-Bus-compatible message-passing semantics (I'm being vague
because it's been 4 months since I last looked at it in detail - I hope
to return to it soon). To provide complete dbus-daemon-like
functionality, you also need a user-space process to create the bus and
manage activations; the
reference implementation, and so far the only implementation, is in
systemd.
The systemd developers who are working on the user-space counterpart
for kdbus have indicated that they have zero interest in supporting a
login-session-centric setup for session kdbus. In practice, I think
this means that the proponents of a login-session-centric world either
can't use kdbus in their sessions, or need to convince the relevant
developers that the added complexity of their model is worth it, or need
to write their own user-space for kdbus sessions and
disable systemd's. (It's not all bad - they can still use kdbus for
the system bus, which is already an improvement.)
Remaining issue: environment variables
======================================
Sadly, not all the issues have been resolved yet. The biggest is
environment variables: on existing systems there is an expectation
that environment variables set by *dm, PAM, or /etc/X11/Xsession.d
(or the non-Debian equivalent) will be propagated into every process
in the session. In a brief survey of about half the Xsession.d scripts
* PULSE_SERVER
* ESPEAKER
* XDG_DATA_HOME, XDG_DATA_DIRS
* each variable printed by locale(1)
* VDPAU_DRIVER
* GTK_IM_MODULE, QT_IM_MODULE, QT4_IM_MODULE, CLUTTER_IM_MODULE,
XMODIFIERS
* GTK_MODULES
plus the obvious ones set by *dm, such as DISPLAY, or by PAM. Similarly,
a user's ~/.xsession can set arbitrary variables - mine sets CCACHE_DIR,
EDITOR, MPD_HOST and XDG_CONFIG_DIRS, among others.
The naive implementation would be to run a tool at the end of
/etc/X11/Xsession.d that uploads all of these into `dbus-daemon
--session` (if used) and into `systemd --user` (if used). However, not
notably, XDG_SESSION_ID from the login session should not be copied into
activated processes that exist outside any login session.
As a short-term solution, I'm tempted to write that tool, but make it
only upload a whitelisted set of variables automatically, and say "if
you install dbus-user-bus, you are expected to run this tool from your
~/.xsession if you need it".
Thoughts?
Other than my two additions, I agree with Lennart.

Thanks
David
Stef Bon
2015-02-03 10:16:40 UTC
Permalink
Post by Simon McVittie
In principle, a PAM module or something could ensure that we have a
dbus-daemon per login session, even tty/ssh/cron login sessions
(which all go through PAM). In practice, nobody has ever cared enough to
implement this, so we're left with D-Bus autolaunch, which can't
actually work for tty sessions and had bad side-effects from its
attempts to do so, so I disabled it 3 years ago in favour of
recommending that users requiring a D-Bus session should start their own
and manage its lifetime themselves e.g. with dbus-run-session(1).
Hi all,

I've never understood why the session bus is started through dbus-launch.
Leave it to the login manager (not PAM), or provide the socket and
activate the session bus only when
some app is connecting to it, which can be a graphical session, but
may be also a console.

Stef
Simon McVittie
2015-02-03 12:40:42 UTC
Permalink
Post by Stef Bon
I've never understood why the session bus is started through dbus-launch.
If we move from a per-login-session to a per-user-session bus, then it
won't be; dbus-launch will become solely for the people who run twm
under xdm or something, but who still want to run (say) Firefox.
Post by Stef Bon
Leave it to the login manager (not PAM), or provide the socket and
activate the session bus only when
some app is connecting to it, which can be a graphical session, but
may be also a console.
That is what I plan to do.

S
Simon McVittie
2015-02-11 21:18:19 UTC
Permalink
Post by Simon McVittie
So that the people who are happy with the complexities of the current
* ./configure --disable-user-bus: you get a login-session-centric world
* ./configure --enable-user-bus: you get a user-session-centric world
* configure either way and selectively install/delete files: you can
either have a login-session-centric or user-session-centric world,
depending what you install. (This is so I can have dbus-user-bus and
dbus-x11 binary packages in Debian, where the answer to "do A or do
B?" is always "both!", without having to compile everything twice;
the GNOME metapackage could eventually depend on dbus-user-bus.)
Implemented by:

https://bugs.freedesktop.org/show_bug.cgi?id=61303
followed by
https://bugs.freedesktop.org/show_bug.cgi?id=61301
--
Simon McVittie
Collabora Ltd. <http://www.collabora.com/>
Loading...