chiark / gitweb /
util: unify SO_PEERCRED/SO_PEERSEC invocations
[elogind.git] / src / libsystemd-bus / bus-message.c
index 1a461e62e07d5ec6b557fe57d0a0fc8c9297aaf4..f09f0d682df372a6a8589825f99c50072317bb14 100644 (file)
@@ -65,7 +65,7 @@ static void message_free_part(sd_bus_message *m, struct bus_body_part *part) {
                  * can't be sealed yet. */
 
                 if (!part->sealed)
-                        bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped);
+                        bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
                 else {
                         if (part->mapped > 0)
                                 assert_se(munmap(part->data, part->mapped) == 0);
@@ -151,7 +151,7 @@ static void message_free(sd_bus_message *m) {
         free(m->root_container.signature);
         free(m->root_container.offsets);
 
-        free(m->peeked_signature);
+        free(m->root_container.peeked_signature);
 
         bus_creds_done(&m->creds);
         free(m);
@@ -1049,20 +1049,27 @@ static int part_make_space(
                 return -ENOMEM;
 
         if (!part->data && part->memfd < 0)
-                part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped);
+                part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated);
 
         if (part->memfd >= 0) {
-                uint64_t u = sz;
 
-                r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &u);
-                if (r < 0) {
-                        m->poisoned = true;
-                        return -errno;
+                if (part->allocated == 0 || sz > part->allocated) {
+                        uint64_t new_allocated;
+
+                        new_allocated = PAGE_ALIGN(sz > 0 ? 2 * sz : 1);
+                        r = ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &new_allocated);
+                        if (r < 0) {
+                                m->poisoned = true;
+                                return -errno;
+                        }
+
+                        part->allocated = new_allocated;
                 }
 
                 if (!part->data || sz > part->mapped) {
-                        size_t psz = PAGE_ALIGN(sz > 0 ? sz : 1);
+                        size_t psz;
 
+                        psz = PAGE_ALIGN(sz > 0 ? sz : 1);
                         if (part->mapped <= 0)
                                 n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
                         else
@@ -1079,14 +1086,20 @@ static int part_make_space(
 
                 part->munmap_this = true;
         } else {
-                n = realloc(part->data, MAX(sz, 1u));
-                if (!n) {
-                        m->poisoned = true;
-                        return -ENOMEM;
-                }
+                if (part->allocated == 0 || sz > part->allocated) {
+                        size_t new_allocated;
 
-                part->data = n;
-                part->free_this = true;
+                        new_allocated = sz > 0 ? 2 * sz : 64;
+                        n = realloc(part->data, new_allocated);
+                        if (!n) {
+                                m->poisoned = true;
+                                return -ENOMEM;
+                        }
+
+                        part->data = n;
+                        part->allocated = new_allocated;
+                        part->free_this = true;
+                }
         }
 
         if (q)
@@ -2042,7 +2055,7 @@ static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c,
                                 return r;
                 }
 
-                assert(i <= c->n_offsets);
+                assert(!c->need_offsets || i <= c->n_offsets);
 
                 /* We need to add an offset for each item that has a
                  * variable size and that is not the last one in the
@@ -2054,7 +2067,8 @@ static int bus_message_close_struct(sd_bus_message *m, struct bus_container *c,
                 p += n;
         }
 
-        assert(i == c->n_offsets);
+        assert(!c->need_offsets || i == c->n_offsets);
+        assert(c->need_offsets || n_variable == 0);
 
         if (n_variable <= 0) {
                 a = message_extend_body(m, 1, 0, add_offset);
@@ -2757,8 +2771,19 @@ int bus_message_seal(sd_bus_message *m, uint64_t serial, usec_t timeout) {
         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)) {
+                                uint64_t sz;
+
+                                /* Try to seal it if that makes
+                                 * sense. First, unmap our own map to
+                                 * make sure we don't keep it busy. */
                                 bus_body_part_unmap(part);
 
+                                /* Then, sync up real memfd size */
+                                sz = part->size;
+                                if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SIZE_SET, &sz) < 0)
+                                        return -errno;
+
+                                /* Finally, try to seal */
                                 if (ioctl(part->memfd, KDBUS_CMD_MEMFD_SEAL_SET, 1) >= 0)
                                         part->sealed = true;
                         }
@@ -3891,6 +3916,7 @@ _public_ int sd_bus_message_enter_container(sd_bus_message *m,
         w = m->containers + m->n_containers++;
         w->enclosing = type;
         w->signature = signature;
+        w->peeked_signature = NULL;
         w->index = 0;
 
         w->before = before;
@@ -3935,6 +3961,7 @@ _public_ int sd_bus_message_exit_container(sd_bus_message *m) {
         }
 
         free(c->signature);
+        free(c->peeked_signature);
         free(c->offsets);
         m->n_containers--;
 
@@ -4012,10 +4039,8 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
                         if (!sig)
                                 return -ENOMEM;
 
-                        free(m->peeked_signature);
-                        m->peeked_signature = sig;
-
-                        *contents = sig;
+                        free(c->peeked_signature);
+                        *contents = c->peeked_signature = sig;
                 }
 
                 if (type)
@@ -4040,10 +4065,8 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
                         if (!sig)
                                 return -ENOMEM;
 
-                        free(m->peeked_signature);
-                        m->peeked_signature = sig;
-
-                        *contents = sig;
+                        free(c->peeked_signature);
+                        *contents = c->peeked_signature = sig;
                 }
 
                 if (type)
@@ -4083,15 +4106,15 @@ _public_ int sd_bus_message_peek_type(sd_bus_message *m, char *type, const char
                                 if (k > c->item_size)
                                         return -EBADMSG;
 
-                                free(m->peeked_signature);
-                                m->peeked_signature = strndup((char*) q + 1, k - 1);
-                                if (!m->peeked_signature)
+                                free(c->peeked_signature);
+                                c->peeked_signature = strndup((char*) q + 1, k - 1);
+                                if (!c->peeked_signature)
                                         return -ENOMEM;
 
-                                if (!signature_is_valid(m->peeked_signature, true))
+                                if (!signature_is_valid(c->peeked_signature, true))
                                         return -EBADMSG;
 
-                                *contents = m->peeked_signature;
+                                *contents = c->peeked_signature;
                         } else {
                                 size_t rindex, l;
 
@@ -5109,6 +5132,14 @@ int bus_message_parse_fields(sd_bus_message *m) {
                 break;
         }
 
+        /* Refuse non-local messages that claim they are local */
+        if (streq_ptr(m->path, "/org/freedesktop/DBus/Local"))
+                return -EBADMSG;
+        if (streq_ptr(m->interface, "org.freedesktop.DBus.Local"))
+                return -EBADMSG;
+        if (streq_ptr(m->sender, "org.freedesktop.DBus.Local"))
+                return -EBADMSG;
+
         m->root_container.end = BUS_MESSAGE_BODY_SIZE(m);
 
         if (BUS_MESSAGE_IS_GVARIANT(m)) {
@@ -5492,3 +5523,13 @@ int bus_message_remarshal(sd_bus *bus, sd_bus_message **m) {
 
         return 0;
 }
+
+int bus_message_append_sender(sd_bus_message *m, const char *sender) {
+        assert(m);
+        assert(sender);
+
+        assert_return(!m->sealed, -EPERM);
+        assert_return(!m->sender, -EPERM);
+
+        return message_append_field_string(m, BUS_MESSAGE_HEADER_SENDER, SD_BUS_TYPE_STRING, sender, &m->sender);
+}