X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Flibsystemd-bus%2Fbus-message.c;h=74ea71ec0d62bb6749898a384c0d993ed785c63f;hp=c385ef5ed05b1e39387e6e447677a827c6b2a25c;hb=ed205a6bc53735392b46fde6820520a1d18d6ebd;hpb=89ffcd2ad5bf87866314e96c4179ba622851cd6e diff --git a/src/libsystemd-bus/bus-message.c b/src/libsystemd-bus/bus-message.c index c385ef5ed..74ea71ec0 100644 --- a/src/libsystemd-bus/bus-message.c +++ b/src/libsystemd-bus/bus-message.c @@ -403,6 +403,8 @@ static int message_new_reply( if (!call) return -EINVAL; + if (!call->sealed) + return -EPERM; if (call->header->type != SD_BUS_MESSAGE_TYPE_METHOD_CALL) return -EINVAL; if (!m) @@ -766,11 +768,27 @@ int message_append_basic(sd_bus_message *m, char type, const void *p, const void case SD_BUS_TYPE_STRING: case SD_BUS_TYPE_OBJECT_PATH: + + if (!p) { + if (e) + c->signature[c->index] = 0; + + return -EINVAL; + } + align = 4; sz = 4 + strlen(p) + 1; break; case SD_BUS_TYPE_SIGNATURE: + + if (!p) { + if (e) + c->signature[c->index] = 0; + + return -EINVAL; + } + align = 1; sz = 1 + strlen(p) + 1; break; @@ -1356,8 +1374,7 @@ static int message_peek_body(sd_bus_message *m, size_t *rindex, size_t align, si return buffer_peek(m->body, BUS_MESSAGE_BODY_SIZE(m), rindex, align, nbytes, ret); } -static bool validate_string(const char *s, size_t l) { - assert(s); +static bool validate_nul(const char *s, size_t l) { /* Check for NUL chars in the string */ if (memchr(s, 0, l)) @@ -1367,6 +1384,14 @@ static bool validate_string(const char *s, size_t l) { if (s[l] != 0) return false; + return true; +} + +static bool validate_string(const char *s, size_t l) { + + if (!validate_nul(s, l)) + return false; + /* Check if valid UTF8 */ if (!utf8_is_valid(s)) return false; @@ -1375,12 +1400,8 @@ static bool validate_string(const char *s, size_t l) { } static bool validate_signature(const char *s, size_t l) { - /* Check for NUL chars in the signature */ - if (memchr(s, 0, l)) - return false; - /* Check for NUL termination */ - if (s[l] != 0) + if (!validate_nul(s, l)) return false; /* Check if valid signature */ @@ -1390,6 +1411,17 @@ static bool validate_signature(const char *s, size_t l) { return true; } +static bool validate_object_path(const char *s, size_t l) { + + if (!validate_nul(s, l)) + return false; + + if (!object_path_is_valid(s)) + return false; + + return true; +} + int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { struct bus_container *c; int r; @@ -1429,8 +1461,13 @@ int sd_bus_message_read_basic(sd_bus_message *m, char type, void *p) { if (r == 0) return -EBADMSG; - if (!validate_string(q, l)) - return -EBADMSG; + if (type == SD_BUS_TYPE_OBJECT_PATH) { + if (!validate_object_path(q, l)) + return -EBADMSG; + } else { + if (!validate_string(q, l)) + return -EBADMSG; + } m->rindex = rindex; *(const char**) p = q; @@ -1547,7 +1584,7 @@ static int bus_message_enter_array( if (r <= 0) return r; - if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > 67108864) + if (BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q) > BUS_ARRAY_MAX_SIZE) return -EBADMSG; r = message_peek_body(m, &rindex, alignment, 0, NULL); @@ -1704,6 +1741,25 @@ int sd_bus_message_enter_container(sd_bus_message *m, char type, const char *con if (!contents) return -EINVAL; + /* + * We enforce a global limit on container depth, that is much + * higher than the 32 structs and 32 arrays the specification + * mandates. This is simpler to implement for us, and we need + * this only to ensure our container array doesn't grow + * without bounds. We are happy to return any data from a + * message as long as the data itself is valid, even if the + * overall message might be not. + * + * Note that the message signature is validated when + * parsing the headers, and that validation does check the + * 32/32 limit. + * + * Note that the specification defines no limits on the depth + * of stacked variants, but we do. + */ + if (m->n_containers >= BUS_CONTAINER_DEPTH) + return -EBADMSG; + w = realloc(m->containers, sizeof(struct bus_container) * (m->n_containers + 1)); if (!w) return -ENOMEM; @@ -2084,12 +2140,11 @@ static int message_peek_fields( return buffer_peek(m->fields, BUS_MESSAGE_FIELDS_SIZE(m), rindex, align, nbytes, ret); } -static int message_peek_field_string( +static int message_peek_field_uint32( sd_bus_message *m, size_t *ri, - const char **ret) { + uint32_t *ret) { - size_t l; int r; void *q; @@ -2100,43 +2155,43 @@ static int message_peek_field_string( if (r < 0) return r; - l = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); - r = message_peek_fields(m, ri, 1, l+1, &q); - if (r < 0) - return r; - - if (!validate_string(q, l)) - return -EBADMSG; - if (ret) - *ret = q; + *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); return 0; } -static int message_peek_field_signature( +static int message_peek_field_string( sd_bus_message *m, + bool (*validate)(const char *p), size_t *ri, const char **ret) { - size_t l; + uint32_t l; int r; void *q; assert(m); assert(ri); - r = message_peek_fields(m, ri, 1, 1, &q); + r = message_peek_field_uint32(m, ri, &l); if (r < 0) return r; - l = *(uint8_t*) q; r = message_peek_fields(m, ri, 1, l+1, &q); if (r < 0) return r; - if (!validate_signature(q, l)) - return -EBADMSG; + if (validate) { + if (!validate_nul(q, l)) + return -EBADMSG; + + if (!validate(q)) + return -EBADMSG; + } else { + if (!validate_string(q, l)) + return -EBADMSG; + } if (ret) *ret = q; @@ -2144,23 +2199,32 @@ static int message_peek_field_signature( return 0; } -static int message_peek_field_uint32( +static int message_peek_field_signature( sd_bus_message *m, size_t *ri, - uint32_t *ret) { + const char **ret) { + size_t l; int r; void *q; assert(m); assert(ri); - r = message_peek_fields(m, ri, 4, 4, &q); + r = message_peek_fields(m, ri, 1, 1, &q); if (r < 0) return r; + l = *(uint8_t*) q; + r = message_peek_fields(m, ri, 1, l+1, &q); + if (r < 0) + return r; + + if (!validate_signature(q, l)) + return -EBADMSG; + if (ret) - *ret = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); + *ret = q; return 0; } @@ -2182,7 +2246,6 @@ static int message_skip_fields( for (;;) { char t; - void *q; size_t l; if (array_size != (uint32_t) -1 && @@ -2193,10 +2256,17 @@ static int message_skip_fields( if (!t) return 0; - if (t == SD_BUS_TYPE_STRING || - t == SD_BUS_TYPE_OBJECT_PATH) { + if (t == SD_BUS_TYPE_STRING) { - r = message_peek_field_string(m, ri, NULL); + r = message_peek_field_string(m, NULL, ri, NULL); + if (r < 0) + return r; + + (*signature)++; + + } else if (t == SD_BUS_TYPE_OBJECT_PATH) { + + r = message_peek_field_string(m, object_path_is_valid, ri, NULL); if (r < 0) return r; @@ -2213,8 +2283,8 @@ static int message_skip_fields( } else if (bus_type_is_basic(t)) { size_t align, k; - align = bus_type_get_alignment(align); - k = bus_type_get_size(align); + align = bus_type_get_alignment(t); + k = bus_type_get_size(t); r = message_peek_fields(m, ri, align, k, NULL); if (r < 0) @@ -2231,7 +2301,7 @@ static int message_skip_fields( assert(l >= 1); { char sig[l-1], *s; - size_t nas; + uint32_t nas; int alignment; strncpy(sig, *signature + 1, l-1); @@ -2241,12 +2311,10 @@ static int message_skip_fields( if (alignment < 0) return alignment; - r = message_peek_fields(m, ri, 4, 4, &q); + r = message_peek_field_uint32(m, ri, &nas); if (r < 0) return r; - - nas = BUS_MESSAGE_BSWAP32(m, *(uint32_t*) q); - if (nas > 67108864) + if (nas > BUS_ARRAY_MAX_SIZE) return -EBADMSG; r = message_peek_fields(m, ri, alignment, 0, NULL); @@ -2323,42 +2391,42 @@ static int message_parse_fields(sd_bus_message *m) { if (!streq(signature, "o")) return -EBADMSG; - r = message_peek_field_string(m, &ri, &m->path); + r = message_peek_field_string(m, object_path_is_valid, &ri, &m->path); break; case SD_BUS_MESSAGE_HEADER_INTERFACE: if (!streq(signature, "s")) return -EBADMSG; - r = message_peek_field_string(m, &ri, &m->interface); + r = message_peek_field_string(m, interface_name_is_valid, &ri, &m->interface); break; case SD_BUS_MESSAGE_HEADER_MEMBER: if (!streq(signature, "s")) return -EBADMSG; - r = message_peek_field_string(m, &ri, &m->member); + r = message_peek_field_string(m, member_name_is_valid, &ri, &m->member); break; case SD_BUS_MESSAGE_HEADER_ERROR_NAME: if (!streq(signature, "s")) return -EBADMSG; - r = message_peek_field_string(m, &ri, &m->error.name); + r = message_peek_field_string(m, error_name_is_valid, &ri, &m->error.name); break; case SD_BUS_MESSAGE_HEADER_DESTINATION: if (!streq(signature, "s")) return -EBADMSG; - r = message_peek_field_string(m, &ri, &m->destination); + r = message_peek_field_string(m, service_name_is_valid, &ri, &m->destination); break; case SD_BUS_MESSAGE_HEADER_SENDER: if (!streq(signature, "s")) return -EBADMSG; - r = message_peek_field_string(m, &ri, &m->sender); + r = message_peek_field_string(m, service_name_is_valid, &ri, &m->sender); break; @@ -2379,8 +2447,6 @@ static int message_parse_fields(sd_bus_message *m) { free(m->root_container.signature); m->root_container.signature = c; - - r = 0; break; } @@ -2389,6 +2455,12 @@ static int message_parse_fields(sd_bus_message *m) { return -EBADMSG; r = message_peek_field_uint32(m, &ri, &m->reply_serial); + if (r < 0) + return r; + + if (m->reply_serial == 0) + return -EBADMSG; + break; default: @@ -2441,14 +2513,17 @@ static void setup_iovec(sd_bus_message *m) { assert(m->sealed); m->n_iovec = 0; + m->size = 0; m->iovec[m->n_iovec].iov_base = m->header; m->iovec[m->n_iovec].iov_len = sizeof(*m->header); + m->size += m->iovec[m->n_iovec].iov_len; m->n_iovec++; if (m->fields) { m->iovec[m->n_iovec].iov_base = m->fields; m->iovec[m->n_iovec].iov_len = m->header->fields_size; + m->size += m->iovec[m->n_iovec].iov_len; m->n_iovec++; if (m->header->fields_size % 8 != 0) { @@ -2456,6 +2531,7 @@ static void setup_iovec(sd_bus_message *m) { m->iovec[m->n_iovec].iov_base = (void*) padding; m->iovec[m->n_iovec].iov_len = 8 - m->header->fields_size % 8; + m->size += m->iovec[m->n_iovec].iov_len; m->n_iovec++; } } @@ -2463,6 +2539,7 @@ static void setup_iovec(sd_bus_message *m) { if (m->body) { m->iovec[m->n_iovec].iov_base = m->body; m->iovec[m->n_iovec].iov_len = m->header->body_size; + m->size += m->iovec[m->n_iovec].iov_len; m->n_iovec++; } }