chiark / gitweb /
sd-bus: add extra assert check
[elogind.git] / src / libsystemd / sd-bus / bus-message.c
index 79dc471d41e3b027529ca02d2b488bae9f6d763c..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,16 +127,17 @@ 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->free_kdbus)
+                free(m->kdbus);
+
         sd_bus_unref(m->bus);
 
         if (m->free_fds) {
@@ -146,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);
@@ -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) {
@@ -847,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);
 
@@ -997,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);
 
@@ -1076,10 +1112,10 @@ static int part_make_space(
                         uint64_t new_allocated;
 
                         new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
-                        r = ftruncate(part->memfd, new_allocated);
+                        r = memfd_set_size(part->memfd, new_allocated);
                         if (r < 0) {
                                 m->poisoned = true;
-                                return -errno;
+                                return r;
                         }
 
                         part->allocated = new_allocated;
@@ -2027,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;
@@ -2527,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;
@@ -2537,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;
@@ -2546,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);
+        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;
 
@@ -2593,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;
@@ -2602,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);
+        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;
 
@@ -2799,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 (ftruncate(part->memfd, sz) < 0)
-                                        return -errno;
+                                r = memfd_set_size(part->memfd, sz);
+                                if (r < 0)
+                                        return r;
 
                                 /* Finally, try to seal */
-                                if (fcntl(part->memfd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE) >= 0)
+                                if (memfd_set_sealed(part->memfd) >= 0)
                                         part->sealed = true;
                         }
         }
@@ -2840,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
@@ -4413,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:
@@ -5133,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:
@@ -5140,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:
@@ -5270,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;
+
+                if (j >= i)
+                        break;
 
-                r = sd_bus_message_peek_type(m, &type, NULL);
+                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) {
@@ -5336,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;
@@ -5353,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;