bus-kernel.c revision 022fb8558e797483709ab3e9fe846f04f7026dac
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering/***
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering This file is part of systemd.
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering Copyright 2013 Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering systemd is free software; you can redistribute it and/or modify it
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering under the terms of the GNU Lesser General Public License as published by
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering (at your option) any later version.
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering systemd is distributed in the hope that it will be useful, but
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering Lesser General Public License for more details.
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering You should have received a copy of the GNU Lesser General Public License
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering***/
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#ifdef HAVE_VALGRIND_MEMCHECK_H
4871690d9e32608bbd9b18505b5326c2079c9690Allin Cottrell#include <valgrind/memcheck.h>
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#endif
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include <fcntl.h>
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include <malloc.h>
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering#include <libgen.h>
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering#include <sys/mman.h>
d025f1e4dca8fc1436aff76f9e6185fe3e728daaZbigniew Jędrzejewski-Szmek#include <sys/prctl.h>
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include "util.h"
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include "strv.h"
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include "memfd-util.h"
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include "bus-internal.h"
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek#include "bus-message.h"
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include "bus-kernel.h"
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include "bus-bloom.h"
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include "bus-util.h"
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include "bus-label.h"
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#include "cgroup-util.h"
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering#define UNIQUE_NAME_MAX (3+DECIMAL_STR_MAX(uint64_t))
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringint bus_kernel_parse_unique_name(const char *s, uint64_t *id) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering int r;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(s);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(id);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (!startswith(s, ":1."))
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return 0;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek r = safe_atou64(s + 3, id);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (r < 0)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return r;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return 1;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering}
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic void append_payload_vec(struct kdbus_item **d, const void *p, size_t sz) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(d);
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek assert(sz > 0);
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek *d = ALIGN8_PTR(*d);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Note that p can be NULL, which encodes a region full of
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * zeroes, which is useful to optimize certain padding
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * conditions */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek (*d)->size = offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec);
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek (*d)->type = KDBUS_ITEM_PAYLOAD_VEC;
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek (*d)->vec.address = PTR_TO_UINT64(p);
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek (*d)->vec.size = sz;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering}
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic void append_payload_memfd(struct kdbus_item **d, int memfd, size_t sz) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(d);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(memfd >= 0);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(sz > 0);
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *d = ALIGN8_PTR(*d);
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek (*d)->size = offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering (*d)->type = KDBUS_ITEM_PAYLOAD_MEMFD;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering (*d)->memfd.fd = memfd;
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek (*d)->memfd.size = sz;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering}
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic void append_destination(struct kdbus_item **d, const char *s, size_t length) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(d);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(s);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *d = ALIGN8_PTR(*d);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering (*d)->size = offsetof(struct kdbus_item, str) + length + 1;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering (*d)->type = KDBUS_ITEM_DST_NAME;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering memcpy((*d)->str, s, length + 1);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering}
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic struct kdbus_bloom_filter *append_bloom(struct kdbus_item **d, size_t length) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering struct kdbus_item *i;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek assert(d);
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek
8c0b803b97bb0ee6603d9be85fb6b69cd6081eafLennart Poettering i = ALIGN8_PTR(*d);
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek i->size = offsetof(struct kdbus_item, bloom_filter) +
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek offsetof(struct kdbus_bloom_filter, data) +
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek length;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering i->type = KDBUS_ITEM_BLOOM_FILTER;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek *d = (struct kdbus_item *) ((uint8_t*) i + i->size);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return &i->bloom_filter;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering}
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic void append_fds(struct kdbus_item **d, const int fds[], unsigned n_fds) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(d);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(fds);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(n_fds > 0);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *d = ALIGN8_PTR(*d);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering (*d)->size = offsetof(struct kdbus_item, fds) + sizeof(int) * n_fds;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering (*d)->type = KDBUS_ITEM_FDS;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering memcpy((*d)->fds, fds, sizeof(int) * n_fds);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *d = (struct kdbus_item *) ((uint8_t*) *d + (*d)->size);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering}
f6422def2c10aa0dea1b872d2f187853e61bd015Michal Schmidt
8c0b803b97bb0ee6603d9be85fb6b69cd6081eafLennart Poetteringstatic int bus_message_setup_bloom(sd_bus_message *m, struct kdbus_bloom_filter *bloom) {
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek void *data;
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek unsigned i;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering int r;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(m);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(bloom);
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering data = bloom->data;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering memzero(data, m->bus->bloom_size);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering bloom->generation = 0;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "message-type", bus_message_type_to_string(m->header->type));
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (m->interface)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "interface", m->interface);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (m->member)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "member", m->member);
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek if (m->path) {
a174f94d529c7ae9be589867308b669ec9b4dcc0Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path", m->path);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, "path-slash-prefix", m->path, '/');
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering }
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering r = sd_bus_message_rewind(m, true);
2a0e0692565f0435657c93498e09cbb2d3517152Shawn Landden if (r < 0)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return r;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering for (i = 0; i < 64; i++) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering char type;
2a0e0692565f0435657c93498e09cbb2d3517152Shawn Landden const char *t;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering char buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering char *e;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering r = sd_bus_message_peek_type(m, &type, NULL);
2a0e0692565f0435657c93498e09cbb2d3517152Shawn Landden if (r < 0)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return r;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (type != SD_BUS_TYPE_STRING &&
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering type != SD_BUS_TYPE_OBJECT_PATH &&
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering type != SD_BUS_TYPE_SIGNATURE)
2a0e0692565f0435657c93498e09cbb2d3517152Shawn Landden break;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering r = sd_bus_message_read_basic(m, type, &t);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (r < 0)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return r;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering e = stpcpy(buf, "arg");
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (i < 10)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *(e++) = '0' + (char) i;
2a0e0692565f0435657c93498e09cbb2d3517152Shawn Landden else {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *(e++) = '0' + (char) (i / 10);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *(e++) = '0' + (char) (i % 10);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering }
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering *e = 0;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering bloom_add_pair(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek strcpy(e, "-dot-prefix");
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '.');
2a0e0692565f0435657c93498e09cbb2d3517152Shawn Landden strcpy(e, "-slash-prefix");
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek bloom_add_prefixes(data, m->bus->bloom_size, m->bus->bloom_n_hash, buf, t, '/');
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek }
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek return 0;
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek}
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmekstatic int bus_message_setup_kmsg(sd_bus *b, sd_bus_message *m) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering struct bus_body_part *part;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering struct kdbus_item *d;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering const char *destination;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering bool well_known;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering uint64_t unique;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering size_t sz, dl;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering unsigned i;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering int r;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(b);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(m);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(m->sealed);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* We put this together only once, if this message is reused
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * we reuse the earlier-built version */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (m->kdbus)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return 0;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering destination = m->destination ?: m->destination_ptr;
505b6a61c22d5565e9308045c7b9bf79f7d0517eLennart Poettering
fa1c4b518ec7d8ec2d647213ee651cde4d6c9d7eZbigniew Jędrzejewski-Szmek if (destination) {
505b6a61c22d5565e9308045c7b9bf79f7d0517eLennart Poettering r = bus_kernel_parse_unique_name(destination, &unique);
505b6a61c22d5565e9308045c7b9bf79f7d0517eLennart Poettering if (r < 0)
505b6a61c22d5565e9308045c7b9bf79f7d0517eLennart Poettering return r;
505b6a61c22d5565e9308045c7b9bf79f7d0517eLennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering well_known = r == 0;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering } else
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering well_known = false;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering sz = offsetof(struct kdbus_msg, items);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert_cc(ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec)) ==
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering ALIGN8(offsetof(struct kdbus_item, memfd) + sizeof(struct kdbus_memfd)));
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Add in fixed header, fields header and payload */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering sz += (1 + m->n_body_parts) *
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering ALIGN8(offsetof(struct kdbus_item, vec) + sizeof(struct kdbus_vec));
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Add space for bloom filter */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering sz += ALIGN8(offsetof(struct kdbus_item, bloom_filter) +
d18d46ecea80a7f07415edb9264af6a254fd70bbZbigniew Jędrzejewski-Szmek offsetof(struct kdbus_bloom_filter, data) +
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering m->bus->bloom_size);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek /* Add in well-known destination header */
a174f94d529c7ae9be589867308b669ec9b4dcc0Lennart Poettering if (well_known) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering dl = strlen(destination);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering sz += ALIGN8(offsetof(struct kdbus_item, str) + dl + 1);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering }
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Add space for unix fds */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (m->n_fds > 0)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering sz += ALIGN8(offsetof(struct kdbus_item, fds) + sizeof(int)*m->n_fds);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering m->kdbus = memalign(8, sz);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (!m->kdbus) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering r = -ENOMEM;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering goto fail;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering }
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek m->free_kdbus = true;
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek memzero(m->kdbus, sz);
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek m->kdbus->flags =
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek ((m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_FLAGS_EXPECT_REPLY) |
874bc134ac6504c45e94174e37af13ff21a6bfe2Zbigniew Jędrzejewski-Szmek ((m->header->flags & BUS_MESSAGE_NO_AUTO_START) ? KDBUS_MSG_FLAGS_NO_AUTO_START : 0);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (well_known) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* verify_destination_id will usually be 0, which makes the kernel driver only look
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * at the provided well-known name. Otherwise, the kernel will make sure the provided
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * destination id matches the owner of the provided weel-known-name, and fail if they
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * differ. Currently, this is only needed for bus-proxyd. */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering m->kdbus->dst_id = m->verify_destination_id;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering } else {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering m->kdbus->dst_id = destination ? unique : KDBUS_DST_ID_BROADCAST;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering }
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen m->kdbus->payload_type = KDBUS_PAYLOAD_DBUS;
40b71e89bae4e51768db4dc50ec64c1e9c96eec4Sebastian Thorarensen m->kdbus->cookie = (uint64_t) m->header->serial;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering m->kdbus->priority = m->priority;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek if (m->header->flags & BUS_MESSAGE_NO_REPLY_EXPECTED) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering m->kdbus->cookie_reply = m->reply_cookie;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering } else {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering struct timespec now;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert_se(clock_gettime(CLOCK_MONOTONIC_COARSE, &now) == 0);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering m->kdbus->timeout_ns = now.tv_sec * NSEC_PER_SEC + now.tv_nsec +
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering m->timeout * NSEC_PER_USEC;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering }
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering d = m->kdbus->items;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (well_known)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering append_destination(&d, destination, dl);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering append_payload_vec(&d, m->header, BUS_MESSAGE_BODY_BEGIN(m));
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering MESSAGE_FOREACH_PART(part, i, m) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (part->is_zero) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* If this is padding then simply send a
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * vector with a NULL data pointer which the
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * kernel will just pass through. This is the
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * most efficient way to encode zeroes */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering append_payload_vec(&d, NULL, part->size);
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering continue;
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering }
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (part->memfd >= 0 && part->sealed && destination) {
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering /* Try to send a memfd, if the part is
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering * sealed and this is not a broadcast. Since we can only */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering append_payload_memfd(&d, part->memfd, part->size);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering continue;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering }
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering /* Otherwise, let's send a vector to the actual data.
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering * For that, we need to map it first. */
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering r = bus_body_part_map(part);
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (r < 0)
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering goto fail;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering append_payload_vec(&d, part->data, part->size);
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering }
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (m->kdbus->dst_id == KDBUS_DST_ID_BROADCAST) {
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering struct kdbus_bloom_filter *bloom;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering bloom = append_bloom(&d, m->bus->bloom_size);
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering r = bus_message_setup_bloom(m, bloom);
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering if (r < 0)
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering goto fail;
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering }
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering if (m->n_fds > 0)
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering append_fds(&d, m->fds, m->n_fds);
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering m->kdbus->size = (uint8_t*) d - (uint8_t*) m->kdbus;
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering assert(m->kdbus->size <= sz);
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering return 0;
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poetteringfail:
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering m->poisoned = true;
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering return r;
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering}
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poetteringstatic void unset_memfds(struct sd_bus_message *m) {
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering struct bus_body_part *part;
0b507b17a760b21e33fc52ff377db6aa5086c680Lennart Poettering unsigned i;
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering assert(m);
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering /* Make sure the memfds are not freed twice */
1dfa7e79a60de680086b1d93fcc3629b463f58bdLennart Poettering MESSAGE_FOREACH_PART(part, i, m)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (part->memfd >= 0)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering part->memfd = -1;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering}
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poetteringstatic int bus_kernel_make_message(sd_bus *bus, struct kdbus_msg *k) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering sd_bus_message *m = NULL;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering struct kdbus_item *d;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering unsigned n_fds = 0;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering _cleanup_free_ int *fds = NULL;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering struct bus_header *h = NULL;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering size_t total, n_bytes = 0, idx = 0;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering const char *destination = NULL, *seclabel = NULL;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering int r;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(bus);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(k);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering assert(k->payload_type == KDBUS_PAYLOAD_DBUS);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering KDBUS_ITEM_FOREACH(d, k, items) {
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering size_t l;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering l = d->size - offsetof(struct kdbus_item, data);
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering switch (d->type) {
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering case KDBUS_ITEM_PAYLOAD_OFF:
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (!h) {
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering h = (struct bus_header *)((uint8_t *)k + d->vec.offset);
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (!bus_header_is_complete(h, d->vec.size))
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering return -EBADMSG;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering }
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering n_bytes += d->vec.size;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering break;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering case KDBUS_ITEM_PAYLOAD_MEMFD:
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (!h)
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering return -EBADMSG;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering n_bytes += d->memfd.size;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering break;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering case KDBUS_ITEM_FDS: {
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering int *f;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering unsigned j;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering j = l / sizeof(int);
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering f = realloc(fds, sizeof(int) * (n_fds + j));
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (!f)
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering return -ENOMEM;
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering fds = f;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering memcpy(fds + n_fds, d->fds, sizeof(int) * j);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering n_fds += j;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering break;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering }
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering case KDBUS_ITEM_SECLABEL:
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering seclabel = d->str;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering break;
f7a5bb2842037fa27dbc99d92c3fee7fe1bbbc2aZbigniew Jędrzejewski-Szmek }
f7a5bb2842037fa27dbc99d92c3fee7fe1bbbc2aZbigniew Jędrzejewski-Szmek }
f7a5bb2842037fa27dbc99d92c3fee7fe1bbbc2aZbigniew Jędrzejewski-Szmek
f7a5bb2842037fa27dbc99d92c3fee7fe1bbbc2aZbigniew Jędrzejewski-Szmek if (!h)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return -EBADMSG;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering r = bus_header_message_size(h, &total);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (r < 0)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return r;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (n_bytes != total)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return -EBADMSG;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* on kdbus we only speak native endian gvariant, never dbus1
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering * marshalling or reverse endian */
6b9732b2bf0499c5e4ea8a9d4f6051d98033f680Zbigniew Jędrzejewski-Szmek if (h->version != 2 ||
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering h->endian != BUS_NATIVE_ENDIAN)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return -EPROTOTYPE;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering r = bus_message_from_header(bus, h, sizeof(struct bus_header), fds, n_fds, NULL, seclabel, 0, &m);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (r < 0)
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering return r;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* The well-known names list is different from the other
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering credentials. If we asked for it, but nothing is there, this
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering means that the list of well-known names is simply empty, not
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering that we lack any data */
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering KDBUS_ITEM_FOREACH(d, k, items) {
6baa7db00812437bbc87e73faa1a11b6cf631958Lennart Poettering size_t l;
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering l = d->size - offsetof(struct kdbus_item, data);
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering switch (d->type) {
d682b3a7e7c7c2941a4d3e193f1e330dbc9fae89Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering case KDBUS_ITEM_PAYLOAD_OFF: {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering size_t begin_body;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering begin_body = BUS_MESSAGE_BODY_BEGIN(m);
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering if (idx + d->vec.size > begin_body) {
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering struct bus_body_part *part;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* Contains body material */
151b9b9662a90455262ce575a8a8ae74bf4ff336Lennart Poettering
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering part = message_append_part(m);
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering if (!part) {
f9a810bedacf1da7c505c1786a2416d592665926Lennart Poettering r = -ENOMEM;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering goto fail;
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering }
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering
0153028ae379eb7c9a463c548ef73ea392c6cdb0Lennart Poettering /* A -1 offset is NUL padding. */
part->is_zero = d->vec.offset == ~0ULL;
if (idx >= begin_body) {
if (!part->is_zero)
part->data = (uint8_t *)k + d->vec.offset;
part->size = d->vec.size;
} else {
if (!part->is_zero)
part->data = (uint8_t *)k + d->vec.offset + (begin_body - idx);
part->size = d->vec.size - (begin_body - idx);
}
part->sealed = true;
}
idx += d->vec.size;
break;
}
case KDBUS_ITEM_PAYLOAD_MEMFD: {
struct bus_body_part *part;
if (idx < BUS_MESSAGE_BODY_BEGIN(m)) {
r = -EBADMSG;
goto fail;
}
part = message_append_part(m);
if (!part) {
r = -ENOMEM;
goto fail;
}
part->memfd = d->memfd.fd;
part->size = d->memfd.size;
part->sealed = true;
idx += d->memfd.size;
break;
}
case KDBUS_ITEM_CREDS:
/* UID/GID/PID are always valid */
m->creds.uid = (uid_t) d->creds.uid;
m->creds.gid = (gid_t) d->creds.gid;
m->creds.pid = (pid_t) d->creds.pid;
m->creds.mask |= (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID) & bus->creds_mask;
/* The PID starttime/TID might be missing
* however, when the data is faked by some
* data bus proxy and it lacks that
* information about the real client since
* SO_PEERCRED is used for that */
if (d->creds.starttime > 0) {
m->creds.pid_starttime = d->creds.starttime / NSEC_PER_USEC;
m->creds.mask |= SD_BUS_CREDS_PID_STARTTIME & bus->creds_mask;
}
if (d->creds.tid > 0) {
m->creds.tid = (pid_t) d->creds.tid;
m->creds.mask |= SD_BUS_CREDS_TID & bus->creds_mask;
}
break;
case KDBUS_ITEM_TIMESTAMP:
if (bus->attach_flags & KDBUS_ATTACH_TIMESTAMP) {
m->realtime = d->timestamp.realtime_ns / NSEC_PER_USEC;
m->monotonic = d->timestamp.monotonic_ns / NSEC_PER_USEC;
m->seqnum = d->timestamp.seqnum;
}
break;
case KDBUS_ITEM_PID_COMM:
m->creds.comm = d->str;
m->creds.mask |= SD_BUS_CREDS_COMM & bus->creds_mask;
break;
case KDBUS_ITEM_TID_COMM:
m->creds.tid_comm = d->str;
m->creds.mask |= SD_BUS_CREDS_TID_COMM & bus->creds_mask;
break;
case KDBUS_ITEM_EXE:
m->creds.exe = d->str;
m->creds.mask |= SD_BUS_CREDS_EXE & bus->creds_mask;
break;
case KDBUS_ITEM_CMDLINE:
m->creds.cmdline = d->str;
m->creds.cmdline_size = l;
m->creds.mask |= SD_BUS_CREDS_CMDLINE & bus->creds_mask;
break;
case KDBUS_ITEM_CGROUP:
m->creds.cgroup = d->str;
m->creds.mask |= (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID) & bus->creds_mask;
r = bus_get_root_path(bus);
if (r < 0)
goto fail;
m->creds.cgroup_root = bus->cgroup_root;
break;
case KDBUS_ITEM_AUDIT:
m->creds.audit_session_id = (uint32_t) d->audit.sessionid;
m->creds.audit_login_uid = (uid_t) d->audit.loginuid;
m->creds.mask |= (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID) & bus->creds_mask;
break;
case KDBUS_ITEM_CAPS:
m->creds.capability = (uint8_t *) d->caps.caps;
m->creds.capability_size = d->size - offsetof(struct kdbus_item, caps.caps);
m->creds.mask |= (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS) & bus->creds_mask;
break;
case KDBUS_ITEM_DST_NAME:
if (!service_name_is_valid(d->str))
return -EBADMSG;
destination = d->str;
break;
case KDBUS_ITEM_OWNED_NAME:
if (!service_name_is_valid(d->name.name))
return -EBADMSG;
r = strv_extend(&m->creds.well_known_names, d->name.name);
if (r < 0)
goto fail;
break;
case KDBUS_ITEM_CONN_DESCRIPTION:
m->creds.description = d->str;
m->creds.mask |= SD_BUS_CREDS_DESCRIPTION & bus->creds_mask;
break;
case KDBUS_ITEM_FDS:
case KDBUS_ITEM_SECLABEL:
break;
default:
log_debug("Got unknown field from kernel %llu", d->type);
}
}
r = bus_message_parse_fields(m);
if (r < 0)
goto fail;
/* Override information from the user header with data from the kernel */
if (k->src_id == KDBUS_SRC_ID_KERNEL)
m->sender = m->creds.unique_name = (char*) "org.freedesktop.DBus";
else {
snprintf(m->sender_buffer, sizeof(m->sender_buffer), ":1.%llu", (unsigned long long) k->src_id);
m->sender = m->creds.unique_name = m->sender_buffer;
}
if (destination)
m->destination = destination;
else if (k->dst_id == KDBUS_DST_ID_BROADCAST)
m->destination = NULL;
else if (k->dst_id == KDBUS_DST_ID_NAME)
m->destination = bus->unique_name; /* fill in unique name if the well-known name is missing */
else {
snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
m->destination = m->destination_buffer;
}
/* We take possession of the kmsg struct now */
m->kdbus = k;
m->release_kdbus = true;
m->free_fds = true;
fds = NULL;
bus->rqueue[bus->rqueue_size++] = m;
return 1;
fail:
unset_memfds(m);
sd_bus_message_unref(m);
return r;
}
int bus_kernel_take_fd(sd_bus *b) {
struct kdbus_cmd_hello *hello;
struct kdbus_item *item;
_cleanup_free_ char *g = NULL;
const char *name;
size_t l = 0, m = 0, sz;
int r;
assert(b);
if (b->is_server)
return -EINVAL;
b->use_memfd = 1;
if (b->description) {
g = bus_label_escape(b->description);
if (!g)
return -ENOMEM;
name = g;
} else {
char pr[17] = {};
/* If no name is explicitly set, we'll include a hint
* indicating the library implementation, a hint which
* kind of bus this is and the thread name */
assert_se(prctl(PR_GET_NAME, (unsigned long) pr) >= 0);
if (isempty(pr)) {
name = b->is_system ? "sd-system" :
b->is_user ? "sd-user" : "sd";
} else {
_cleanup_free_ char *e = NULL;
e = bus_label_escape(pr);
if (!e)
return -ENOMEM;
g = strappend(b->is_system ? "sd-system-" :
b->is_user ? "sd-user-" : "sd-",
e);
if (!g)
return -ENOMEM;
name = g;
}
b->description = bus_label_unescape(name);
if (!b->description)
return -ENOMEM;
}
m = strlen(name);
sz = ALIGN8(offsetof(struct kdbus_cmd_hello, items)) +
ALIGN8(offsetof(struct kdbus_item, str) + m + 1);
if (b->fake_creds_valid)
sz += ALIGN8(offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds));
if (b->fake_label) {
l = strlen(b->fake_label);
sz += ALIGN8(offsetof(struct kdbus_item, str) + l + 1);
}
hello = alloca0_align(sz, 8);
hello->size = sz;
hello->flags = b->hello_flags;
hello->attach_flags_send = _KDBUS_ATTACH_ANY;
hello->attach_flags_recv = b->attach_flags;
hello->pool_size = KDBUS_POOL_SIZE;
item = hello->items;
item->size = offsetof(struct kdbus_item, str) + m + 1;
item->type = KDBUS_ITEM_CONN_DESCRIPTION;
memcpy(item->str, name, m + 1);
item = KDBUS_ITEM_NEXT(item);
if (b->fake_creds_valid) {
item->size = offsetof(struct kdbus_item, creds) + sizeof(struct kdbus_creds);
item->type = KDBUS_ITEM_CREDS;
item->creds = b->fake_creds;
item = KDBUS_ITEM_NEXT(item);
}
if (b->fake_label) {
item->size = offsetof(struct kdbus_item, str) + l + 1;
item->type = KDBUS_ITEM_SECLABEL;
memcpy(item->str, b->fake_label, l+1);
}
r = ioctl(b->input_fd, KDBUS_CMD_HELLO, hello);
if (r < 0)
return -errno;
if (!b->kdbus_buffer) {
b->kdbus_buffer = mmap(NULL, KDBUS_POOL_SIZE, PROT_READ, MAP_SHARED, b->input_fd, 0);
if (b->kdbus_buffer == MAP_FAILED) {
b->kdbus_buffer = NULL;
return -errno;
}
}
/* The higher 32bit of the bus_flags fields are considered
* 'incompatible flags'. Refuse them all for now. */
if (hello->bus_flags > 0xFFFFFFFFULL)
return -ENOTSUP;
if (!bloom_validate_parameters((size_t) hello->bloom.size, (unsigned) hello->bloom.n_hash))
return -ENOTSUP;
b->bloom_size = (size_t) hello->bloom.size;
b->bloom_n_hash = (unsigned) hello->bloom.n_hash;
if (asprintf(&b->unique_name, ":1.%llu", (unsigned long long) hello->id) < 0)
return -ENOMEM;
b->unique_id = hello->id;
b->is_kernel = true;
b->bus_client = true;
b->can_fds = !!(hello->flags & KDBUS_HELLO_ACCEPT_FD);
b->message_version = 2;
b->message_endian = BUS_NATIVE_ENDIAN;
/* the kernel told us the UUID of the underlying bus */
memcpy(b->server_id.bytes, hello->id128, sizeof(b->server_id.bytes));
return bus_start_running(b);
}
int bus_kernel_connect(sd_bus *b) {
assert(b);
assert(b->input_fd < 0);
assert(b->output_fd < 0);
assert(b->kernel);
if (b->is_server)
return -EINVAL;
b->input_fd = open(b->kernel, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (b->input_fd < 0)
return -errno;
b->output_fd = b->input_fd;
return bus_kernel_take_fd(b);
}
static void close_kdbus_msg(sd_bus *bus, struct kdbus_msg *k) {
struct kdbus_cmd_free cmd;
struct kdbus_item *d;
assert(bus);
assert(k);
cmd.flags = 0;
cmd.offset = (uint8_t *)k - (uint8_t *)bus->kdbus_buffer;
KDBUS_ITEM_FOREACH(d, k, items) {
if (d->type == KDBUS_ITEM_FDS)
close_many(d->fds, (d->size - offsetof(struct kdbus_item, fds)) / sizeof(int));
else if (d->type == KDBUS_ITEM_PAYLOAD_MEMFD)
safe_close(d->memfd.fd);
}
(void) ioctl(bus->input_fd, KDBUS_CMD_FREE, &cmd);
}
int bus_kernel_write_message(sd_bus *bus, sd_bus_message *m, bool hint_sync_call) {
int r;
assert(bus);
assert(m);
assert(bus->state == BUS_RUNNING);
/* If we can't deliver, we want room for the error message */
r = bus_rqueue_make_room(bus);
if (r < 0)
return r;
r = bus_message_setup_kmsg(bus, m);
if (r < 0)
return r;
/* If this is a synchronous method call, then let's tell the
* kernel, so that it can pass CPU time/scheduling to the
* destination for the time, if it wants to. If we
* synchronously wait for the result anyway, we won't need CPU
* anyway. */
if (hint_sync_call)
m->kdbus->flags |= KDBUS_MSG_FLAGS_EXPECT_REPLY|KDBUS_MSG_FLAGS_SYNC_REPLY;
r = ioctl(bus->output_fd, KDBUS_CMD_MSG_SEND, m->kdbus);
if (r < 0) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *reply;
if (errno == EAGAIN || errno == EINTR)
return 0;
else if (errno == ENXIO || errno == ESRCH) {
/* ENXIO: unique name not known
* ESRCH: well-known name not known */
if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Destination %s not known", m->destination);
else {
log_debug("Could not deliver message to %s as destination is not known. Ignoring.", m->destination);
return 0;
}
} else if (errno == EADDRNOTAVAIL) {
/* EADDRNOTAVAIL: activation is possible, but turned off in request flags */
if (m->header->type == SD_BUS_MESSAGE_METHOD_CALL)
sd_bus_error_setf(&error, SD_BUS_ERROR_SERVICE_UNKNOWN, "Activation of %s not requested", m->destination);
else {
log_debug("Could not deliver message to %s as destination is not activated. Ignoring.", m->destination);
return 0;
}
} else
return -errno;
r = bus_message_new_synthetic_error(
bus,
BUS_MESSAGE_COOKIE(m),
&error,
&reply);
if (r < 0)
return r;
r = bus_seal_synthetic_message(bus, reply);
if (r < 0)
return r;
bus->rqueue[bus->rqueue_size++] = reply;
} else if (hint_sync_call) {
struct kdbus_msg *k;
k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + m->kdbus->offset_reply);
assert(k);
if (k->payload_type == KDBUS_PAYLOAD_DBUS) {
r = bus_kernel_make_message(bus, k);
if (r < 0) {
close_kdbus_msg(bus, k);
/* Anybody can send us invalid messages, let's just drop them. */
if (r == -EBADMSG || r == -EPROTOTYPE)
log_debug("Ignoring invalid message: %s", strerror(-r));
else
return r;
}
} else {
log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type);
close_kdbus_msg(bus, k);
}
}
return 1;
}
static int push_name_owner_changed(sd_bus *bus, const char *name, const char *old_owner, const char *new_owner) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
int r;
assert(bus);
r = sd_bus_message_new_signal(
bus,
&m,
"/org/freedesktop/DBus",
"org.freedesktop.DBus",
"NameOwnerChanged");
if (r < 0)
return r;
r = sd_bus_message_append(m, "sss", name, old_owner, new_owner);
if (r < 0)
return r;
m->sender = "org.freedesktop.DBus";
r = bus_seal_synthetic_message(bus, m);
if (r < 0)
return r;
bus->rqueue[bus->rqueue_size++] = m;
m = NULL;
return 1;
}
static int translate_name_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
char new_owner[UNIQUE_NAME_MAX], old_owner[UNIQUE_NAME_MAX];
assert(bus);
assert(k);
assert(d);
if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR)))
old_owner[0] = 0;
else
sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old_id.id);
if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) {
if (isempty(old_owner))
return 0;
new_owner[0] = 0;
} else
sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new_id.id);
return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner);
}
static int translate_id_change(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
char owner[UNIQUE_NAME_MAX];
assert(bus);
assert(k);
assert(d);
sprintf(owner, ":1.%llu", d->id_change.id);
return push_name_owner_changed(
bus, owner,
d->type == KDBUS_ITEM_ID_ADD ? NULL : owner,
d->type == KDBUS_ITEM_ID_ADD ? owner : NULL);
}
static int translate_reply(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
int r;
assert(bus);
assert(k);
assert(d);
r = bus_message_new_synthetic_error(
bus,
k->cookie_reply,
d->type == KDBUS_ITEM_REPLY_TIMEOUT ?
&SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call timed out") :
&SD_BUS_ERROR_MAKE_CONST(SD_BUS_ERROR_NO_REPLY, "Method call peer died"),
&m);
if (r < 0)
return r;
m->sender = "org.freedesktop.DBus";
r = bus_seal_synthetic_message(bus, m);
if (r < 0)
return r;
bus->rqueue[bus->rqueue_size++] = m;
m = NULL;
return 1;
}
static int bus_kernel_translate_message(sd_bus *bus, struct kdbus_msg *k) {
struct kdbus_item *d, *found = NULL;
static int (* const translate[])(sd_bus *bus, struct kdbus_msg *k, struct kdbus_item *d) = {
[KDBUS_ITEM_NAME_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
[KDBUS_ITEM_NAME_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
[KDBUS_ITEM_NAME_CHANGE - _KDBUS_ITEM_KERNEL_BASE] = translate_name_change,
[KDBUS_ITEM_ID_ADD - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
[KDBUS_ITEM_ID_REMOVE - _KDBUS_ITEM_KERNEL_BASE] = translate_id_change,
[KDBUS_ITEM_REPLY_TIMEOUT - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
[KDBUS_ITEM_REPLY_DEAD - _KDBUS_ITEM_KERNEL_BASE] = translate_reply,
};
assert(bus);
assert(k);
assert(k->payload_type == KDBUS_PAYLOAD_KERNEL);
KDBUS_ITEM_FOREACH(d, k, items) {
if (d->type >= _KDBUS_ITEM_KERNEL_BASE && d->type < _KDBUS_ITEM_KERNEL_BASE + ELEMENTSOF(translate)) {
if (found)
return -EBADMSG;
found = d;
} else
log_debug("Got unknown field from kernel %llu", d->type);
}
if (!found) {
log_debug("Didn't find a kernel message to translate.");
return 0;
}
return translate[found->type - _KDBUS_ITEM_KERNEL_BASE](bus, k, found);
}
int bus_kernel_read_message(sd_bus *bus, bool hint_priority, int64_t priority) {
struct kdbus_cmd_recv recv = {};
struct kdbus_msg *k;
int r;
assert(bus);
r = bus_rqueue_make_room(bus);
if (r < 0)
return r;
if (hint_priority) {
recv.flags |= KDBUS_RECV_USE_PRIORITY;
recv.priority = priority;
}
r = ioctl(bus->input_fd, KDBUS_CMD_MSG_RECV, &recv);
if (r < 0) {
if (errno == EAGAIN)
return 0;
return -errno;
}
k = (struct kdbus_msg *)((uint8_t *)bus->kdbus_buffer + recv.offset);
if (k->payload_type == KDBUS_PAYLOAD_DBUS) {
r = bus_kernel_make_message(bus, k);
/* Anybody can send us invalid messages, let's just drop them. */
if (r == -EBADMSG || r == -EPROTOTYPE) {
log_debug("Ignoring invalid message: %s", strerror(-r));
r = 0;
}
} else if (k->payload_type == KDBUS_PAYLOAD_KERNEL)
r = bus_kernel_translate_message(bus, k);
else {
log_debug("Ignoring message with unknown payload type %llu.", (unsigned long long) k->payload_type);
r = 0;
}
if (r <= 0)
close_kdbus_msg(bus, k);
return r < 0 ? r : 1;
}
int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *mapped, size_t *allocated) {
struct memfd_cache *c;
int fd;
assert(address);
assert(mapped);
assert(allocated);
if (!bus || !bus->is_kernel)
return -ENOTSUP;
assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
if (bus->n_memfd_cache <= 0) {
int r;
assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
r = memfd_new(bus->description);
if (r < 0)
return r;
*address = NULL;
*mapped = 0;
*allocated = 0;
return r;
}
c = &bus->memfd_cache[--bus->n_memfd_cache];
assert(c->fd >= 0);
assert(c->mapped == 0 || c->address);
*address = c->address;
*mapped = c->mapped;
*allocated = c->allocated;
fd = c->fd;
assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
return fd;
}
static void close_and_munmap(int fd, void *address, size_t size) {
if (size > 0)
assert_se(munmap(address, PAGE_ALIGN(size)) >= 0);
safe_close(fd);
}
void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t mapped, size_t allocated) {
struct memfd_cache *c;
uint64_t max_mapped = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
assert(fd >= 0);
assert(mapped == 0 || address);
if (!bus || !bus->is_kernel) {
close_and_munmap(fd, address, mapped);
return;
}
assert_se(pthread_mutex_lock(&bus->memfd_cache_mutex) >= 0);
if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
close_and_munmap(fd, address, mapped);
return;
}
c = &bus->memfd_cache[bus->n_memfd_cache++];
c->fd = fd;
c->address = address;
/* If overly long, let's return a bit to the OS */
if (mapped > max_mapped) {
assert_se(memfd_set_size(fd, max_mapped) >= 0);
assert_se(munmap((uint8_t*) address + max_mapped, PAGE_ALIGN(mapped - max_mapped)) >= 0);
c->mapped = c->allocated = max_mapped;
} else {
c->mapped = mapped;
c->allocated = allocated;
}
assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
}
void bus_kernel_flush_memfd(sd_bus *b) {
unsigned i;
assert(b);
for (i = 0; i < b->n_memfd_cache; i++)
close_and_munmap(b->memfd_cache[i].fd, b->memfd_cache[i].address, b->memfd_cache[i].mapped);
}
int kdbus_translate_request_name_flags(uint64_t flags, uint64_t *kdbus_flags) {
uint64_t f = 0;
assert(kdbus_flags);
if (flags & SD_BUS_NAME_ALLOW_REPLACEMENT)
f |= KDBUS_NAME_ALLOW_REPLACEMENT;
if (flags & SD_BUS_NAME_REPLACE_EXISTING)
f |= KDBUS_NAME_REPLACE_EXISTING;
if (flags & SD_BUS_NAME_QUEUE)
f |= KDBUS_NAME_QUEUE;
*kdbus_flags = f;
return 0;
}
int kdbus_translate_attach_flags(uint64_t mask, uint64_t *kdbus_mask) {
uint64_t m = 0;
assert(kdbus_mask);
if (mask & (SD_BUS_CREDS_UID|SD_BUS_CREDS_GID|SD_BUS_CREDS_PID|SD_BUS_CREDS_PID_STARTTIME|SD_BUS_CREDS_TID))
m |= KDBUS_ATTACH_CREDS;
if (mask & SD_BUS_CREDS_COMM)
m |= KDBUS_ATTACH_PID_COMM;
if (mask & SD_BUS_CREDS_TID_COMM)
m |= KDBUS_ATTACH_TID_COMM;
if (mask & SD_BUS_CREDS_EXE)
m |= KDBUS_ATTACH_EXE;
if (mask & SD_BUS_CREDS_CMDLINE)
m |= KDBUS_ATTACH_CMDLINE;
if (mask & (SD_BUS_CREDS_CGROUP|SD_BUS_CREDS_UNIT|SD_BUS_CREDS_USER_UNIT|SD_BUS_CREDS_SLICE|SD_BUS_CREDS_SESSION|SD_BUS_CREDS_OWNER_UID))
m |= KDBUS_ATTACH_CGROUP;
if (mask & (SD_BUS_CREDS_EFFECTIVE_CAPS|SD_BUS_CREDS_PERMITTED_CAPS|SD_BUS_CREDS_INHERITABLE_CAPS|SD_BUS_CREDS_BOUNDING_CAPS))
m |= KDBUS_ATTACH_CAPS;
if (mask & SD_BUS_CREDS_SELINUX_CONTEXT)
m |= KDBUS_ATTACH_SECLABEL;
if (mask & (SD_BUS_CREDS_AUDIT_SESSION_ID|SD_BUS_CREDS_AUDIT_LOGIN_UID))
m |= KDBUS_ATTACH_AUDIT;
if (mask & SD_BUS_CREDS_WELL_KNOWN_NAMES)
m |= KDBUS_ATTACH_NAMES;
if (mask & SD_BUS_CREDS_DESCRIPTION)
m |= KDBUS_ATTACH_CONN_DESCRIPTION;
*kdbus_mask = m;
return 0;
}
int bus_kernel_create_bus(const char *name, bool world, char **s) {
struct kdbus_cmd_make *make;
struct kdbus_item *n;
int fd;
assert(name);
assert(s);
fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return -errno;
make = alloca0_align(ALIGN8(offsetof(struct kdbus_cmd_make, items) +
offsetof(struct kdbus_item, data64) + sizeof(uint64_t) +
offsetof(struct kdbus_item, str) +
DECIMAL_STR_MAX(uid_t) + 1 + strlen(name) + 1),
8);
make->size = offsetof(struct kdbus_cmd_make, items);
n = make->items;
n->size = offsetof(struct kdbus_item, bloom_parameter) +
sizeof(struct kdbus_bloom_parameter);
n->type = KDBUS_ITEM_BLOOM_PARAMETER;
n->bloom_parameter.size = DEFAULT_BLOOM_SIZE;
n->bloom_parameter.n_hash = DEFAULT_BLOOM_N_HASH;
assert_cc(DEFAULT_BLOOM_SIZE > 0);
assert_cc(DEFAULT_BLOOM_N_HASH > 0);
make->size += ALIGN8(n->size);
n = KDBUS_ITEM_NEXT(n);
sprintf(n->str, UID_FMT "-%s", getuid(), name);
n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
n->type = KDBUS_ITEM_MAKE_NAME;
make->size += ALIGN8(n->size);
make->flags = world ? KDBUS_MAKE_ACCESS_WORLD : 0;
if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
safe_close(fd);
return -errno;
}
if (s) {
char *p;
p = strjoin("/dev/kdbus/", n->str, "/bus", NULL);
if (!p) {
safe_close(fd);
return -ENOMEM;
}
*s = p;
}
return fd;
}
static int bus_kernel_translate_access(BusPolicyAccess access) {
assert(access >= 0);
assert(access < _BUS_POLICY_ACCESS_MAX);
switch (access) {
case BUS_POLICY_ACCESS_SEE:
return KDBUS_POLICY_SEE;
case BUS_POLICY_ACCESS_TALK:
return KDBUS_POLICY_TALK;
case BUS_POLICY_ACCESS_OWN:
return KDBUS_POLICY_OWN;
default:
assert_not_reached("Unknown policy access");
}
}
static int bus_kernel_translate_policy(const BusNamePolicy *policy, struct kdbus_item *item) {
int r;
assert(policy);
assert(item);
switch (policy->type) {
case BUSNAME_POLICY_TYPE_USER: {
const char *user = policy->name;
uid_t uid;
r = get_user_creds(&user, &uid, NULL, NULL, NULL);
if (r < 0)
return r;
item->policy_access.type = KDBUS_POLICY_ACCESS_USER;
item->policy_access.id = uid;
break;
}
case BUSNAME_POLICY_TYPE_GROUP: {
const char *group = policy->name;
gid_t gid;
r = get_group_creds(&group, &gid);
if (r < 0)
return r;
item->policy_access.type = KDBUS_POLICY_ACCESS_GROUP;
item->policy_access.id = gid;
break;
}
default:
assert_not_reached("Unknown policy type");
}
item->policy_access.access = bus_kernel_translate_access(policy->access);
return 0;
}
int bus_kernel_open_bus_fd(const char *bus, char **path) {
char *p;
int fd;
size_t len;
len = strlen("/dev/kdbus/") + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + strlen("/bus") + 1;
if (path) {
p = malloc(len);
if (!p)
return -ENOMEM;
*path = p;
} else
p = alloca(len);
sprintf(p, "/dev/kdbus/" UID_FMT "-%s/bus", getuid(), bus);
fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return -errno;
return fd;
}
int bus_kernel_create_endpoint(const char *bus_name, const char *ep_name, char **ep_path) {
_cleanup_free_ char *path = NULL;
struct kdbus_cmd_make *make;
struct kdbus_item *n;
size_t size;
int fd;
fd = bus_kernel_open_bus_fd(bus_name, &path);
if (fd < 0)
return fd;
size = ALIGN8(offsetof(struct kdbus_cmd_make, items));
size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(ep_name) + 1);
make = alloca0_align(size, 8);
make->size = size;
make->flags = KDBUS_MAKE_ACCESS_WORLD;
n = make->items;
n->type = KDBUS_ITEM_MAKE_NAME;
n->size = offsetof(struct kdbus_item, str) + strlen(ep_name) + 1;
strcpy(n->str, ep_name);
if (ioctl(fd, KDBUS_CMD_ENDPOINT_MAKE, make) < 0) {
safe_close(fd);
return -errno;
}
if (ep_path) {
char *p;
p = strjoin(dirname(path), "/", ep_name, NULL);
if (!p) {
safe_close(fd);
return -ENOMEM;
}
*ep_path = p;
}
return fd;
}
int bus_kernel_set_endpoint_policy(int fd, uid_t uid, BusEndpoint *ep) {
struct kdbus_cmd_update *update;
struct kdbus_item *n;
BusEndpointPolicy *po;
Iterator i;
size_t size;
int r;
size = ALIGN8(offsetof(struct kdbus_cmd_update, items));
HASHMAP_FOREACH(po, ep->policy_hash, i) {
size += ALIGN8(offsetof(struct kdbus_item, str) + strlen(po->name) + 1);
size += ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access));
}
update = alloca0_align(size, 8);
update->size = size;
n = update->items;
HASHMAP_FOREACH(po, ep->policy_hash, i) {
n->type = KDBUS_ITEM_NAME;
n->size = offsetof(struct kdbus_item, str) + strlen(po->name) + 1;
strcpy(n->str, po->name);
n = KDBUS_ITEM_NEXT(n);
n->type = KDBUS_ITEM_POLICY_ACCESS;
n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
n->policy_access.type = KDBUS_POLICY_ACCESS_USER;
n->policy_access.access = bus_kernel_translate_access(po->access);
n->policy_access.id = uid;
n = KDBUS_ITEM_NEXT(n);
}
r = ioctl(fd, KDBUS_CMD_ENDPOINT_UPDATE, update);
if (r < 0)
return -errno;
return 0;
}
int bus_kernel_make_starter(
int fd,
const char *name,
bool activating,
bool accept_fd,
BusNamePolicy *policy,
BusPolicyAccess world_policy) {
struct kdbus_cmd_hello *hello;
struct kdbus_item *n;
size_t policy_cnt = 0;
BusNamePolicy *po;
size_t size;
int r;
assert(fd >= 0);
assert(name);
LIST_FOREACH(policy, po, policy)
policy_cnt++;
if (world_policy >= 0)
policy_cnt++;
size = ALIGN8(offsetof(struct kdbus_cmd_hello, items)) +
ALIGN8(offsetof(struct kdbus_item, str) + strlen(name) + 1) +
policy_cnt * ALIGN8(offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access));
hello = alloca0_align(size, 8);
n = hello->items;
strcpy(n->str, name);
n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
n->type = KDBUS_ITEM_NAME;
n = KDBUS_ITEM_NEXT(n);
LIST_FOREACH(policy, po, policy) {
n->type = KDBUS_ITEM_POLICY_ACCESS;
n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
r = bus_kernel_translate_policy(po, n);
if (r < 0)
return r;
n = KDBUS_ITEM_NEXT(n);
}
if (world_policy >= 0) {
n->type = KDBUS_ITEM_POLICY_ACCESS;
n->size = offsetof(struct kdbus_item, policy_access) + sizeof(struct kdbus_policy_access);
n->policy_access.type = KDBUS_POLICY_ACCESS_WORLD;
n->policy_access.access = bus_kernel_translate_access(world_policy);
}
hello->size = size;
hello->flags =
(activating ? KDBUS_HELLO_ACTIVATOR : KDBUS_HELLO_POLICY_HOLDER) |
(accept_fd ? KDBUS_HELLO_ACCEPT_FD : 0);
hello->pool_size = KDBUS_POOL_SIZE;
hello->attach_flags_send = _KDBUS_ATTACH_ANY;
hello->attach_flags_recv = _KDBUS_ATTACH_ALL;
if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0)
return -errno;
/* The higher 32bit of the bus_flags fields are considered
* 'incompatible flags'. Refuse them all for now. */
if (hello->bus_flags > 0xFFFFFFFFULL)
return -ENOTSUP;
if (!bloom_validate_parameters((size_t) hello->bloom.size, (unsigned) hello->bloom.n_hash))
return -ENOTSUP;
return fd;
}
int bus_kernel_create_domain(const char *name, char **s) {
struct kdbus_cmd_make *make;
struct kdbus_item *n;
int fd;
assert(name);
assert(s);
fd = open("/dev/kdbus/control", O_RDWR|O_NOCTTY|O_CLOEXEC);
if (fd < 0)
return -errno;
make = alloca0_align(ALIGN8(offsetof(struct kdbus_cmd_make, items) +
offsetof(struct kdbus_item, str) +
strlen(name) + 1),
8);
n = make->items;
strcpy(n->str, name);
n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
n->type = KDBUS_ITEM_MAKE_NAME;
make->size = ALIGN8(offsetof(struct kdbus_cmd_make, items) + n->size);
make->flags = KDBUS_MAKE_ACCESS_WORLD;
if (ioctl(fd, KDBUS_CMD_DOMAIN_MAKE, make) < 0) {
safe_close(fd);
return -errno;
}
/* The higher 32bit of the flags field are considered
* 'incompatible flags'. Refuse them all for now. */
if (make->flags > 0xFFFFFFFFULL) {
safe_close(fd);
return -ENOTSUP;
}
if (s) {
char *p;
p = strappend("/dev/kdbus/domain/", name);
if (!p) {
safe_close(fd);
return -ENOMEM;
}
*s = p;
}
return fd;
}
int bus_kernel_try_close(sd_bus *bus) {
assert(bus);
assert(bus->is_kernel);
if (ioctl(bus->input_fd, KDBUS_CMD_BYEBYE) < 0)
return -errno;
return 0;
}
int bus_kernel_drop_one(int fd) {
struct kdbus_cmd_recv recv = {
.flags = KDBUS_RECV_DROP
};
assert(fd >= 0);
if (ioctl(fd, KDBUS_CMD_MSG_RECV, &recv) < 0)
return -errno;
return 0;
}