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

Lennart Poettering mzqohf at 0pointer.de
Wed Nov 26 03:27:16 PST 2014


On Tue, 25.11.14 18:32, Thiago Macieira (thiago at kde.org) wrote:

> On Wednesday 26 November 2014 01:25:18 Lennart Poettering wrote:
> > > Thinking of non-system buses here.
> > > 
> > > If the variable is empty, I agree that it should have an equivalent of an
> > > "autostart" mechanism, but I disagree on the solution and I also disagree
> > > that distros should leave it empty.
> > 
> > Oh, no. No autostart please. No such concept exists in kdbus, and
> > systemd/sd-bus will not support that either. In fact I refuse to support
> > that even on dbus1 in sd-bus. Autostart is a kludge for systems where dbus
> > is just an add-on, but that's completely out-of-focus for kdbus,
> > systemd and sd-bus.
> 
> I didn't actually mean automatically starting the bus, sorry for the 
> confusion. I meant automatic discovery only. Currently on dbus1, "autostart:" 
> as a transport protocol means both auto discovery and automatic starting if 
> the bus isn't running.
> 
> Please also note that the autostart solution has a valid use-case which is 
> when a D-Bus application is launched in an environment where no bus had been 
> started before. I understand this is out-of-scope for kdbus, since after all a 
> regular user won't be able to create a kdbus bus if one wasn't provided by a 
> privileged process before. In an environment where a kdbus bus wasn't 
> provided, the only alternative is to fallback to dbus1.

Hmm? Creating busses requires no privileges. Users create their own
busses without requiring any kind of privilege for that.

You are free to implement autostart behaviour for dbus1 in your own
library, but this concept is not defined for kdbus.

> > No, we don't support weird setups where kdbusfs mounted
> > elsewhere. This is a bew API we introduce here, and we can very much
> > make decisions where stuff is to be mounted.
> 
> You may not support it in systemd, but from reading the kernel API that could 
> happen with another implementation.

Well, you can also mount /sys to /foobar and /proc to /waldo. No app
supports that though and the place where kdbusfs is mounted is simply
part of the kdbus API definition, and if you mount it anywhere else
you get to keep the pieces.

Note that we the kernel driver explicitly creates a dir /sys/fs/kdbus
in order to have a place where to mount it. The location is really not
configurable.

> > We initially tried to support that, but it's awfully racy, since the
> > driver calls and calls to other services wouldn't be executed in
> > strict order anymore... We removed this again after figuring out and
> > decided that emulation can only happen client side, synchronous to the
> > message stream if we want to guarantee correct ordering.
> 
> I'm not asking for AddMatch and connection control mechanisms. The one I 
> really want is StartServiceByName, since it can't be emulated. Moreover, 
> starting services is systemd's raison-d'ĂȘtre, so I feel it should be no 
> problem for you to provide such a service.

My recommendation for StartServiceByName() is to convert it into a
Ping() method call to the respective service and wait for it to
return. This is at least what the compat proxy does.

> It would be nice if UpdateActivationEnvironment worked. This functionality was 
> added for people who need to update variables like XDG_DATA_DIRS after 
> starting the bus. If this one isn't present, we can report "not implemented" 
> and be fine with it. We'll just have to tell people to configure their systemd 
> user session environments properly.
> 
> The same goes for ReloadConfig, but I'd prefer to know whether that failed (no 
> config reloading is possible) or whether it happens automatically whether the 
> call was made or not. ReloadConfig is important when there are new activatable 
> services on a user's bus, such as newly-installed applications.

If you really want to support this, then call into systemd for it, and
make it graceful to support non-systemd systems. Return a notsupported
error if the systemd service is not reachable.

> > > > The client side emulation can choose to either forward ReloadConifg
> > > > and UpdateActivationEnvironment to the respect systemd calls, or just
> > > > return som "not supported" error.
> > > 
> > > Can't do that. What if it's a kdbus system that is not systemd?
> > 
> > Well, again, return "not supported" then. I mean, currently there is
> > no kdbus userspace implementation beyond kdbus, we cannot really
> > discuss something that doesn't exist...
> 
> I assume you meant "beyond systemd" there.

Oops. Sorry, yes.

