[systemd-devel] Compatibility between D-Bus and kdbus

Lennart Poettering mzqohf at 0pointer.de
Wed Oct 1 13:40:44 PDT 2014


On Wed, 01.10.14 14:33, Simon McVittie (simon.mcvittie at collabora.co.uk) wrote:

Thanks a ton for reviewing kdbus and its concepts!

(Also, sorry for not responding earlier to all the dbus/kdbus traffic
in the last month, I was travelling.)

> System bus access-control policy
> ================================
> 
> I think this is the biggest point of incompatibility. In dbus-daemon
> there is a needlessly elaborate access-control language; in kdbus, there
> is a much simpler and more realistic access-control language, which
> specifically does not look into message payloads.
> 
> This is far easier to reason about than what dbus-daemon does, but it's
> a problem for any system service that assumes that its existing
> per-interface or per-method access-control will be applied, such as
> Avahi denying access to SetHostName. It is not acceptable for such
> services to get instant security flaws as a result of their D-Bus
> implementation being upgraded from a version that does not support kdbus
> to a version that does. Unfortunately, last time we discussed this, we
> didn't have a particularly good solution.
> 
> If I remember correctly, the least bad solution anyone could think of
> was to introduce a new pseudo-bus-type alongside DBUS_BUS_SYSTEM (and
> its equivalent in other libraries like GDBus), perhaps called
> "DBUS_BUS_SYSTEM_UNTRUSTED" or something (better names welcome), with
> its own shared connection: connections to that bus type are not assumed
> to filter messages by their payload, and method-call recipients are
> expected to use Polkit or similar, or do their own simplistic
> access-controls like "must be uid 0" by calling GetConnectionUnixUser or
> GetConnectionCredentials on the sender's unique name.

Yes, this is indeed the solution I have in mind, and I think Ryan is
mostly OK with this too for GLib.

> On non-kdbus systems, it would just be the same thing as
> DBUS_BUS_SYSTEM; on kdbus systems, DBUS_BUS_SYSTEM would refuse to use
> the kdbus transport, and fall back to stream-based D-Bus compatibility
> mechanisms like systemd-bus-proxyd. That would enable individual
> libraries and applications to opt-in to using this new shared connection
> when they have been audited for safety, with the goal being that
> everything eventually moved to it, and nothing connected to
> DBUS_BUS_SYSTEM any more.
> 
> I'm also very tempted to propose a syntax for an opt-in kdbus-like
> security model (which would take precedence over system.conf/system.d)
> via adding lines to .service files, so that individual services can have
> a sane security model on non-kdbus or non-Linux systems, and systemd's
> systemd-dbus1-generator could use those lines as input. If we get far
> enough with moving system services to that, maybe the transition can be
> easier.

If packages want compatibility with both kdbus/systemd and classic
dbus1, then I'd suggest to simply continue shipping the old XML policy
file fragments, plus the new systemd .busname unit. On dbus1 systems
the old policy would be used, on new kdbus systems the new policy
would be used. The app would of course be updated to use the new bus
name to connect to to acknowledge that it is responsible for doing
auth on its own. 

In this scheme compatbility should be easy: just add the new stuff on
top, and leave the old stuff in place, and things should be good. No
need to add anything new that would be a stop-gap and little else.

> Session bus access-control policy
> =================================
> 
> In principle, people could configure the session bus to do the same
> elaborate access-control as the system bus. In practice, this is not a
> particularly useful thing to do, because there are many ways for
> processes running under the same uid to subvert each other, particularly
> if a LSM like SELinux or AppArmor is not used.

Yes, Linux access control is built around UIDs, GIDs and labels, and I
am pretty strongly of the idea that we should do access control based
on exactly these credentials, but not come up with new access control
schemes betweend processes, that does not run along these lines.

> kdbus does not appear to make any attempt to protect a uid from itself:
> the uid that created a bus is considered to be privileged on that bus. I
> assume this means that the intention is that app sandboxing will use a
> separate Unix uid, like it does on Android?

Well, our idea about sandboxing for apps that it is mostly about
visibility, not just mere access control. Or in other words: if a
sandboxed app shall not be able to manipulate other processes then
these processes should not be visible to it at all (via PID
namespacing). Similar, if it is not supposed to be able to manipulate
per-user kernel settings, then this should also be solved by
visibility (via user namespacing) and so on. For kdbus this translates
to the "custom endpoint" logic, where you can add additional bus
device nodes for existing busses, that carry a second, stricter policy
that is applied on top of the main bus policy. This allows us to hide
bus services from sandboxed apps entirely.

