chiark / gitweb /
sd-bus: add extra assert check
[elogind.git] / src / libsystemd / sd-bus / bus-message.c
index 4fcc693543a8d0ada16bd4a9454e5a7596cf7284..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"
@@ -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);
@@ -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,9 +518,7 @@ 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;
 }
@@ -517,7 +533,8 @@ _public_ int sd_bus_message_new_signal(
         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);
@@ -558,7 +575,8 @@ _public_ int sd_bus_message_new_method_call(
         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);
@@ -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);
 
@@ -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;
 }
 
@@ -844,6 +864,13 @@ _public_ int sd_bus_message_get_auto_start(sd_bus_message *m) {
         return !(m->header->flags & BUS_MESSAGE_NO_AUTO_START);
 }
 
+_public_ int sd_bus_message_get_allow_interactive_authorization(sd_bus_message *m) {
+        assert_return(m, -EINVAL);
+
+        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) {
         assert_return(m, NULL);
 
@@ -994,6 +1021,18 @@ _public_ int sd_bus_message_set_auto_start(sd_bus_message *m, int b) {
         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_ALLOW_INTERACTIVE_AUTHORIZATION;
+
+        return 0;
+}
+
 static struct bus_container *message_get_container(sd_bus_message *m) {
         assert(m);
 
@@ -1073,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;
@@ -2024,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;
@@ -2524,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;
@@ -2534,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;
@@ -2543,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;
 
@@ -2590,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;
@@ -2599,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;
 
@@ -2784,7 +2824,7 @@ int bus_message_seal(sd_bus_message *m, uint64_t cookie, usec_t timeout) {
         /* 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;
@@ -2796,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;
                         }
         }
@@ -2837,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
@@ -4410,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:
@@ -5045,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;
                         }
@@ -5130,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:
@@ -5137,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:
@@ -5267,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) {
@@ -5333,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;
@@ -5350,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;