Comment 63 for bug 306362

Revision history for this message
Scott James Remnant (Canonical) (canonical-scott) wrote :

Here's the technical summary:

The D-Bus protocol is made up of messages, the basic types of which are "method call", "reply", "error" and "signal".

Messages are policy-checked by the bus daemon. To be allowed, the message must past both the "send" rules (for the client) and the "receive" rules (for the service).

A method call is thus two messages: the "method call" sent from the client to the service, and a "reply" or "error" sent back from the service to the client. The client must have permission to send the "method call", and receive both "reply" and "error". The service must have permission to receive the "method call", and send both "reply" and "error".

A signal is a signal message: the "signal" is sent from a service to clients. The service must have permission to send the "signal". The clients must have permission to receive the "signal".

--

Policy is specified by a series of <allow> and <deny> rules for particular policy contexts (default, by user, etc.), and is in the /etc/dbus-1/system.conf file and the various service /etc/dbus-1/system.d/*.conf files.

The daemon simply concatenates the rules, it doesn't distinguish that a certain file comes from a certain service, etc. Remember that: it's important.

Since every message is checked for both send *and* receive, in practice, you only need to test one side of this. The standard so far has been to allow clients to send the message to you:

Here's an example for a typical service, this example is pastable:

  <policy user="root">
    <allow own="com.ubuntu.RoomService"/>
  </policy>

  <policy context="default">
    <allow send_destination="com.ubuntu.RoomService"/>
  </policy>

This allows the "root" user to own the "com.ubuntu.RoomService" bus name; and allows any user to send method calls to it.

If you wanted to restrict some method calls, you might do something like:

  <policy user="root">
    <allow own="com.ubuntu.RoomService"/>
    <allow send_destination="com.ubuntu.RoomService"/>
  </policy>

  <policy context="default">
    <allow send_destination="com.ubuntu.RoomService"/>
    <deny send_destination="com.ubuntu.RoomService" send_member="EvictGuest"/>
  </policy>

Note that we explicitly qualified the deny with a "send_destination"; otherwise we'd have denied the EvictGuest method call to *any* service, not just our own - which might be a different interface, or a different service entirely.

There is a case for using receive policy rules, restricting who can receive signals (which are otherwise allowed). For example, to only allow root to receive a signal:

  <policy user="root">
    <allow own="com.ubuntu.RoomService"/>
    <allow receive_sender="com.ubuntu.RoomService" receive_type="signal">
  </policy>

  <policy context="default">
    <allow send_destination="com.ubuntu.RoomService"/>
    <deny receive_sender="com.ubuntu.RoomService" receive_type="signal">
  </policy>

ie. root can own the bus name, and can receive signals from RoomService; everyone else can send method calls to RoomService but cannot receive signals from it.

Again note that we qualify with the sender, we don't want to deny signals from other services.

--

The above assumes that the default System Bus policy is:

 * deny owning a bus name
 * deny sending method calls
 * allow sending a reply to a method call, an error return
 * allow sending a signal
 * allow receiving all messages

Which is the default as of 1.2.8.

The first three points are probably non-controversial, it requires services to allow themselves to own a bus name, to allow clients to send the method calls - but doesn't require that they allow themselves to send a reply to those method calls.

The fourth and fifth are suggested because services have not been particularly careful about allowing clients to receive their signals or messages to date, and prevents breaking their configuration.

It's actually not possible to allow/deny sending a particular signal, because you can't match the sender, instead you would allow/deny receiving the signal.

A worry is that the default policy permits anyone to forge signals, with only the bus name being different - and relies on clients carefully checking the bus name. The standard dbus_message_is_signal() method call does not check the bus name.