D-Bus policies. system bus and bus names

Simon McVittie smcv at collabora.com
Wed May 31 11:04:55 UTC 2017


On Tue, 30 May 2017 at 23:07:08 +0200, David Sommerseth wrote:
>     <allow own_prefix="net.openvpn.v3.backends"/>

This is fine. This is what own_prefix is intended for.

>     <allow send_interface="net.openvpn.v3.backends"/>
[...]
> the man page explicitly tells me NOT to only use send_interface in
> an allow or deny rule.
>
> The trouble is that it seems to be lacking a send_destination variant
> similar to own_prefix.

I'd be happy to review a spec and implementation for
send_destination_prefix if you want to contribute one, although that
won't help you until it's widely deployed.

However, you can emulate it on existing dbus-daemons like this:

* In an appropriate <policy> to describe legitimate OpenVPN backends
  (probably <policy user="root">), have
  <allow own="net.openvpn.v3.any_backend"/> in addition to the own_prefix
  rule you already have

* In each backend, request the name net.openvpn.v3.any_backend without
  using the DBUS_NAME_FLAG_DO_NOT_QUEUE flag (you may specify
  ALLOW_REPLACEMENT and/or REPLACE_EXISTING, or not, whichever you prefer).
  Do not consider DBUS_REQUEST_NAME_REPLY_IN_QUEUE to be an error.

* In clients, do not send any messages with destination
  net.openvpn.v3.any_backend, because that would be useless (the client
  cannot know which member of the queue will get the message).

* In an appropriate <policy> to describe legitimate clients that will
  communicate with the backends (probably
  <policy context="default"> or <policy user="root">?), have
  <allow send_destination="net.openvpn.v3.any_backend"/>.
  If you want to do finer-grained access-control than "only root",
  "only this daemon user" or "all users", you should use probably polkit
  instead of adjusting the <policy>: see
  <http://smcv.pseudorandom.co.uk/2015/why_polkit/> for background.

In effect, requesting net.openvpn.v3.any_backend is acting as an opt-in
mechanism: by requesting that name, a backend opts in to allowing
legitimate clients of OpenVPN backends to communicate with it.

You might think that the last allow rule I mentioned just allows sending
messages whose destination field is literally net.openvpn.v3.any_backend,
but that is not the case. Instead, it allows sending messages that will be
delivered to *a connection that has requested* net.openvpn.v3.any_backend,
either its primary owner or any potential owner in the queue - the
destination field in the message may be the unique name, or any other
well-known name owned by the same connection.

> If I try this on the session bus, the policies doesn't seem to cause any
> challenges at all.

The session bus is not a security boundary. session.conf allows sending
and receiving all messages and owning all names, so further <allow> rules
are pointless (unless a domain-specific <deny> rule has been added
and the <allow> rules are opening holes in it).

The system bus is a security boundary between uids. system.conf allows
all processes to send signals and receive any message that was validly
sent, but does not allow sending method calls (or unrequested replies,
but you should never send those) without further configuration.

The system bus should perhaps only allow sending *broadcast* signals,
treating unicast signals as something that must be allowed explicitly, but
the XML policy language can't currently express that rule
(<https://bugs.freedesktop.org/show_bug.cgi?id=92853>).

> The master plan is that an "openvpn management daemon" is first started.
>  A front-end client (which the user interacts with) passes a
> configuration to this daemon over D-Bus, and tells it to start a tunnel
> with that configuration.  This management daemon forks out and
> "daemonizes" before and then starts the tunnel operations.

Using fork() without exec(), other than during very early process startup
as part of BSD-style daemonization, is usually a bad idea: it has a
tendency to leave global state in a weird mixture of what was correct
for the parent, and what is correct for the child, unless every library
in the process is extremely careful to use non-portable facilities
like pthread_atfork().

If you are using any non-trivial libraries (for example the GLib main
loop commonly used with D-Bus) then you should probably prefer to run
a subprocess that is a separate executable, via fork()-and-exec(),
or some wrapper API like posix_spawn() or GLib's GSubprocess.
A side benefit of this arrangement is that it gives you better
portability to Windows, which has APIs analogous to posix_spawn()
but does not have a direct equivalent of fork().

In your plan, do user processes (the user's GNOME or KDE GUI or whatever
other front-end client is relevant) communicate only with the centralized
management daemon, or do they also communicate with the individual backends
bypassing the centralized daemon? Either way is valid, but I need to give
slightly different advice depending on which one you have chosen.

> All this said, the "tunnel/session daemon" doesn't need to be on the
> system bus.  But I'm concerned what happens if the "management daemon"
> dies or gets restarted if the session bus is used.  Who does that
> session bus belong to?  I do want to be able to have a possibility to
> recover properly while avoiding tunnel interruptions.

The session bus belongs to either a (uid, machine) pair or a
(uid, X11 display) pair, depending how D-Bus was configured. It is not
appropriate for system-level processes, and processes with a different
uid are not allowed to connect to it.

Because the OpenVPN tunnels are providing networking facilities to the
whole system, and because they presumably need to run with root
privileges to be able to manipulate the routing table etc., I would say
that they need to be on the system bus.

> By the way, I'm targeting RHEL7 as the "oldest" Linux distribution to be
> supported.  And that is based on the d-bus-1.6.12 baseline (with a
> handful of backported fixes).

dbus 1.6.x is just about new enough to have own_prefix.

    S


More information about the dbus mailing list