chiark / gitweb /
bus: it's OK to send messages with an empty payload but non-empty signature
[elogind.git] / src / libsystemd-bus / bus-message.c
index 9b4da3d3d3be90690f971dceec5ff24ab610af69..32af8609b3d0c0264aac21e99e33a389f02cf073 100644 (file)
@@ -1131,9 +1131,7 @@ static void message_extend_containers(sd_bus_message *m, size_t expand) {
 }
 
 static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz, bool add_offset) {
-        struct bus_body_part *part = NULL;
-        size_t start_body, end_body, padding, start_part, end_part, added;
-        bool add_new_part;
+        size_t start_body, end_body, padding, added;
         void *p;
         int r;
 
@@ -1156,54 +1154,61 @@ static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz, boo
                 return NULL;
         }
 
-        add_new_part =
-                m->n_body_parts <= 0 ||
-                m->body_end->sealed ||
-                padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
+        if (added > 0) {
+                struct bus_body_part *part = NULL;
+                bool add_new_part;
+
+                add_new_part =
+                        m->n_body_parts <= 0 ||
+                        m->body_end->sealed ||
+                        padding != ALIGN_TO(m->body_end->size, align) - m->body_end->size;
+
+                if (add_new_part) {
+                        if (padding > 0) {
+                                part = message_append_part(m);
+                                if (!part)
+                                        return NULL;
+
+                                part_zero(part, padding);
+                        }
 
-        if (add_new_part) {
-                if (padding > 0) {
                         part = message_append_part(m);
                         if (!part)
                                 return NULL;
 
-                        part_zero(part, padding);
-                }
+                        r = part_make_space(m, part, sz, &p);
+                        if (r < 0)
+                                return NULL;
+                } else {
+                        struct bus_container *c;
+                        void *op;
+                        size_t os, start_part, end_part;
 
-                part = message_append_part(m);
-                if (!part)
-                        return NULL;
+                        part = m->body_end;
+                        op = part->data;
+                        os = part->size;
 
-                r = part_make_space(m, part, sz, &p);
-                if (r < 0)
-                        return NULL;
-        } else {
-                struct bus_container *c;
-                void *op;
-                size_t os;
+                        start_part = ALIGN_TO(part->size, align);
+                        end_part = start_part + sz;
 
-                part = m->body_end;
-                op = part->data;
-                os = part->size;
+                        r = part_make_space(m, part, end_part, &p);
+                        if (r < 0)
+                                return NULL;
 
-                start_part = ALIGN_TO(part->size, align);
-                end_part = start_part + sz;
+                        if (padding > 0) {
+                                memset(p, 0, padding);
+                                p = (uint8_t*) p + padding;
+                        }
 
-                r = part_make_space(m, part, end_part, &p);
-                if (r < 0)
-                        return NULL;
+                        /* Readjust pointers */
+                        for (c = m->containers; c < m->containers + m->n_containers; c++)
+                                c->array_size = adjust_pointer(c->array_size, op, os, part->data);
 
-                if (padding > 0) {
-                        memset(p, 0, padding);
-                        p = (uint8_t*) p + padding;
+                        m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
                 }
-
-                /* Readjust pointers */
-                for (c = m->containers; c < m->containers + m->n_containers; c++)
-                        c->array_size = adjust_pointer(c->array_size, op, os, part->data);
-
-                m->error.message = (const char*) adjust_pointer(m->error.message, op, os, part->data);
-        }
+        } else
+                /* Return something that is not NULL and is aligned */
+                p = (uint8_t *) NULL + align;
 
         m->header->body_size = end_body;
         message_extend_containers(m, added);
@@ -2021,7 +2026,7 @@ static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c,
         if (!BUS_MESSAGE_IS_GVARIANT(m))
                 return 0;
 
-        p = c->signature;
+        p = strempty(c->signature);
         while (*p != 0) {
                 size_t n;
 
@@ -2069,7 +2074,7 @@ static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c,
                 if (!a)
                         return -ENOMEM;
 
-                p = c->signature;
+                p = strempty(c->signature);
                 for (i = 0, j = 0; i < c->n_offsets; i++) {
                         unsigned k;
                         size_t n;
@@ -2399,10 +2404,12 @@ _public_ int sd_bus_message_append_array_space(
 
         assert_return(m, -EINVAL);
         assert_return(!m->sealed, -EPERM);
-        assert_return(bus_type_is_trivial(type), -EINVAL);
+        assert_return(bus_type_is_trivial(type) && type != SD_BUS_TYPE_BOOLEAN, -EINVAL);
         assert_return(ptr || size == 0, -EINVAL);
         assert_return(!m->poisoned, -ESTALE);
 
+        /* alignment and size of the trivial types (except bool) is
+         * identical for gvariant and dbus1 marshalling */
         align = bus_type_get_alignment(type);
         sz = bus_type_get_size(type);
 
@@ -2549,8 +2556,8 @@ _public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
         part->size = size;
         copy_fd = -1;
 
-        message_extend_containers(m, size);
         m->header->body_size += size;
+        message_extend_containers(m, size);
 
         return sd_bus_message_close_container(m);
 }
@@ -2964,8 +2971,12 @@ static int container_next_item(sd_bus_message *m, struct bus_container *c, size_
                         *rindex = ALIGN_TO(c->offsets[c->offset_index], alignment);
                         c->item_size = c->offsets[c->offset_index+1] - *rindex;
                 } else {
+
+                        if (c->offset_index+1 >= (c->end-c->begin)/sz)
+                                goto end;
+
                         /* Fixed-size array */
-                        *rindex += sz;
+                        *rindex = c->begin + (c->offset_index+1) * sz;
                         c->item_size = sz;
                 }
 
@@ -3549,12 +3560,20 @@ static int build_struct_offsets(
         int r;
 
         assert(m);
-        assert(signature);
         assert(item_size);
         assert(offsets);
         assert(n_offsets);
 
+        if (isempty(signature)) {
+                *item_size = 0;
+                *offsets = NULL;
+                *n_offsets = 0;
+                return 0;
+        }
+
         sz = determine_word_size(size, 0);
+        if (sz <= 0)
+                return -EBADMSG;
 
         /* First, loop over signature and count variable elements and
          * elements in general. We use this to know how large the
@@ -3892,6 +3911,7 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m,
 
 _public_ int sd_bus_message_exit_container(sd_bus_message *m) {
         struct bus_container *c;
+        unsigned saved;
         int r;
 
         assert_return(m, -EINVAL);
@@ -3923,7 +3943,10 @@ _public_ int sd_bus_message_exit_container(sd_bus_message *m) {
 
         c = message_get_container(m);
 
+        saved = c->index;
+        c->index = c->saved_index;
         r = container_next_item(m, c, &m->rindex);
+        c->index = saved;
         if (r < 0)
                 return r;
 
@@ -4127,6 +4150,9 @@ _public_ int sd_bus_message_rewind(sd_bus_message *m, int complete) {
                 m->rindex = c->begin;
         }
 
+        c->offset_index = 0;
+        c->item_size = c->n_offsets > 0 ? c->offsets[0] : c->end;
+
         return !isempty(c->signature);
 }
 
@@ -4825,7 +4851,7 @@ int bus_message_parse_fields(sd_bus_message *m) {
         uint32_t unix_fds = 0;
         void *offsets = NULL;
         unsigned n_offsets = 0;
-        size_t sz;
+        size_t sz = 0;
         unsigned i = 0;
 
         assert(m);
@@ -5059,9 +5085,6 @@ int bus_message_parse_fields(sd_bus_message *m) {
         if (m->n_fds != unix_fds)
                 return -EBADMSG;
 
-        if (isempty(m->root_container.signature) != (BUS_MESSAGE_BODY_SIZE(m) == 0))
-                return -EBADMSG;
-
         switch (m->header->type) {
 
         case SD_BUS_MESSAGE_SIGNAL:
@@ -5276,7 +5299,7 @@ _public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complet
         assert_return(m, NULL);
 
         c = complete ? &m->root_container : message_get_container(m);
-        return c->signature ?: "";
+        return strempty(c->signature);
 }
 
 _public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {