chiark / gitweb /
sd-bus: add extra assert check
[elogind.git] / src / libsystemd / sd-bus / bus-message.c
index 2c25b3f5f1723c3a0a6370ec022e7c50958394ad..ec3a39d051c82629ed3d945c5965204d13d098d3 100644 (file)
@@ -28,6 +28,7 @@
 #include "strv.h"
 #include "time-util.h"
 #include "cgroup-util.h"
+#include "memfd-util.h"
 
 #include "sd-bus.h"
 #include "bus-message.h"
@@ -70,7 +71,7 @@ static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
                         if (part->mapped > 0)
                                 assert_se(munmap(part->data, part->mapped) == 0);
 
-                        close_nointr_nofail(part->memfd);
+                        safe_close(part->memfd);
                 }
 
         } else if (part->munmap_this)
@@ -126,18 +127,18 @@ static void message_free(sd_bus_message *m) {
 
         message_reset_parts(m);
 
-        if (m->free_kdbus)
-                free(m->kdbus);
-
         if (m->release_kdbus) {
-                uint64_t off;
+                struct kdbus_cmd_free cmd_free;
 
-                off = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer;
-                ioctl(m->bus->input_fd, KDBUS_CMD_FREE, &off);
+                cmd_free.flags = 0;
+                cmd_free.offset = (uint8_t *)m->kdbus - (uint8_t *)m->bus->kdbus_buffer;
+                (void) ioctl(m->bus->input_fd, KDBUS_CMD_FREE, &cmd_free);
         }
 
-        if (m->bus)
-                sd_bus_unref(m->bus);
+        if (m->free_kdbus)
+                free(m->kdbus);
+
+        sd_bus_unref(m->bus);
 
         if (m->free_fds) {
                 close_many(m->fds, m->n_fds);
@@ -147,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);
@@ -194,7 +200,7 @@ static void *message_extend_fields(sd_bus_message *m, size_t align, size_t sz, b
 
         /* Zero out padding */
         if (start > old_size)
-                memset((uint8_t*) np + old_size, 0, start - old_size);
+                memzero((uint8_t*) np + old_size, start - old_size);
 
         op = m->header;
         m->header = np;
@@ -252,7 +258,7 @@ static int message_append_field_string(
                         return -ENOMEM;
 
                 p[0] = h;
-                memset(p+1, 0, 7);
+                memzero(p+1, 7);
                 memcpy(p+8, s, l);
                 p[8+l] = 0;
                 p[8+l+1] = 0;
@@ -337,7 +343,7 @@ static int message_append_field_uint32(sd_bus_message *m, uint8_t h, uint32_t x)
                         return -ENOMEM;
 
                 p[0] = h;
-                memset(p+1, 0, 7);
+                memzero(p+1, 7);
                 *((uint32_t*) (p + 8)) = x;
                 p[12] = 0;
                 p[13] = 'u';
@@ -373,6 +379,7 @@ int bus_message_from_header(
         struct bus_header *h;
         size_t a, label_sz;
 
+        assert(bus);
         assert(buffer || length <= 0);
         assert(fds || n_fds <= 0);
         assert(ret);
@@ -413,10 +420,20 @@ int bus_message_from_header(
         m->n_fds = n_fds;
 
         if (ucred) {
-                m->creds.uid = ucred->uid;
                 m->creds.pid = ucred->pid;
+                m->creds.uid = ucred->uid;
                 m->creds.gid = ucred->gid;
-                m->creds.mask |= SD_BUS_CREDS_UID | SD_BUS_CREDS_PID | SD_BUS_CREDS_GID;
+
+                /* Due to namespace translations some data might be
+                 * missing from this ucred record. */
+                if (m->creds.pid > 0)
+                        m->creds.mask |= SD_BUS_CREDS_PID;
+
+                if (m->creds.uid != UID_INVALID)
+                        m->creds.mask |= SD_BUS_CREDS_UID;
+
+                if (m->creds.gid != GID_INVALID)
+                        m->creds.mask |= SD_BUS_CREDS_GID;
         }
 
         if (label) {
@@ -426,10 +443,9 @@ int bus_message_from_header(
                 m->creds.mask |= SD_BUS_CREDS_SELINUX_CONTEXT;
         }
 
-        if (bus)
-                m->bus = sd_bus_ref(bus);
-
+        m->bus = sd_bus_ref(bus);
         *ret = m;
+
         return 0;
 }
 
@@ -489,6 +505,8 @@ fail:
 static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
         sd_bus_message *m;
 
+        assert(bus);
+
         m = malloc0(ALIGN(sizeof(sd_bus_message)) + sizeof(struct bus_header));
         if (!m)
                 return NULL;
@@ -500,24 +518,23 @@ static sd_bus_message *message_new(sd_bus *bus, uint8_t type) {
         m->header->version = bus ? bus->message_version : 1;
         m->allow_fds = !bus || bus->can_fds || (bus->state != BUS_HELLO && bus->state != BUS_RUNNING);
         m->root_container.need_offsets = BUS_MESSAGE_IS_GVARIANT(m);
-
-        if (bus)
-                m->bus = sd_bus_ref(bus);
+        m->bus = sd_bus_ref(bus);
 
         return m;
 }
 
 _public_ int sd_bus_message_new_signal(
                 sd_bus *bus,
+                sd_bus_message **m,
                 const char *path,
                 const char *interface,
-                const char *member,
-                sd_bus_message **m) {
+                const char *member) {
 
         sd_bus_message *t;
         int r;
 
-        assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
+        assert_return(bus, -ENOTCONN);
+        assert_return(bus->state != BUS_UNSET, -ENOTCONN);
         assert_return(object_path_is_valid(path), -EINVAL);
         assert_return(interface_name_is_valid(interface), -EINVAL);
         assert_return(member_name_is_valid(member), -EINVAL);
@@ -549,16 +566,17 @@ fail:
 
 _public_ int sd_bus_message_new_method_call(
                 sd_bus *bus,
+                sd_bus_message **m,
                 const char *destination,
                 const char *path,
                 const char *interface,
-                const char *member,
-                sd_bus_message **m) {
+                const char *member) {
 
         sd_bus_message *t;
         int r;
 
-        assert_return(!bus || bus->state != BUS_UNSET, -ENOTCONN);
+        assert_return(bus, -ENOTCONN);
+        assert_return(bus->state != BUS_UNSET, -ENOTCONN);
         assert_return(!destination || service_name_is_valid(destination), -EINVAL);
         assert_return(object_path_is_valid(path), -EINVAL);
         assert_return(!interface || interface_name_is_valid(interface), -EINVAL);
@@ -607,7 +625,7 @@ static int message_new_reply(
         assert_return(call, -EINVAL);
         assert_return(call->sealed, -EPERM);
         assert_return(call->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EINVAL);
-        assert_return(!call->bus || call->bus->state != BUS_UNSET, -ENOTCONN);
+        assert_return(call->bus->state != BUS_UNSET, -ENOTCONN);
         assert_return(m, -EINVAL);
 
         t = message_new(call->bus, type);
@@ -617,7 +635,7 @@ static int message_new_reply(
         t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
         t->reply_cookie = BUS_MESSAGE_COOKIE(call);
 
-        r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_cookie);
+        r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, (uint32_t) t->reply_cookie);
         if (r < 0)
                 goto fail;
 
@@ -647,8 +665,8 @@ _public_ int sd_bus_message_new_method_return(
 
 _public_ int sd_bus_message_new_method_error(
                 sd_bus_message *call,
-                const sd_bus_error *e,
-                sd_bus_message **m) {
+                sd_bus_message **m,
+                const sd_bus_error *e) {
 
         sd_bus_message *t;
         int r;
@@ -697,23 +715,23 @@ _public_ int sd_bus_message_new_method_errorf(
         bus_error_setfv(&error, name, format, ap);
         va_end(ap);
 
-        return sd_bus_message_new_method_error(call, &error, m);
+        return sd_bus_message_new_method_error(call, m, &error);
 }
 
 _public_ int sd_bus_message_new_method_errno(
                 sd_bus_message *call,
+                sd_bus_message **m,
                 int error,
-                const sd_bus_error *p,
-                sd_bus_message **m) {
+                const sd_bus_error *p) {
 
         _cleanup_free_ sd_bus_error berror = SD_BUS_ERROR_NULL;
 
         if (sd_bus_error_is_set(p))
-                return sd_bus_message_new_method_error(call, p, m);
+                return sd_bus_message_new_method_error(call, m, p);
 
         sd_bus_error_set_errno(&berror, error);
 
-        return sd_bus_message_new_method_error(call, &berror, m);
+        return sd_bus_message_new_method_error(call, m, &berror);
 }
 
 _public_ int sd_bus_message_new_method_errnof(
@@ -730,7 +748,7 @@ _public_ int sd_bus_message_new_method_errnof(
         bus_error_set_errnofv(&berror, error, format, ap);
         va_end(ap);
 
-        return sd_bus_message_new_method_error(call, &berror, m);
+        return sd_bus_message_new_method_error(call, m, &berror);
 }
 
 int bus_message_new_synthetic_error(
@@ -742,6 +760,7 @@ int bus_message_new_synthetic_error(
         sd_bus_message *t;
         int r;
 
+        assert(bus);
         assert(sd_bus_error_is_set(e));
         assert(m);
 
@@ -752,7 +771,7 @@ int bus_message_new_synthetic_error(
         t->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
         t->reply_cookie = cookie;
 
-        r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, t->reply_cookie);
+        r = message_append_field_uint32(t, BUS_MESSAGE_HEADER_REPLY_SERIAL, (uint32_t) t->reply_cookie);
         if (r < 0)
                 goto fail;
 
@@ -799,9 +818,10 @@ _public_ sd_bus_message* sd_bus_message_unref(sd_bus_message *m) {
         assert(m->n_ref > 0);
         m->n_ref--;
 
-        if (m->n_ref <= 0)
-                message_free(m);
+        if (m->n_ref > 0)
+                return NULL;
 
+        message_free(m);
         return NULL;
 }
 
@@ -831,16 +851,24 @@ _public_ int sd_bus_message_get_reply_cookie(sd_bus_message *m, uint64_t *cookie
         return 0;
 }
 
-_public_ int sd_bus_message_get_no_reply(sd_bus_message *m) {
+_public_ int sd_bus_message_get_expect_reply(sd_bus_message *m) {
+        assert_return(m, -EINVAL);
+
+        return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
+                !(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED);
+}
+
+_public_ int sd_bus_message_get_auto_start(sd_bus_message *m) {
         assert_return(m, -EINVAL);
 
-        return m->header->type == SD_BUS_MESSAGE_METHOD_CALL ? !!(m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) : 0;
+        return !(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
 }
 
-_public_ int sd_bus_message_get_no_auto_start(sd_bus_message *m) {
+_public_ int sd_bus_message_get_allow_interactive_authorization(sd_bus_message *m) {
         assert_return(m, -EINVAL);
 
-        return !!(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
+        return m->header->type == SD_BUS_MESSAGE_METHOD_CALL &&
+                (m->header->flags & BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION);
 }
 
 _public_ const char *sd_bus_message_get_path(sd_bus_message *m) {
@@ -968,27 +996,39 @@ _public_ int sd_bus_message_is_method_error(sd_bus_message *m, const char *name)
         return 1;
 }
 
-_public_ int sd_bus_message_set_no_reply(sd_bus_message *m, int b) {
+_public_ int sd_bus_message_set_expect_reply(sd_bus_message *m, int b) {
         assert_return(m, -EINVAL);
         assert_return(!m->sealed, -EPERM);
         assert_return(m->header->type == SD_BUS_MESSAGE_METHOD_CALL, -EPERM);
 
         if (b)
-                m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
-        else
                 m->header->flags &= ~BUS_MESSAGE_NO_REPLY_EXPECTED;
+        else
+                m->header->flags |= BUS_MESSAGE_NO_REPLY_EXPECTED;
 
         return 0;
 }
 
-_public_ int sd_bus_message_set_no_auto_start(sd_bus_message *m, int b) {
+_public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) {
         assert_return(m, -EINVAL);
         assert_return(!m->sealed, -EPERM);
 
         if (b)
+                m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START;
+        else
                 m->header->flags |= BUS_MESSAGE_NO_AUTO_START;
+
+        return 0;
+}
+
+_public_ int sd_bus_message_set_allow_interactive_authorization(sd_bus_message *m, int b) {
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+
+        if (b)
+                m->header->flags |= BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
         else
-                m->header->flags &= ~BUS_MESSAGE_NO_AUTO_START;
+                m->header->flags &= ~BUS_MESSAGE_ALLOW_INTERACTIVE_AUTHORIZATION;
 
         return 0;
 }
@@ -1072,10 +1112,10 @@ static int part_make_space(
                         uint64_t new_allocated;
 
                         new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
-                        r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &new_allocated);
+                        r = memfd_set_size(part->memfd, new_allocated);
                         if (r < 0) {
                                 m->poisoned = true;
-                                return -errno;
+                                return r;
                         }
 
                         part->allocated = new_allocated;
@@ -1227,7 +1267,7 @@ static void *message_extend_body(sd_bus_message *m, size_t align, size_t sz, boo
                                 return NULL;
 
                         if (padding > 0) {
-                                memset(p, 0, padding);
+                                memzero(p, padding);
                                 p = (uint8_t*) p + padding;
                         }
 
@@ -1273,7 +1313,7 @@ static int message_push_fd(sd_bus_message *m, int fd) {
         f = realloc(m->fds, sizeof(int) * (m->n_fds + 1));
         if (!f) {
                 m->poisoned = true;
-                close_nointr_nofail(copy);
+                safe_close(copy);
                 return -ENOMEM;
         }
 
@@ -1862,7 +1902,7 @@ _public_ int sd_bus_message_open_container(
         struct bus_container *c, *w;
         uint32_t *array_size = NULL;
         char *signature;
-        size_t before, begin;
+        size_t before, begin = 0;
         bool need_offsets = false;
         int r;
 
@@ -2023,6 +2063,7 @@ static int bus_message_close_variant(sd_bus_message *m, struct bus_container *c)
 
         assert(m);
         assert(c);
+        assert(c->signature);
 
         if (!BUS_MESSAGE_IS_GVARIANT(m))
                 return 0;
@@ -2513,7 +2554,7 @@ _public_ int sd_bus_message_append_array_iovec(
                 if (iov[i].iov_base)
                         memcpy(p, iov[i].iov_base, iov[i].iov_len);
                 else
-                        memset(p, 0, iov[i].iov_len);
+                        memzero(p, iov[i].iov_len);
 
                 p = (uint8_t*) p + iov[i].iov_len;
         }
@@ -2523,7 +2564,7 @@ _public_ int sd_bus_message_append_array_iovec(
 
 _public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
                                                char type,
-                                               sd_memfd *memfd) {
+                                               int memfd) {
         _cleanup_close_ int copy_fd = -1;
         struct bus_body_part *part;
         ssize_t align, sz;
@@ -2533,7 +2574,7 @@ _public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
 
         if (!m)
                 return -EINVAL;
-        if (!memfd)
+        if (memfd < 0)
                 return -EINVAL;
         if (m->sealed)
                 return -EPERM;
@@ -2542,15 +2583,15 @@ _public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
         if (m->poisoned)
                 return -ESTALE;
 
-        r = sd_memfd_set_sealed(memfd, true);
+        r = memfd_set_sealed(memfd);
         if (r < 0)
                 return r;
 
-        copy_fd = sd_memfd_dup_fd(memfd);
+        copy_fd = dup(memfd);
         if (copy_fd < 0)
                 return copy_fd;
 
-        r = sd_memfd_get_size(memfd, &size);
+        r = memfd_get_size(memfd, &size);
         if (r < 0)
                 return r;
 
@@ -2589,7 +2630,7 @@ _public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
         return sd_bus_message_close_container(m);
 }
 
-_public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *memfd) {
+_public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, int memfd) {
         _cleanup_close_ int copy_fd = -1;
         struct bus_body_part *part;
         struct bus_container *c;
@@ -2598,19 +2639,19 @@ _public_ int sd_bus_message_append_string_memfd(sd_bus_message *m, sd_memfd *mem
         int r;
 
         assert_return(m, -EINVAL);
-        assert_return(memfd, -EINVAL);
+        assert_return(memfd >= 0, -EINVAL);
         assert_return(!m->sealed, -EPERM);
         assert_return(!m->poisoned, -ESTALE);
 
-        r = sd_memfd_set_sealed(memfd, true);
+        r = memfd_set_sealed(memfd);
         if (r < 0)
                 return r;
 
-        copy_fd = sd_memfd_dup_fd(memfd);
+        copy_fd = dup(memfd);
         if (copy_fd < 0)
                 return copy_fd;
 
-        r = sd_memfd_get_size(memfd, &size);
+        r = memfd_get_size(memfd, &size);
         if (r < 0)
                 return r;
 
@@ -2778,12 +2819,12 @@ int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
         l = BUS_MESSAGE_FIELDS_SIZE(m);
         a = ALIGN8(l) - l;
         if (a > 0)
-                memset((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 0, a);
+                memzero((uint8_t*) BUS_MESSAGE_FIELDS(m) + l, 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) {
+        if (m->destination && 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)) {
                                 uint64_t sz;
@@ -2795,11 +2836,12 @@ int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
 
                                 /* Then, sync up real memfd size */
                                 sz = part->size;
-                                if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &sz) < 0)
-                                        return -errno;
+                                r = memfd_set_size(part->memfd, sz);
+                                if (r < 0)
+                                        return r;
 
                                 /* Finally, try to seal */
-                                if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
+                                if (memfd_set_sealed(part->memfd) >= 0)
                                         part->sealed = true;
                         }
         }
@@ -2836,7 +2878,7 @@ int bus_body_part_map(struct bus_body_part *part) {
         psz = PAGE_ALIGN(part->size);
 
         if (part->memfd >= 0)
-                p = mmap(NULL, psz, PROT_READ, MAP_SHARED, part->memfd, 0);
+                p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE, part->memfd, 0);
         else if (part->is_zero)
                 p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
         else
@@ -4214,7 +4256,7 @@ static int message_read_ap(
          * in a single stackframe. We hence implement our own
          * home-grown stack in an array. */
 
-        n_array = (unsigned) -1; /* lenght of current array entries */
+        n_array = (unsigned) -1; /* length of current array entries */
         n_struct = strlen(types); /* length of current struct contents signature */
 
         for (;;) {
@@ -4409,13 +4451,32 @@ _public_ int sd_bus_message_skip(sd_bus_message *m, const char *types) {
 
         assert_return(m, -EINVAL);
         assert_return(m->sealed, -EPERM);
-        assert_return(types, -EINVAL);
 
-        if (isempty(types))
-                return 0;
+        /* If types is NULL, read exactly one element */
+        if (!types) {
+                struct bus_container *c;
+                size_t l;
+
+                if (message_end_of_signature(m))
+                        return -ENXIO;
+
+                if (message_end_of_array(m, m->rindex))
+                        return 0;
+
+                c = message_get_container(m);
+
+                r = signature_element_length(c->signature + c->index, &l);
+                if (r < 0)
+                        return r;
+
+                types = strndupa(c->signature + c->index, l);
+        }
 
         switch (*types) {
 
+        case 0: /* Nothing to drop */
+                return 0;
+
         case SD_BUS_TYPE_BYTE:
         case SD_BUS_TYPE_BOOLEAN:
         case SD_BUS_TYPE_INT16:
@@ -4884,6 +4945,7 @@ int bus_message_parse_fields(sd_bus_message *m) {
         size_t ri;
         int r;
         uint32_t unix_fds = 0;
+        bool unix_fds_set = false;
         void *offsets = NULL;
         unsigned n_offsets = 0;
         size_t sz = 0;
@@ -5043,7 +5105,7 @@ int bus_message_parse_fields(sd_bus_message *m) {
 
                         r = message_peek_field_string(m, service_name_is_valid, &ri, item_size, &m->sender);
 
-                        if (r >= 0 && m->sender[0] == ':' && m->bus && m->bus->bus_client && !m->bus->is_kernel) {
+                        if (r >= 0 && m->sender[0] == ':' && m->bus->bus_client && !m->bus->is_kernel) {
                                 m->creds.unique_name = (char*) m->sender;
                                 m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & m->bus->creds_mask;
                         }
@@ -5074,24 +5136,29 @@ int bus_message_parse_fields(sd_bus_message *m) {
                         break;
                 }
 
-                case BUS_MESSAGE_HEADER_REPLY_SERIAL:
+                case BUS_MESSAGE_HEADER_REPLY_SERIAL: {
+                        uint32_t serial;
+
                         if (m->reply_cookie != 0)
                                 return -EBADMSG;
 
                         if (!streq(signature, "u"))
                                 return -EBADMSG;
 
-                        r = message_peek_field_uint32(m, &ri, item_size, &m->reply_cookie);
+                        r = message_peek_field_uint32(m, &ri, item_size, &serial);
                         if (r < 0)
                                 return r;
 
+                        m->reply_cookie = serial;
+
                         if (m->reply_cookie == 0)
                                 return -EBADMSG;
 
                         break;
+                }
 
                 case BUS_MESSAGE_HEADER_UNIX_FDS:
-                        if (unix_fds != 0)
+                        if (unix_fds_set)
                                 return -EBADMSG;
 
                         if (!streq(signature, "u"))
@@ -5101,9 +5168,7 @@ int bus_message_parse_fields(sd_bus_message *m) {
                         if (r < 0)
                                 return -EBADMSG;
 
-                        if (unix_fds == 0)
-                                return -EBADMSG;
-
+                        unix_fds_set = true;
                         break;
 
                 default:
@@ -5125,6 +5190,10 @@ int bus_message_parse_fields(sd_bus_message *m) {
         case SD_BUS_MESSAGE_SIGNAL:
                 if (!m->path || !m->interface || !m->member)
                         return -EBADMSG;
+
+                if (m->reply_cookie != 0)
+                        return -EBADMSG;
+
                 break;
 
         case SD_BUS_MESSAGE_METHOD_CALL:
@@ -5132,6 +5201,9 @@ int bus_message_parse_fields(sd_bus_message *m) {
                 if (!m->path || !m->member)
                         return -EBADMSG;
 
+                if (m->reply_cookie != 0)
+                        return -EBADMSG;
+
                 break;
 
         case SD_BUS_MESSAGE_METHOD_RETURN:
@@ -5262,35 +5334,57 @@ _public_ int sd_bus_message_read_strv(sd_bus_message *m, char ***l) {
         return 1;
 }
 
-const char* bus_message_get_arg(sd_bus_message *m, unsigned i) {
-        int r;
-        const char *t = NULL;
+int bus_message_get_arg(sd_bus_message *m, unsigned i, const char **str, char ***strv) {
+        const char *contents;
         unsigned j;
+        char type;
+        int r;
 
         assert(m);
+        assert(str);
+        assert(strv);
 
         r = sd_bus_message_rewind(m, true);
         if (r < 0)
-                return NULL;
+                return r;
 
-        for (j = 0; j <= i; j++) {
-                char type;
+        for (j = 0;; j++) {
+                r = sd_bus_message_peek_type(m, &type, &contents);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return -ENXIO;
+
+                /* Don't match against arguments after the first one we don't understand */
+                if (!IN_SET(type, SD_BUS_TYPE_STRING, SD_BUS_TYPE_OBJECT_PATH, SD_BUS_TYPE_SIGNATURE) &&
+                    !(type == SD_BUS_TYPE_ARRAY && STR_IN_SET(contents, "s", "o", "g")))
+                        return -ENXIO;
 
-                r = sd_bus_message_peek_type(m, &type, NULL);
+                if (j >= i)
+                        break;
+
+                r = sd_bus_message_skip(m, NULL);
                 if (r < 0)
-                        return NULL;
+                        return r;
+        }
 
-                if (type != SD_BUS_TYPE_STRING &&
-                    type != SD_BUS_TYPE_OBJECT_PATH &&
-                    type != SD_BUS_TYPE_SIGNATURE)
-                        return NULL;
+        if (type == SD_BUS_TYPE_ARRAY) {
 
-                r = sd_bus_message_read_basic(m, type, &t);
+                r = sd_bus_message_read_strv(m, strv);
                 if (r < 0)
-                        return NULL;
+                        return r;
+
+                *str = NULL;
+
+        } else {
+                r = sd_bus_message_read_basic(m, type, str);
+                if (r < 0)
+                        return r;
+
+                *strv = NULL;
         }
 
-        return t;
+        return 0;
 }
 
 bool bus_header_is_complete(struct bus_header *h, size_t size) {
@@ -5328,7 +5422,7 @@ int bus_header_message_size(struct bus_header *h, size_t *sum) {
 }
 
 _public_ int sd_bus_message_get_errno(sd_bus_message *m) {
-        assert_return(m, -EINVAL);
+        assert_return(m, EINVAL);
 
         if (m->header->type != SD_BUS_MESSAGE_METHOD_ERROR)
                 return 0;
@@ -5345,6 +5439,18 @@ _public_ const char* sd_bus_message_get_signature(sd_bus_message *m, int complet
         return strempty(c->signature);
 }
 
+_public_ int sd_bus_message_is_empty(sd_bus_message *m) {
+        assert_return(m, -EINVAL);
+
+        return isempty(m->root_container.signature);
+}
+
+_public_ int sd_bus_message_has_signature(sd_bus_message *m, const char *signature) {
+        assert_return(m, -EINVAL);
+
+        return streq(strempty(m->root_container.signature), strempty(signature));
+}
+
 _public_ int sd_bus_message_copy(sd_bus_message *m, sd_bus_message *source, int all) {
         bool done_something = false;
         int r;
@@ -5467,14 +5573,14 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
         switch ((*m)->header->type) {
 
         case SD_BUS_MESSAGE_SIGNAL:
-                r = sd_bus_message_new_signal(bus, (*m)->path, (*m)->interface, (*m)->member, &n);
+                r = sd_bus_message_new_signal(bus, &n, (*m)->path, (*m)->interface, (*m)->member);
                 if (r < 0)
                         return r;
 
                 break;
 
         case SD_BUS_MESSAGE_METHOD_CALL:
-                r = sd_bus_message_new_method_call(bus, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member, &n);
+                r = sd_bus_message_new_method_call(bus, &n, (*m)->destination, (*m)->path, (*m)->interface, (*m)->member);
                 if (r < 0)
                         return r;
 
@@ -5488,7 +5594,7 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
                         return -ENOMEM;
 
                 n->reply_cookie = (*m)->reply_cookie;
-                r = message_append_field_uint32(n, BUS_MESSAGE_HEADER_REPLY_SERIAL, n->reply_cookie);
+                r = message_append_field_uint32(n, BUS_MESSAGE_HEADER_REPLY_SERIAL, (uint32_t) n->reply_cookie);
                 if (r < 0)
                         return r;
 
@@ -5548,3 +5654,19 @@ int bus_message_append_sender(sd_bus_message *m, const char *sender) {
 
         return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
 }
+
+_public_ int sd_bus_message_get_priority(sd_bus_message *m, int64_t *priority) {
+        assert_return(m, -EINVAL);
+        assert_return(priority, -EINVAL);
+
+        *priority = m->priority;
+        return 0;
+}
+
+_public_ int sd_bus_message_set_priority(sd_bus_message *m, int64_t priority) {
+        assert_return(m, -EINVAL);
+        assert_return(!m->sealed, -EPERM);
+
+        m->priority = priority;
+        return 0;
+}