#include "strv.h"
#include "time-util.h"
#include "cgroup-util.h"
+#include "memfd-util.h"
#include "sd-bus.h"
#include "bus-message.h"
/* If we can reuse the memfd, try that. For that it
* can't be sealed yet. */
- if (!part->sealed)
+ if (!part->sealed) {
+ assert(part->memfd_offset == 0);
+ assert(part->data == part->mmap_begin);
bus_kernel_push_memfd(m->bus, part->memfd, part->data, part->mapped, part->allocated);
- else {
+ } else {
if (part->mapped > 0)
- assert_se(munmap(part->data, part->mapped) == 0);
+ assert_se(munmap(part->mmap_begin, part->mapped) == 0);
safe_close(part->memfd);
}
} else if (part->munmap_this)
- munmap(part->data, part->mapped);
+ munmap(part->mmap_begin, part->mapped);
else if (part->free_this)
free(part->data);
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);
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);
struct bus_header *h;
size_t a, label_sz;
+ assert(bus);
assert(buffer || length <= 0);
assert(fds || n_fds <= 0);
assert(ret);
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) {
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;
}
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;
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;
}
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);
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);
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);
sd_bus_message *t;
int r;
+ assert(bus);
assert(sd_bus_error_is_set(e));
assert(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;
}
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);
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);
if (m->poisoned)
return -ENOMEM;
- if (!part->data && part->memfd < 0)
+ if (!part->data && part->memfd < 0) {
part->memfd = bus_kernel_pop_memfd(m->bus, &part->data, &part->mapped, &part->allocated);
+ part->mmap_begin = part->data;
+ }
if (part->memfd >= 0) {
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;
if (part->mapped <= 0)
n = mmap(NULL, psz, PROT_READ|PROT_WRITE, MAP_SHARED, part->memfd, 0);
else
- n = mremap(part->data, part->mapped, psz, MREMAP_MAYMOVE);
+ n = mremap(part->mmap_begin, part->mapped, psz, MREMAP_MAYMOVE);
if (n == MAP_FAILED) {
m->poisoned = true;
return -errno;
}
+ part->mmap_begin = part->data = n;
part->mapped = psz;
- part->data = n;
+ part->memfd_offset = 0;
}
part->munmap_this = true;
assert(m);
assert(c);
+ assert(c->signature);
if (!BUS_MESSAGE_IS_GVARIANT(m))
return 0;
return 0;
}
-_public_ int sd_bus_message_append_array(sd_bus_message *m,
- char type,
- const void *ptr,
- size_t size) {
+_public_ int sd_bus_message_append_array(
+ sd_bus_message *m,
+ char type,
+ const void *ptr,
+ size_t size) {
int r;
void *p;
return 0;
}
-_public_ int sd_bus_message_append_array_memfd(sd_bus_message *m,
- char type,
- sd_memfd *memfd) {
+_public_ int sd_bus_message_append_array_memfd(
+ sd_bus_message *m,
+ char type,
+ int memfd,
+ uint64_t offset,
+ uint64_t size) {
+
_cleanup_close_ int copy_fd = -1;
struct bus_body_part *part;
ssize_t align, sz;
- uint64_t size;
+ uint64_t real_size;
void *a;
int r;
- if (!m)
- return -EINVAL;
- if (!memfd)
- return -EINVAL;
- if (m->sealed)
- return -EPERM;
- if (!bus_type_is_trivial(type))
- return -EINVAL;
- if (m->poisoned)
- return -ESTALE;
+ assert_return(m, -EINVAL);
+ assert_return(memfd >= 0, -EINVAL);
+ assert_return(bus_type_is_trivial(type), -EINVAL);
+ assert_return(size > 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, &real_size);
if (r < 0)
return r;
+ if (offset == 0 && size == (uint64_t) -1)
+ size = real_size;
+ else if (offset + size > real_size)
+ return -EMSGSIZE;
+
align = bus_type_get_alignment(type);
sz = bus_type_get_size(type);
assert_se(align > 0);
assert_se(sz > 0);
+ if (offset % align != 0)
+ return -EINVAL;
+
if (size % sz != 0)
return -EINVAL;
return -ENOMEM;
part->memfd = copy_fd;
+ part->memfd_offset = offset;
part->sealed = true;
part->size = size;
copy_fd = -1;
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,
+ uint64_t offset,
+ uint64_t size) {
+
_cleanup_close_ int copy_fd = -1;
struct bus_body_part *part;
struct bus_container *c;
- uint64_t size;
+ uint64_t real_size;
void *a;
int r;
assert_return(m, -EINVAL);
- assert_return(memfd, -EINVAL);
+ assert_return(memfd >= 0, -EINVAL);
+ assert_return(size > 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, &real_size);
if (r < 0)
return r;
+ if (offset == 0 && size == (uint64_t) -1)
+ size = real_size;
+ else if (offset + size > real_size)
+ return -EMSGSIZE;
+
/* We require this to be NUL terminated */
if (size == 0)
return -EINVAL;
return -ENOMEM;
part->memfd = copy_fd;
+ part->memfd_offset = offset;
part->sealed = true;
part->size = size;
copy_fd = -1;
/* 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;
/* 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;
}
}
int bus_body_part_map(struct bus_body_part *part) {
void *p;
- size_t psz;
+ size_t psz, shift;
assert_se(part);
return 0;
}
- psz = PAGE_ALIGN(part->size);
+ shift = part->memfd_offset - ((part->memfd_offset / page_size()) * page_size());
+ psz = PAGE_ALIGN(part->size + shift);
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, part->memfd_offset - shift);
else if (part->is_zero)
p = mmap(NULL, psz, PROT_READ, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
else
return -errno;
part->mapped = psz;
- part->data = p;
+ part->mmap_begin = p;
+ part->data = (uint8_t*) p + shift;
part->munmap_this = true;
return 0;
if (part->memfd < 0)
return;
- if (!part->data)
+ if (!part->mmap_begin)
return;
if (!part->munmap_this)
return;
- assert_se(munmap(part->data, part->mapped) == 0);
+ assert_se(munmap(part->mmap_begin, part->mapped) == 0);
+ part->mmap_begin = NULL;
part->data = NULL;
part->mapped = 0;
part->munmap_this = false;
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:
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;
}
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:
if (!m->path || !m->member)
return -EBADMSG;
+ if (m->reply_cookie != 0)
+ return -EBADMSG;
+
break;
case SD_BUS_MESSAGE_METHOD_RETURN:
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) {
}
_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;
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;