So, you wonder whether we want to do app isolatin via uid/gid, but
this is not actually what we have in mind, we want to focus more on
namespacing on all levels.

> Unless there's an outcry from people who like LSMs, I'm inclined to say
> that protecting same-uid session processes from each other is doomed to
> failure, and hence that it's OK for DBUS_BUS_SESSION to connect to kdbus
> without special precautions.

I absolutely agree.

> In kdbus, each uid may connect to each bus up to 256 times. I think this
> is actually somewhat likely to be a practical problem: I currently have
> 46 connections to my session bus, so I'm only an order of magnitude away
> from the session breaking.
> <https://code.google.com/p/d-bus/issues/detail?id=9>

I fully agree, we should bump this limit quite a bit. Kay, Daniel?

> In kdbus, each connection may have 256 bloom filter entries, which AIUI
> are slightly less expressive than match rules (one match rule maps to
> one or more match rules). The system dbus-daemon defaults to allowing
> 512 match rules, and the session to 50 000. Again, I could potentially
> see this being an issue for existing code: Alban's benchmarking for
> GNOME + Telepathy back in 2011 revealed a peak of 81 match rules,
> although admittedly some of those were due to a dbus-glib bug[2]. QtDBus
> adds more / finer-grained match rules than GDBus or dbus-glib, so it
> might get this worse. I've opened a bug with a possible mitigation:
> <https://code.google.com/p/d-bus/issues/detail?id=10>

I also agree on this one, we should increase this, already from the beginning.

> fd-passing
> ==========
> 
> In stream-based D-Bus, any file descriptor may be attached to a message
> whose transport is a Unix domain socket, including another Unix domain
> socket. In kdbus, kdbus file descriptors and Unix domain sockets are
> currently specifically disallowed, to avoid recursion. I am not aware of
> any applications that actually do this: the developers of Tracker
> considered it, but ended up using a pipe() instead.

This is only temporary, we explicitly want to allow passing around
AF_UNIX sockets as soon as we can safely allow that.

> In stream-based D-Bus, it is valid to attach a file descriptor to a
> broadcast message. In kdbus, it is not. I am not aware of any
> applications that actually do this.

dbus1 should probably stop allowing fds in broadcast messages either...

> Bi-endian systems
> =================
> 
> The reference implementation of kdbus' userland part, in systemd,
> specifically requires that message payloads must be in native endianness
> for simplicity.
> 
> It is not clear to me what this would mean for CPU architectures that
> have runtime-switchable endianness, namely arm, powerpc and possibly
> mips. On these architectures, does Linux effectively impose the
> additional restriction that every process must run in the same
> endianness as the kernel, or what?

Well, the idea of allowing that is so broken already... I am pretty
sure people who want to make use of this have to fix a thousand other
things first, and if they really want to, they can certainly spend the
time and fix this in kdbus/systemd too. An easy way out is to simply
remarshall everything via bus-proxy, how we already support it anyway
for remote connections, where the endianess might differ between
sender and receiver.

> * Some operations that are method calls in stream-based D-Bus are
>   synchronous ioctls in kdbus. This can result in apparently
>   paradoxical situations like seeing a name in the equivalent of
>   ListNames before receiving the notification that it has an owner,
>   because the notification is processed asynchronously.
>   (Mitigation: it is fairly common to use "pseudo-blocking"
>   for these calls anyway.)

This indeed is a non-trivial departure from the effective guarantess
dbus1 made, and I have been thinking long about whether this actually
will end up being a problem or not.

(BTW, what's interesting here is that dbus1's client side actually
synchronously executes AddMatch and waits for the response, while
gdbus doesn't care for the response of AddMatch and sets the bit that
tells the driver to not bother with a response. I am pretty sure gdbus
does the right thing here actually. And in fact, sd-bus should
probably follow gdbus here, when it is run on old dbus1
streams... Given this behaviour of gdbus the nice thing is that the
ordering between NameOwnerChanged/NameAcquire/NameLost messages and
the response of AddMatch is irrelevant...)

But yeah, this last issue regarding the now synchronous nature of a
numbr of driver calls is the big incompatibility that I am personally
afraid of. So far we haven't heard of any real issues, but then again,
nobody is using kdbus seriously yet...

Thanks a lot for the review!

Lennart

-- 
Lennart Poettering, Red Hat


More information about the systemd-devel mailing list