chiark / gitweb /
sd-bus: add sd_bus_message.verify_destination_id and .destination_ptr
authorDaniel Mack <daniel@zonque.org>
Wed, 22 Oct 2014 12:41:53 +0000 (14:41 +0200)
committerDaniel Mack <daniel@zonque.org>
Tue, 11 Nov 2014 13:14:01 +0000 (14:14 +0100)
kdbus learned to accept both a numerical destination ID as well as a
well-known-name. In that case, kdbus makes sure that the numerical ID is in
fact the owner of the provided name and fails otherwise.

This allows for race-free assertion of a bus name owner while sending a
message, which is a requirement for bus-proxyd.

Add two new fields to sd_bus_message, and set the numerical ID to
verify_destination_id if bus_message_setup_kmsg() is called for a
message with a well-known name.

Also, set the destination's name in the kdbus item to .destination_ptr
if it is non-NULL.

Normal users should not touch these fields, and they're not publicy
accessible.

src/libsystemd/sd-bus/bus-kernel.c
src/libsystemd/sd-bus/bus-message.c
src/libsystemd/sd-bus/bus-message.h

index 153abee..5e7bc12 100644 (file)
@@ -204,6 +204,7 @@ static int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter
 static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
         struct bus_body_part *part;
         struct kdbus_item *d;
+        const char *destination;
         bool well_known;
         uint64_t unique;
         size_t sz, dl;
@@ -219,8 +220,10 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
         if (m->kdbus)
                 return 0;
 
-        if (m->destination) {
-                r = bus_kernel_parse_unique_name(m->destination, &unique);
+        destination = m->destination ?: m->destination_ptr;
+
+        if (destination) {
+                r = bus_kernel_parse_unique_name(destination, &unique);
                 if (r < 0)
                         return r;
 
@@ -244,7 +247,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
 
         /* Add in well-known destination header */
         if (well_known) {
-                dl = strlen(m->destination);
+                dl = strlen(destination);
                 sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
         }
 
@@ -264,9 +267,17 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
         m->kdbus->flags =
                 ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
                 ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
-        m->kdbus->dst_id =
-                well_known ? 0 :
-                m->destination ? unique : KDBUS_DST_ID_BROADCAST;
+
+        if (well_known) {
+                /* verify_destination_id will usually be 0, which makes the kernel driver only look
+                 * at the provided well-known name. Otherwise, the kernel will make sure the provided
+                 * destination id matches the owner of the provided weel-known-name, and fail if they
+                 * differ. Currently, this is only needed for bus-proxyd. */
+                m->kdbus->dst_id = m->verify_destination_id;
+        } else {
+                m->kdbus->dst_id = destination ? unique : KDBUS_DST_ID_BROADCAST;
+        }
+
         m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS;
         m->kdbus->cookie = (uint64_t) m->header->serial;
         m->kdbus->priority = m->priority;
@@ -284,7 +295,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
         d = m->kdbus->items;
 
         if (well_known)
-                append_destination(&d, m->destination, dl);
+                append_destination(&d, destination, dl);
 
         append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m));
 
@@ -299,7 +310,7 @@ static int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
                         continue;
                 }
 
-                if (part->memfd >= 0 && part->sealed && m->destination) {
+                if (part->memfd >= 0 && part->sealed && destination) {
                         /* Try to send a memfd, if the part is
                          * sealed and this is not a broadcast. Since we can only  */
 
index be36d9f..1a8c445 100644 (file)
@@ -148,6 +148,11 @@ static void message_free(sd_bus_message *m) {
         if (m->iovec != m->iovec_fixed)
                 free(m->iovec);
 
+        if (m->destination_ptr) {
+                free(m->destination_ptr);
+                m->destination_ptr = NULL;
+        }
+
         message_reset_containers(m);
         free(m->root_container.signature);
         free(m->root_container.offsets);
index df79294..8aa71fa 100644 (file)
@@ -100,6 +100,7 @@ struct sd_bus_message {
         usec_t realtime;
         uint64_t seqnum;
         int64_t priority;
+        uint64_t verify_destination_id;
 
         bool sealed:1;
         bool dont_send:1;
@@ -143,6 +144,7 @@ struct sd_bus_message {
 
         char sender_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
         char destination_buffer[3 + DECIMAL_STR_MAX(uint64_t) + 1];
+        char *destination_ptr;
 
         size_t header_offsets[_BUS_MESSAGE_HEADER_MAX];
         unsigned n_header_offsets;