connection: check for msg->dst_id == name_entry->conn->id
authorDaniel Mack <daniel@zonque.org>
Wed, 8 Oct 2014 15:55:53 +0000 (17:55 +0200)
committerDaniel Mack <daniel@zonque.org>
Wed, 8 Oct 2014 15:55:53 +0000 (17:55 +0200)
When sending a message, we now allow both the ID and the name to be
specified. In such cases, make sure to reject the message if the
connection that currently owns the name does not match the given ID.

This allows us to tie the action of sending a message to the fact that
the connection still owns a certain name, which is essential for
enforcing a policy from userspace (bus-proxyd) in a race-free way.

Signed-off-by: Daniel Mack <daniel@zonque.org>
connection.c
kdbus.txt

index 8383bce2e64edd49a833cc92ffcd67d15f084729..3b7543e1c7e7c2d60317e94b6c9ea21ed89a0a5a 100644 (file)
@@ -705,15 +705,26 @@ int kdbus_conn_kmsg_send(struct kdbus_ep *ep,
                return 0;
        }
 
-       if (msg->dst_id == KDBUS_DST_ID_NAME) {
-               /* unicast message to well-known name */
-               BUG_ON(!kmsg->dst_name);
-
+       if (kmsg->dst_name) {
                name_entry = kdbus_name_lock(bus->name_registry,
                                             kmsg->dst_name);
                if (!name_entry)
                        return -ESRCH;
 
+               /*
+                * If both a name and a connection ID are given as destination
+                * of a message, check that the currently owning connection of
+                * the name matches the specified ID.
+                * This way, we allow userspace to send the message to a
+                * specific connection by ID only if the connection currently
+                * owns the given name.
+                */
+               if (msg->dst_id != KDBUS_DST_ID_NAME &&
+                   msg->dst_id != name_entry->conn->id) {
+                       ret = -EREMCHG;
+                       goto exit_name_unlock;
+               }
+
                if (!name_entry->conn && name_entry->activator)
                        conn_dst = kdbus_conn_ref(name_entry->activator);
                else
@@ -851,6 +862,7 @@ int kdbus_conn_kmsg_send(struct kdbus_ep *ep,
 
 exit_unref:
        kdbus_conn_unref(conn_dst);
+exit_name_unlock:
        kdbus_name_unlock(bus->name_registry, name_entry);
 
        return ret;
index 188709053b4c3568e7cc7809cf214acafd564c92..3aa6f13e6478dedf4511dcb71a4aac321f7c2018 100644 (file)
--- a/kdbus.txt
+++ b/kdbus.txt
@@ -751,6 +751,10 @@ struct kdbus_msg {
       Well-known name to send this message to. Required if dst_id is set
       to KDBUS_DST_ID_NAME. If a connection holding the given name can't
       be found, -ESRCH is returned.
+      For messages to a unique name (ID), this item is optional. If present,
+      the kernel will make sure the name owner matches the given unique name.
+      This allows userspace tie the message sending to the condition that a
+      name is currently owned by a certain unique name.
 };
 
 The message will be augmented by the requested metadata items when queued into
@@ -1664,6 +1668,8 @@ KDBUS_CMD_MSG_SEND
                answering
   -ECANCELED   A synchronous message sending was cancelled
   -ENOBUFS     Too many pending messages on the receiver side
+  -EREMCHG     Both a well-known name and a unique name (ID) was given, but
+               the name is not currently owned by that connection.
 
 For KDBUS_CMD_MSG_RECV: