X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-message.c;h=8d449c547827581950825a93c07dd6fa14e9c9bc;hb=815ebc540daf5cede58570bbeb0a4106e201c52e;hp=2e355a74c3609023d3b3d2404f0cb3cb227cd937;hpb=6647dc6659e1e42b3cff3cf5033ea5624000e650;p=elogind.git diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index 2e355a74c..8d449c547 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -791,7 +791,9 @@ _public_ sd_bus_message* sd_bus_message_ref(sd_bus_message *m) { } _public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) { - assert_return(m, NULL); + + if (!m) + return NULL; assert(m->n_ref > 0); m->n_ref--; @@ -1131,9 +1133,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 +1156,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); @@ -1889,9 +1896,7 @@ _public_ int sd_bus_message_open_container( } static size_t determine_word_size(size_t sz, size_t extra) { - if (sz <= 0 && extra == 0) - return 0; - else if (sz + extra <= 0xFF) + if (sz + extra <= 0xFF) return 1; else if (sz + extra*2 <= 0xFFFF) return 2; @@ -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); } @@ -2662,6 +2669,113 @@ _public_ int sd_bus_message_append_strv(sd_bus_message *m, char **l) { return sd_bus_message_close_container(m); } +static int bus_message_close_header(sd_bus_message *m) { + uint8_t *a; + size_t sz, i; + + assert(m); + + if (!BUS_MESSAGE_IS_GVARIANT(m)) + return 0; + + if (m->n_header_offsets < 1) + return 0; + + assert(m->header->fields_size == m->header_offsets[m->n_header_offsets-1]); + + sz = determine_word_size(m->header->fields_size, m->n_header_offsets); + + a = message_extend_fields(m, 1, sz * m->n_header_offsets, false); + if (!a) + return -ENOMEM; + + for (i = 0; i < m->n_header_offsets; i++) + write_word_le(a + sz*i, sz, m->header_offsets[i]); + + return 0; +} + +int bus_message_seal(sd_bus_message *m, uint64_t serial, usec_t timeout) { + struct bus_body_part *part; + size_t l, a; + unsigned i; + int r; + + assert(m); + + if (m->sealed) + return -EPERM; + + if (m->n_containers > 0) + return -EBADMSG; + + if (m->poisoned) + return -ESTALE; + + /* In vtables the return signature of method calls is listed, + * let's check if they match if this is a response */ + if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN && + m->enforced_reply_signature && + !streq(strempty(m->root_container.signature), m->enforced_reply_signature)) + return -ENOMSG; + + /* If gvariant marshalling is used we need to close the body structure */ + r = bus_message_close_struct(m, &m->root_container, false); + if (r < 0) + return r; + + /* If there's a non-trivial signature set, then add it in here */ + if (!isempty(m->root_container.signature)) { + r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL); + if (r < 0) + return r; + } + + if (m->n_fds > 0) { + r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds); + if (r < 0) + return r; + } + + r = bus_message_close_header(m); + if (r < 0) + return r; + + m->header->serial = serial; + m->timeout = m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED ? 0 : timeout; + + /* Add padding at the end of the fields part, since we know + * the body needs to start at an 8 byte alignment. We made + * sure we allocated enough space for this, so all we need to + * do here is to zero it out. */ + l = BUS_MESSAGE_FIELDS_SIZE(m); + a = ALIGN8(l) - l; + if (a > 0) + memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a); + + /* If this is something we can send as memfd, then let's seal + the memfd now. Note that we can send memfds as payload only + for directed messages, and not for broadcasts. */ + if (m->destination && m->bus && m->bus->use_memfd) { + MESSAGE_FOREACH_PART(part, i, m) + if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) { + bus_body_part_unmap(part); + + if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0) + part->sealed = true; + } + } + + m->root_container.end = BUS_MESSAGE_BODY_SIZE(m); + m->root_container.index = 0; + m->root_container.offset_index = 0; + m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0; + + m->sealed = true; + + return 0; +} + int bus_body_part_map(struct bus_body_part *part) { void *p; size_t psz; @@ -2858,8 +2972,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; } @@ -2927,9 +3045,6 @@ static int message_peek_body( assert(rindex); assert(align > 0); - if (message_end_of_array(m, *rindex)) - return 0; - start = ALIGN_TO((size_t) *rindex, align); padding = start - *rindex; end = start + nbytes; @@ -2949,7 +3064,7 @@ static int message_peek_body( } part = find_part(m, start, nbytes, (void**) &q); - if (!part || !q) + if (!part || (nbytes > 0 && !q)) return -EBADMSG; *rindex = end; @@ -2957,7 +3072,7 @@ static int message_peek_body( if (ret) *ret = q; - return 1; + return 0; } static bool validate_nul(const char *s, size_t l) { @@ -3036,7 +3151,7 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { bool ok; r = message_peek_body(m, &rindex, 1, c->item_size, &q); - if (r <= 0) + if (r < 0) return r; if (type == SD_BUS_TYPE_STRING) @@ -3063,7 +3178,7 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { assert(align > 0); r = message_peek_body(m, &rindex, align, c->item_size, &q); - if (r <= 0) + if (r < 0) return r; switch (type) { @@ -3127,15 +3242,13 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { bool ok; r = message_peek_body(m, &rindex, 4, 4, &q); - if (r <= 0) + if (r < 0) return r; l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); r = message_peek_body(m, &rindex, 1, l+1, &q); if (r < 0) return r; - if (r == 0) - return -EBADMSG; if (type == SD_BUS_TYPE_OBJECT_PATH) ok = validate_object_path(q, l); @@ -3151,15 +3264,13 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { uint8_t l; r = message_peek_body(m, &rindex, 1, 1, &q); - if (r <= 0) + if (r < 0) return r; l = *(uint8_t*) q; r = message_peek_body(m, &rindex, 1, l+1, &q); if (r < 0) return r; - if (r == 0) - return -EBADMSG; if (!validate_signature(q, l)) return -EBADMSG; @@ -3177,7 +3288,7 @@ _public_ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { assert(sz > 0); r = message_peek_body(m, &rindex, align, sz, &q); - if (r <= 0) + if (r < 0) return r; switch (type) { @@ -3276,7 +3387,7 @@ static int bus_message_enter_array( /* dbus1 */ r = message_peek_body(m, &rindex, 4, 4, &q); - if (r <= 0) + if (r < 0) return r; if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE) @@ -3289,8 +3400,6 @@ static int bus_message_enter_array( r = message_peek_body(m, &rindex, alignment, 0, NULL); if (r < 0) return r; - if (r == 0) - return -EBADMSG; *array_size = (uint32_t*) q; @@ -3319,8 +3428,6 @@ static int bus_message_enter_array( r = message_peek_body(m, &where, 1, sz, &q); if (r < 0) return r; - if (r == 0) - return -EBADMSG; framing = read_word_le(q, sz); if (framing > c->item_size - sz) @@ -3334,8 +3441,6 @@ static int bus_message_enter_array( r = message_peek_body(m, &where, 1, *n_offsets * sz, &q); if (r < 0) return r; - if (r == 0) - return -EBADMSG; *offsets = new(size_t, *n_offsets); if (!*offsets) @@ -3406,8 +3511,6 @@ static int bus_message_enter_variant( r = message_peek_body(m, &where, 1, 1+k, &q); if (r < 0) return r; - if (r == 0) - return -EBADMSG; if (*(char*) q != 0) return -EBADMSG; @@ -3421,15 +3524,11 @@ static int bus_message_enter_variant( r = message_peek_body(m, &rindex, 1, 1, &q); if (r < 0) return r; - if (r == 0) - return -EBADMSG; l = *(uint8_t*) q; r = message_peek_body(m, &rindex, 1, l+1, &q); if (r < 0) return r; - if (r == 0) - return -EBADMSG; if (!validate_signature(q, l)) return -EBADMSG; @@ -3462,12 +3561,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 @@ -3507,8 +3614,6 @@ static int build_struct_offsets( r = message_peek_body(m, &where, 1, n_variable * sz, &q); if (r < 0) return r; - if (r == 0) - return -EBADMSG; v = n_variable; @@ -3598,7 +3703,7 @@ static int enter_struct_or_dict_entry( /* dbus1 */ r = message_peek_body(m, &m->rindex, 8, 0, NULL); - if (r <= 0) + if (r < 0) return r; } else if (c->item_size <= 0) { @@ -3717,7 +3822,7 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m, /* Allow entering into anonymous containers */ r = sd_bus_message_peek_type(m, &tt, &cc); - if (r <= 0) + if (r < 0) return r; if (type != 0 && type != tt) @@ -3807,6 +3912,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); @@ -3838,7 +3944,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; @@ -3970,8 +4079,6 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char r = message_peek_body(m, &where, 1, k, &q); if (r < 0) return r; - if (r == 0) - goto eof; if (*(char*) q == 0) break; @@ -3996,15 +4103,11 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char r = message_peek_body(m, &rindex, 1, 1, &q); if (r < 0) return r; - if (r == 0) - goto eof; l = *(uint8_t*) q; r = message_peek_body(m, &rindex, 1, l+1, &q); if (r < 0) return r; - if (r == 0) - return -EBADMSG; if (!validate_signature(q, l)) return -EBADMSG; @@ -4048,6 +4151,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) - c->begin; + return !isempty(c->signature); } @@ -4434,7 +4540,7 @@ _public_ int sd_bus_message_read_array(sd_bus_message *m, if (align < 0) return align; - sz = c->item_size; + sz = c->end - c->begin; } else { align = bus_type_get_alignment(type); if (align < 0) @@ -4451,10 +4557,6 @@ _public_ int sd_bus_message_read_array(sd_bus_message *m, r = message_peek_body(m, &m->rindex, align, sz, &p); if (r < 0) goto fail; - if (r == 0) { - r = -EBADMSG; - goto fail; - } } r = sd_bus_message_exit_container(m); @@ -4750,7 +4852,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); @@ -4984,9 +5086,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: @@ -5035,112 +5134,6 @@ int bus_message_parse_fields(sd_bus_message *m) { return 0; } -static int bus_message_close_header(sd_bus_message *m) { - uint8_t *a; - size_t sz, i; - - assert(m); - - if (!BUS_MESSAGE_IS_GVARIANT(m)) - return 0; - - if (m->n_header_offsets < 1) - return 0; - - assert(m->header->fields_size == m->header_offsets[m->n_header_offsets-1]); - - sz = determine_word_size(m->header->fields_size, m->n_header_offsets); - - a = message_extend_fields(m, 1, sz * m->n_header_offsets, false); - if (!a) - return -ENOMEM; - - for (i = 0; i < m->n_header_offsets; i++) - write_word_le(a + sz*i, sz, m->header_offsets[i]); - - return 0; -} - -int bus_message_seal(sd_bus_message *m, uint64_t serial) { - struct bus_body_part *part; - size_t l, a; - unsigned i; - int r; - - assert(m); - - if (m->sealed) - return -EPERM; - - if (m->n_containers > 0) - return -EBADMSG; - - if (m->poisoned) - return -ESTALE; - - /* In vtables the return signature of method calls is listed, - * let's check if they match if this is a response */ - if (m->header->type == SD_BUS_MESSAGE_METHOD_RETURN && - m->enforced_reply_signature && - !streq(strempty(m->root_container.signature), m->enforced_reply_signature)) - return -ENOMSG; - - /* If gvariant marshalling is used we need to close the body structure */ - r = bus_message_close_struct(m, &m->root_container, false); - if (r < 0) - return r; - - /* If there's a non-trivial signature set, then add it in here */ - if (!isempty(m->root_container.signature)) { - r = message_append_field_signature(m, BUS_MESSAGE_HEADER_SIGNATURE, m->root_container.signature, NULL); - if (r < 0) - return r; - } - - if (m->n_fds > 0) { - r = message_append_field_uint32(m, BUS_MESSAGE_HEADER_UNIX_FDS, m->n_fds); - if (r < 0) - return r; - } - - r = bus_message_close_header(m); - if (r < 0) - return r; - - m->header->serial = serial; - - /* Add padding at the end of the fields part, since we know - * the body needs to start at an 8 byte alignment. We made - * sure we allocated enough space for this, so all we need to - * do here is to zero it out. */ - l = BUS_MESSAGE_FIELDS_SIZE(m); - a = ALIGN8(l) - l; - if (a > 0) - memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a); - - /* If this is something we can send as memfd, then let's seal - the memfd now. Note that we can send memfds as payload only - for directed messages, and not for broadcasts. */ - if (m->destination && m->bus && m->bus->use_memfd) { - MESSAGE_FOREACH_PART(part, i, m) - if (part->memfd >= 0 && !part->sealed && (part->size > MEMFD_MIN_SIZE || m->bus->use_memfd < 0)) { - bus_body_part_unmap(part); - - if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0) - part->sealed = true; - } - } - - m->root_container.end = BUS_MESSAGE_BODY_SIZE(m); - m->root_container.index = 0; - m->root_container.offset_index = 0; - m->root_container.item_size = m->root_container.n_offsets > 0 ? m->root_container.offsets[0] : 0; - - m->sealed = true; - - return 0; -} - _public_ int sd_bus_message_set_destination(sd_bus_message *m, const char *destination) { assert_return(m, -EINVAL); assert_return(destination, -EINVAL); @@ -5307,7 +5300,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) {