[systemd-devel] Support `systemd-run --machine M --user` for running unprivileged

Lennart Poettering lennart at poettering.net
Tue Mar 19 11:06:15 UTC 2019


On Mo, 18.03.19 17:04, Vito Caputo (vcaputo at pengaru.com) wrote:

> I'd personally appreciate being able to wire things up in my window
> manager where I can run things via hotkeys like:
>
> `systemd-run --machine finance --user firefox`
> `systemd-run --machine entertainment --user firefox`
>
> etc.
>
> These containers are already configured using systemd-nspawn, with the X
> socket bind-mounted.
>
> I'm not using user namespaces, so this is just trying to run things as
> the same uid inside the container as outside the container without root
> or polkit kludges.
>
> I can do this already using ssh and ssh keys, but it seems completely
> unnecessary - systemd is already running everywhere, and I can use the
> logind set-linger option to get the user instance up @ container boot.
>
> Has anyone taken a look at what the technical barriers are?  I can't be
> the only person wanting this kind of functionality.

Hmm, I think supporting this would make sense indeed. It should
probably feel like the ssh thing, i.e. so that

"systemd-run --machine=lennart at foobar --user firefox" does the right
thing. In fact, people keep asking for a way to connect to the user
bus of another local user all the time, and this could be a way to
safely provide that too (think: "systemd-run --machine=otheruser at .host
--user firefox"; making use of the ".host" alias which refers to the
local host system always).

A clean implementation would probably involve this:

1. Add an OpenUserBus() call to systemd-machined's bus API, like we
   already have OpenPTY(), OpenLogin(), OpenShell(),
   OpenRootDirectory() to get specific resources from a
   container. Most likely this new call should be implemented very
   similar to OpenShell() but instead of invoking $SHELL should call
   systemd-stdio-bridge running inside the container. It would return
   a connected AF_UNIX socket fd to the client.

2. Create a new host-side tiny binary that wraps this OpenUserBus()
   call: when invoked it calls it, and passes the AF_UNIX socket it
   acquires that way to its parent somehow.

3. Tweak sd-bus to call this new binary when connecting this way.

4. Expose this in systemd-run.

Why bother with systemd-machined here? We need a privileged component
somewhere, since entering the container requires privs.

Why bother with systemd-stdio-bridge inside the container? First of
all, this would match how the SSH case is handled: there too we call
systemd-stdio-bridge on the other side. The main reason though is
this: when connecting to the user bus we really should go through PAM
I think, so that a full PAM session is started (and thus systemd
--user potentially started, and thus dbus-daemon), limits applied and
$XDG_RUNTIME_DIR and $DBUS_SESSION_BUS_ADDRESS set in whatever way
desired. But if we to call PAM we need to go through PID 1 in the
container, and then we somehow need to call something there that then
propagates the dbus traffic to us. Ideally that could be a short
binary included in the container payload that simply passes a
connected socket back, but this means we'd have to have it already in
the container image included (otherwise we'd have to do it with some
statically compiled, inserted binary, which is ugly and
messy). systemd-stdio-bridge OTOH already exists, and does something
very similar. Only drawback: traffic is bumped off another process
instead of passing the naked AF_UNIX socket through. (But there are
some niceties by doing it this way too: the fact that
systemd-stdio-bridge is continously running inside a PAM session keeps
the user at .service instance inside the container – and its dbus
instance — pinned as long as the connection is going on.)

Why have the new tiny binary wrapping OpenUserBus()? We could also do
this inside the sd-bus library code, in-process. I think doing this
out of process is a bit nicer though, otherwise we'd have to use an
sd-bus connection to set up another sd-bus connection all hidden
behind the same sd-bus API, and I am not sure I like that kind of
recursive asynchronicity too much if it happens inside the same
process. But this is mostly a matter of taste, as it keeps things
simpler I think to just fork something off that does its own work and
then dies quickly.

Does that make sense?

Would love to review/merge patches for this (or something similar)!

Lennart

--
Lennart Poettering, Berlin


More information about the systemd-devel mailing list