b->bus_client = true;
b->can_fds = !!(hello.conn_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));
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
+ else {
+ log_debug("Could not deliver message to %s as destination is not known. Ignoring.", m->destination);
return 0;
+ }
} else if (errno == EADDRNOTAVAIL) {
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
+ else {
+ log_debug("Could not deliver message to %s as destination is not activated. Ignoring.", m->destination);
return 0;
+ }
} else
return -errno;
assert(k);
assert(d);
- if (d->name_change.flags != 0)
- return 0;
-
- if (d->type == KDBUS_ITEM_NAME_ADD)
+ if (d->type == KDBUS_ITEM_NAME_ADD || (d->name_change.old.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);
+ sprintf(old_owner, ":1.%llu", (unsigned long long) d->name_change.old.id);
+
+ if (d->type == KDBUS_ITEM_NAME_REMOVE || (d->name_change.new.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))) {
+
+ if (isempty(old_owner))
+ return 0;
- if (d->type == KDBUS_ITEM_NAME_REMOVE)
new_owner[0] = 0;
- else
- sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new_id);
+ } else
+ sprintf(new_owner, ":1.%llu", (unsigned long long) d->name_change.new.id);
return push_name_owner_changed(bus, d->name_change.name, old_owner, new_owner);
}
case KDBUS_ITEM_PAYLOAD_OFF:
if (!h) {
- h = (struct bus_header *)((uint8_t *)bus->kdbus_buffer + d->vec.offset);
+ h = (struct bus_header *)((uint8_t *)k + d->vec.offset);
if (!bus_header_is_complete(h, d->vec.size))
return -EBADMSG;
if (r < 0)
return r;
+ /* The well-known names list is different from the other
+ credentials. If we asked for it, but nothing is there, this
+ means that the list of well-known names is simply empty, not
+ that we lack any data */
+
+ m->creds.mask |= (SD_BUS_CREDS_UNIQUE_NAME|SD_BUS_CREDS_WELL_KNOWN_NAMES) & bus->creds_mask;
+
KDBUS_ITEM_FOREACH(d, k, items) {
size_t l;
if (idx >= begin_body) {
if (!part->is_zero)
- part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset;
+ part->data = (uint8_t *)k + d->vec.offset;
part->size = d->vec.size;
} else {
if (!part->is_zero)
- part->data = (uint8_t *)bus->kdbus_buffer + d->vec.offset + (begin_body - idx);
+ part->data = (uint8_t *)k + d->vec.offset + (begin_body - idx);
part->size = d->vec.size - (begin_body - idx);
}
r = strv_extend(&m->creds.well_known_names, d->name.name);
if (r < 0)
goto fail;
- m->creds.mask |= SD_BUS_CREDS_WELL_KNOWN_NAMES & bus->creds_mask;
break;
case KDBUS_ITEM_FDS:
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 = "org.freedesktop.DBus";
+ 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;
- m->creds.mask |= SD_BUS_CREDS_UNIQUE_NAME & bus->creds_mask;
}
- if (!m->destination) {
- if (destination)
- m->destination = destination;
- else if (k->dst_id != KDBUS_DST_ID_NAME &&
- k->dst_id != KDBUS_DST_ID_BROADCAST) {
- snprintf(m->destination_buffer, sizeof(m->destination_buffer), ":1.%llu", (unsigned long long) k->dst_id);
- m->destination = m->destination_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 */
/* Anybody can send us invalid messages, let's just drop them. */
if (r == -EBADMSG || r == -EPROTOTYPE) {
- log_error("Ignoring invalid message: %s", strerror(-r));
+ log_debug("Ignoring invalid message: %s", strerror(-r));
r = 0;
}
return r < 0 ? r : 1;
}
-int bus_kernel_pop_memfd(sd_bus *bus, void **address, size_t *size) {
+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(size);
+ assert(mapped);
+ assert(allocated);
if (!bus || !bus->is_kernel)
return -ENOTSUP;
return -errno;
*address = NULL;
- *size = 0;
+ *mapped = 0;
+ *allocated = 0;
return fd;
}
c = &bus->memfd_cache[--bus->n_memfd_cache];
assert(c->fd >= 0);
- assert(c->size == 0 || c->address);
+ assert(c->mapped == 0 || c->address);
*address = c->address;
- *size = c->size;
+ *mapped = c->mapped;
+ *allocated = c->allocated;
fd = c->fd;
assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
close_nointr_nofail(fd);
}
-void bus_kernel_push_memfd(sd_bus *bus, int fd, void *address, size_t size) {
+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_sz = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
+ uint64_t max_mapped = PAGE_ALIGN(MEMFD_CACHE_ITEM_SIZE_MAX);
assert(fd >= 0);
- assert(size == 0 || address);
+ assert(mapped == 0 || address);
if (!bus || !bus->is_kernel) {
- close_and_munmap(fd, address, size);
+ close_and_munmap(fd, address, mapped);
return;
}
if (bus->n_memfd_cache >= ELEMENTSOF(bus->memfd_cache)) {
assert_se(pthread_mutex_unlock(&bus->memfd_cache_mutex) >= 0);
- close_and_munmap(fd, address, size);
+ close_and_munmap(fd, address, mapped);
return;
}
c->address = address;
/* If overly long, let's return a bit to the OS */
- if (size > max_sz) {
- assert_se(ioctl(fd, KDBUS_CMD_MEMFD_SIZE_SET, &max_sz) >= 0);
- assert_se(munmap((uint8_t*) address + max_sz, PAGE_ALIGN(size - max_sz)) >= 0);
- c->size = max_sz;
- } else
- c->size = size;
+ if (mapped > max_mapped) {
+ assert_se(ioctl(fd, KDBUS_CMD_MEMFD_SIZE_SET, &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);
}
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].size);
+ 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) {
if (flags & SD_BUS_NAME_REPLACE_EXISTING)
f |= KDBUS_NAME_REPLACE_EXISTING;
- if (!(flags & SD_BUS_NAME_DO_NOT_QUEUE))
+ if (flags & SD_BUS_NAME_QUEUE)
f |= KDBUS_NAME_QUEUE;
*kdbus_flags = f;
}
int bus_kernel_create_bus(const char *name, char **s) {
- struct kdbus_cmd_bus_make *make;
+ struct kdbus_cmd_make *make;
struct kdbus_item *n;
int fd;
if (fd < 0)
return -errno;
- make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_bus_make, items) +
+ make = alloca0(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));
+ make->size = offsetof(struct kdbus_cmd_make, items);
+
n = make->items;
+ n->size = offsetof(struct kdbus_item, data64) + sizeof(uint64_t);
+ n->type = KDBUS_ITEM_BLOOM_SIZE;
+ n->data64[0] = BLOOM_SIZE;
+ assert_cc(BLOOM_SIZE % 8 == 0);
+ make->size += ALIGN8(n->size);
+
+ n = KDBUS_ITEM_NEXT(n);
sprintf(n->str, "%lu-%s", (unsigned long) 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->size = ALIGN8(offsetof(struct kdbus_cmd_bus_make, items) + n->size);
make->flags = KDBUS_MAKE_POLICY_OPEN;
- make->bloom_size = BLOOM_SIZE;
- assert_cc(BLOOM_SIZE % 8 == 0);
if (ioctl(fd, KDBUS_CMD_BUS_MAKE, make) < 0) {
close_nointr_nofail(fd);
n = hello->items;
strcpy(n->str, name);
n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
- n->type = KDBUS_ITEM_STARTER_NAME;
+ n->type = KDBUS_ITEM_NAME;
hello->size = ALIGN8(offsetof(struct kdbus_cmd_hello, items) + n->size);
- hello->conn_flags = KDBUS_HELLO_STARTER;
+ hello->conn_flags = KDBUS_HELLO_ACTIVATOR;
hello->pool_size = KDBUS_POOL_SIZE;
if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) {
}
int bus_kernel_create_namespace(const char *name, char **s) {
- struct kdbus_cmd_ns_make *make;
+ struct kdbus_cmd_make *make;
struct kdbus_item *n;
int fd;
if (fd < 0)
return -errno;
- make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_ns_make, items) +
+ make = alloca0(ALIGN8(offsetof(struct kdbus_cmd_make, items) +
offsetof(struct kdbus_item, str) +
strlen(name) + 1));
n->size = offsetof(struct kdbus_item, str) + strlen(n->str) + 1;
n->type = KDBUS_ITEM_MAKE_NAME;
- make->size = ALIGN8(offsetof(struct kdbus_cmd_ns_make, items) + n->size);
+ make->size = ALIGN8(offsetof(struct kdbus_cmd_make, items) + n->size);
make->flags = KDBUS_MAKE_POLICY_OPEN | KDBUS_MAKE_ACCESS_WORLD;
if (ioctl(fd, KDBUS_CMD_NS_MAKE, make) < 0) {
return fd;
}
+
+int bus_kernel_create_monitor(const char *bus) {
+ struct kdbus_cmd_hello *hello;
+ char *p;
+ int fd;
+
+ assert(bus);
+
+ p = alloca(sizeof("/dev/kdbus/") - 1 + DECIMAL_STR_MAX(uid_t) + 1 + strlen(bus) + sizeof("/bus"));
+ sprintf(p, "/dev/kdbus/%lu-%s/bus", (unsigned long) getuid(), bus);
+
+ fd = open(p, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
+ return -errno;
+
+ hello = alloca0(sizeof(struct kdbus_cmd_hello));
+ hello->size = sizeof(struct kdbus_cmd_hello);
+ hello->conn_flags = KDBUS_HELLO_ACTIVATOR;
+ hello->pool_size = KDBUS_POOL_SIZE;
+
+ if (ioctl(fd, KDBUS_CMD_HELLO, hello) < 0) {
+ close_nointr_nofail(fd);
+ return -errno;
+ }
+
+ /* The higher 32bit of both flags fields are considered
+ * 'incompatible flags'. Refuse them all for now. */
+ if (hello->bus_flags > 0xFFFFFFFFULL ||
+ hello->conn_flags > 0xFFFFFFFFULL) {
+ close_nointr_nofail(fd);
+ return -ENOTSUP;
+ }
+
+ 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;
+}