> > Note that on dbus1 systemd systems we actually never provided
> > UpdateActivationEnvironment correctly (since services got forked off
> > PID 1, instead of dbus-daemon but the call would alter dbus-daemon's
> > env block, not systemd's one), but nobody ever noticed. I really
> > think you should just return some "not supported" error or make it a
> > NOP if you don't want to pass this on to systemd.
> 
> I *want* to pass this to systemd, somehow. So the first question is whether we 
> can expect there to be a connection by systemd in the buses it creates. On the 
> system bus, there's org.freedesktop.systemd1 so I expect that to continue. Can 
> we expect a similar service on systemd-user buses?

Yes. systemd creates the bus and then acquires
org.freedesktop.systemd1 on it, and does this for both the system and
the user bus the same way. 

> > When creating the bus the creator can pass policy to the kernel so
> > that there is no time window where the bus is accessible and open to
> > manipulation from untrusted clients.
> 
> How can you update the policies then? 

There's an ioctl for that too, that the creator can then call on the
fd it has open. 

> I imagine that the typical scenario here would be to permit connections from 
> the same PID to be considered "privileged", so they can install new policies 
> and activators.

Only the creator can update policy, not normal peers. This is not
enforced by permission checks howver, but simply by the fact that bus
connection fds and creator fds are very different things. You cannot
use bus connectionf fds to set policy. And you cannot use creator fds
to own names or send messages. They are completely distinct.

> > > > if you want to create a new endpoint for an existing bus, then invoke
> > > > that ioctl on the bus fd. The control file after all is unrelated to
> > > > any bus, and thus wouldn#t know which bus you mean if we'd allow
> > > > invoking that ioctl on it.
> > > 
> > > Ok, so any application that connected to the "bus" bus can then create
> > > custom endpoints. Correct?
> > 
> > You need privs (either CAP_IPC_OWNER or matching uid) for that.
> 
> Understood. But that means a user's application connecting to the bus in 
> $DBUS_SESSION_BUS_ADDRESS is able to create new endpoints.

Well, yes. But we disabled that for clients connected to custom
EPs. Meaning: you can create custom EPs from the default EP, but not
additional custom EPs from a custom EP.

> > > How does one get to install policies or activators on this custom bus if
> > > the opening connection is a regular, non-privileged process?
> > 
> > the policy you can specify when you open the custom EP... (not sure I
> > grok the question though).
> 
> You got it right. The question on updating the policies above
> remains, though.

There's one ioctl that creates an EP that takes the initial policy as
parameter. If you then one day want to update the policy then you
invoke a second "update" ioctl that replaces the policy by a different
one atomically.

> > What's the usecase?
> > 
> > I mean you can fake p2p connections by allocating a bus and only
> > connecting two peers to it (busses are relatively cheap now), but I am
> > not sure why.
> 
> Because kdbus has a few extra advantages that sockets don't, like the zero- or 
> single-copy from process to process. And because we can: if the necessary 
> delta to support P2P is minimal, just a convention, then it's more practical 
> to keep everything centralised than to have an AF_UNIX socket handler and a 
> kdbus fd parser.

Well, but in those cases you can just use the user bus or system bus,
there's no need to create a new bus just for the purpose of P2P...

> > Well, I doubt the usecase for direct links.
> > 
> > I mean, the reasons for peer-to-peer links I am aware of are:
> > 
> > a) performance
> > b) network transparency
> > c) IPC before dbus-daemon is around
> > 
> > a) and c) don't apply on kdbus anymore. And kdbus is inherently not a
> > network transport, hence you have to use AF_INET there anyway.
> 
> Plus d) connection between processes of different privileges (e.g., different 
> UIDs)

Why not use the regular system bus for that?

> > > Because I thought that the activator may be one process for all possible
> > > services. I'm guessing this is not the way you'd envisioned it. Otherwise,
> > > if you have 200 activatable services, there are 200 connections by one or
> > > more process. There's no bus daemon to run out of fd's here, but they
> > > would count towards the user's system-wide file descriptor limit.
> > 
> > Yes, systemd maintains one fd per bus-activatable name, that is
> > correct. And it bumps the NOFILES limits to make sure that works.
> 
> Correct me if I'm wrong, but doesn't the kernel impose a per-UID limit on the 
> number of FDs open?

To my knowledge only one per-process.

> > Well, but you could just process what you want, and not read from the
> > fd anymore. Then you exit, leaving the messages in the fd unread. The
> > kernel will then activate the process again and pass the new messages
> > to it. I am not really sure what the usecase is for telling the kernel
> > explicitly that you don't want more messages...
> 
> Right that works for activatable services.
> 
> For non-activatable services, any unhandled calls will get 
> KDBUS_ITEM_REPLY_DEAD sent back to the sender. The only difference from what I 
> was asking is timing: with a KDBUS_CMD_SHUTDOWN, the error condition would 
> come as soon as the message was sent, as opposed to when the receiver closed 
> the fd. I don't think that is a problem.

But does that timing fix anything? I don't see any race that was fixed
by such differen behaviour.

> > > > > === Wildcards ===
> > > > > 
> > > > > Are you sure that * not matching a dot is a good idea? What is the
> > > > > rationale behind it?
> > > > 
> > > > Hmm, what precisely is this about? wildcards about?
> > > 
> > > Just wondering why the * does not match the dot. I'd assume the more
> > > common
> > > case is to match a full prefix and that includes match dots.
> > 
> > Hmm? * in what precisely? missing the context here...
> 
> 11.2 Wildcard names
> 
> "Policy holder connections may upload names that contain the wildcard suffix 
> (".*"). That way, a policy can be uploaded that is effective for every
> well-kwown name that extends the provided name by exactly one more level."
> 
> As I said, I kind of expect that the normal case is that the policy applies to 
> the entire tree, not just one more level.

Ah, OK, no I get the context!

So, dbus1 policy had this concept (see "own_prefix" in the man page)
and we deemed it to actually be a useful one, given that this opens up
using names as the synchronization primitive they are.

I think the reason to limit this to one label only is to keep a clear
distinction between what is namespace and what is instance. And
ensuring the instance is just the last label (for whatever you encode
into it) and the other labels are namespace...

In general it is always easy to be strict initially and then open
things up further when there's a strong usecase for it, rather than
the other way round.

Lennart

-- 
Lennart Poettering, Red Hat


More information about the systemd-devel mailing list