diff options
Diffstat (limited to 'ipc/kdbus')
39 files changed, 0 insertions, 13449 deletions
diff --git a/ipc/kdbus/Makefile b/ipc/kdbus/Makefile deleted file mode 100644 index 66663a124..000000000 --- a/ipc/kdbus/Makefile +++ /dev/null @@ -1,33 +0,0 @@ -# -# By setting KDBUS_EXT=2, the kdbus module will be built as kdbus2.ko, and -# KBUILD_MODNAME=kdbus2. This has the effect that all exported objects have -# different names than usually (kdbus2fs, /sys/fs/kdbus2/) and you can run -# your test-infrastructure against the kdbus2.ko, while running your system -# on kdbus.ko. -# -# To just build the module, use: -# make KDBUS_EXT=2 M=ipc/kdbus -# - -kdbus$(KDBUS_EXT)-y := \ - bus.o \ - connection.o \ - endpoint.o \ - fs.o \ - handle.o \ - item.o \ - main.o \ - match.o \ - message.o \ - metadata.o \ - names.o \ - node.o \ - notify.o \ - domain.o \ - policy.o \ - pool.o \ - reply.o \ - queue.o \ - util.o - -obj-$(CONFIG_KDBUS) += kdbus$(KDBUS_EXT).o diff --git a/ipc/kdbus/bus.c b/ipc/kdbus/bus.c deleted file mode 100644 index e636d3478..000000000 --- a/ipc/kdbus/bus.c +++ /dev/null @@ -1,514 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/fs.h> -#include <linux/hashtable.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/random.h> -#include <linux/sched.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/uio.h> - -#include "bus.h" -#include "notify.h" -#include "connection.h" -#include "domain.h" -#include "endpoint.h" -#include "handle.h" -#include "item.h" -#include "match.h" -#include "message.h" -#include "metadata.h" -#include "names.h" -#include "policy.h" -#include "util.h" - -static void kdbus_bus_free(struct kdbus_node *node) -{ - struct kdbus_bus *bus = container_of(node, struct kdbus_bus, node); - - WARN_ON(!list_empty(&bus->monitors_list)); - WARN_ON(!hash_empty(bus->conn_hash)); - - kdbus_notify_free(bus); - - kdbus_user_unref(bus->creator); - kdbus_name_registry_free(bus->name_registry); - kdbus_domain_unref(bus->domain); - kdbus_policy_db_clear(&bus->policy_db); - kdbus_meta_proc_unref(bus->creator_meta); - kfree(bus); -} - -static void kdbus_bus_release(struct kdbus_node *node, bool was_active) -{ - struct kdbus_bus *bus = container_of(node, struct kdbus_bus, node); - - if (was_active) - atomic_dec(&bus->creator->buses); -} - -static struct kdbus_bus *kdbus_bus_new(struct kdbus_domain *domain, - const char *name, - struct kdbus_bloom_parameter *bloom, - const u64 *pattach_owner, - u64 flags, kuid_t uid, kgid_t gid) -{ - struct kdbus_bus *b; - u64 attach_owner; - int ret; - - if (bloom->size < 8 || bloom->size > KDBUS_BUS_BLOOM_MAX_SIZE || - !KDBUS_IS_ALIGNED8(bloom->size) || bloom->n_hash < 1) - return ERR_PTR(-EINVAL); - - ret = kdbus_sanitize_attach_flags(pattach_owner ? *pattach_owner : 0, - &attach_owner); - if (ret < 0) - return ERR_PTR(ret); - - ret = kdbus_verify_uid_prefix(name, domain->user_namespace, uid); - if (ret < 0) - return ERR_PTR(ret); - - b = kzalloc(sizeof(*b), GFP_KERNEL); - if (!b) - return ERR_PTR(-ENOMEM); - - kdbus_node_init(&b->node, KDBUS_NODE_BUS); - - b->node.free_cb = kdbus_bus_free; - b->node.release_cb = kdbus_bus_release; - b->node.uid = uid; - b->node.gid = gid; - b->node.mode = S_IRUSR | S_IXUSR; - - if (flags & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD)) - b->node.mode |= S_IRGRP | S_IXGRP; - if (flags & KDBUS_MAKE_ACCESS_WORLD) - b->node.mode |= S_IROTH | S_IXOTH; - - b->id = atomic64_inc_return(&domain->last_id); - b->bus_flags = flags; - b->attach_flags_owner = attach_owner; - generate_random_uuid(b->id128); - b->bloom = *bloom; - b->domain = kdbus_domain_ref(domain); - - kdbus_policy_db_init(&b->policy_db); - - init_rwsem(&b->conn_rwlock); - hash_init(b->conn_hash); - INIT_LIST_HEAD(&b->monitors_list); - - INIT_LIST_HEAD(&b->notify_list); - spin_lock_init(&b->notify_lock); - mutex_init(&b->notify_flush_lock); - - ret = kdbus_node_link(&b->node, &domain->node, name); - if (ret < 0) - goto exit_unref; - - /* cache the metadata/credentials of the creator */ - b->creator_meta = kdbus_meta_proc_new(); - if (IS_ERR(b->creator_meta)) { - ret = PTR_ERR(b->creator_meta); - b->creator_meta = NULL; - goto exit_unref; - } - - ret = kdbus_meta_proc_collect(b->creator_meta, - KDBUS_ATTACH_CREDS | - KDBUS_ATTACH_PIDS | - KDBUS_ATTACH_AUXGROUPS | - KDBUS_ATTACH_TID_COMM | - KDBUS_ATTACH_PID_COMM | - KDBUS_ATTACH_EXE | - KDBUS_ATTACH_CMDLINE | - KDBUS_ATTACH_CGROUP | - KDBUS_ATTACH_CAPS | - KDBUS_ATTACH_SECLABEL | - KDBUS_ATTACH_AUDIT); - if (ret < 0) - goto exit_unref; - - b->name_registry = kdbus_name_registry_new(); - if (IS_ERR(b->name_registry)) { - ret = PTR_ERR(b->name_registry); - b->name_registry = NULL; - goto exit_unref; - } - - /* - * Bus-limits of the creator are accounted on its real UID, just like - * all other per-user limits. - */ - b->creator = kdbus_user_lookup(domain, current_uid()); - if (IS_ERR(b->creator)) { - ret = PTR_ERR(b->creator); - b->creator = NULL; - goto exit_unref; - } - - return b; - -exit_unref: - kdbus_node_drain(&b->node); - kdbus_node_unref(&b->node); - return ERR_PTR(ret); -} - -/** - * kdbus_bus_ref() - increase the reference counter of a kdbus_bus - * @bus: The bus to reference - * - * Every user of a bus, except for its creator, must add a reference to the - * kdbus_bus using this function. - * - * Return: the bus itself - */ -struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus) -{ - if (bus) - kdbus_node_ref(&bus->node); - return bus; -} - -/** - * kdbus_bus_unref() - decrease the reference counter of a kdbus_bus - * @bus: The bus to unref - * - * Release a reference. If the reference count drops to 0, the bus will be - * freed. - * - * Return: NULL - */ -struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus) -{ - if (bus) - kdbus_node_unref(&bus->node); - return NULL; -} - -/** - * kdbus_bus_find_conn_by_id() - find a connection with a given id - * @bus: The bus to look for the connection - * @id: The 64-bit connection id - * - * Looks up a connection with a given id. The returned connection - * is ref'ed, and needs to be unref'ed by the user. Returns NULL if - * the connection can't be found. - */ -struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id) -{ - struct kdbus_conn *conn, *found = NULL; - - down_read(&bus->conn_rwlock); - hash_for_each_possible(bus->conn_hash, conn, hentry, id) - if (conn->id == id) { - found = kdbus_conn_ref(conn); - break; - } - up_read(&bus->conn_rwlock); - - return found; -} - -/** - * kdbus_bus_broadcast() - send a message to all subscribed connections - * @bus: The bus the connections are connected to - * @conn_src: The source connection, may be %NULL for kernel notifications - * @staging: Staging object containing the message to send - * - * Send message to all connections that are currently active on the bus. - * Connections must still have matches installed in order to let the message - * pass. - * - * The caller must hold the name-registry lock of @bus. - */ -void kdbus_bus_broadcast(struct kdbus_bus *bus, - struct kdbus_conn *conn_src, - struct kdbus_staging *staging) -{ - struct kdbus_conn *conn_dst; - unsigned int i; - int ret; - - lockdep_assert_held(&bus->name_registry->rwlock); - - /* - * Make sure broadcast are queued on monitors before we send it out to - * anyone else. Otherwise, connections might react to broadcasts before - * the monitor gets the broadcast queued. In the worst case, the - * monitor sees a reaction to the broadcast before the broadcast itself. - * We don't give ordering guarantees across connections (and monitors - * can re-construct order via sequence numbers), but we should at least - * try to avoid re-ordering for monitors. - */ - kdbus_bus_eavesdrop(bus, conn_src, staging); - - down_read(&bus->conn_rwlock); - hash_for_each(bus->conn_hash, i, conn_dst, hentry) { - if (!kdbus_conn_is_ordinary(conn_dst)) - continue; - - /* - * Check if there is a match for the kmsg object in - * the destination connection match db - */ - if (!kdbus_match_db_match_msg(conn_dst->match_db, conn_src, - staging)) - continue; - - if (conn_src) { - /* - * Anyone can send broadcasts, as they have no - * destination. But a receiver needs TALK access to - * the sender in order to receive broadcasts. - */ - if (!kdbus_conn_policy_talk(conn_dst, NULL, conn_src)) - continue; - } else { - /* - * Check if there is a policy db that prevents the - * destination connection from receiving this kernel - * notification - */ - if (!kdbus_conn_policy_see_notification(conn_dst, NULL, - staging->msg)) - continue; - } - - ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging, - NULL, NULL); - if (ret < 0) - kdbus_conn_lost_message(conn_dst); - } - up_read(&bus->conn_rwlock); -} - -/** - * kdbus_bus_eavesdrop() - send a message to all subscribed monitors - * @bus: The bus the monitors are connected to - * @conn_src: The source connection, may be %NULL for kernel notifications - * @staging: Staging object containing the message to send - * - * Send message to all monitors that are currently active on the bus. Monitors - * must still have matches installed in order to let the message pass. - * - * The caller must hold the name-registry lock of @bus. - */ -void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - struct kdbus_conn *conn_src, - struct kdbus_staging *staging) -{ - struct kdbus_conn *conn_dst; - int ret; - - /* - * Monitor connections get all messages; ignore possible errors - * when sending messages to monitor connections. - */ - - lockdep_assert_held(&bus->name_registry->rwlock); - - down_read(&bus->conn_rwlock); - list_for_each_entry(conn_dst, &bus->monitors_list, monitor_entry) { - ret = kdbus_conn_entry_insert(conn_src, conn_dst, staging, - NULL, NULL); - if (ret < 0) - kdbus_conn_lost_message(conn_dst); - } - up_read(&bus->conn_rwlock); -} - -/** - * kdbus_cmd_bus_make() - handle KDBUS_CMD_BUS_MAKE - * @domain: domain to operate on - * @argp: command payload - * - * Return: NULL or newly created bus on success, ERR_PTR on failure. - */ -struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, - void __user *argp) -{ - struct kdbus_bus *bus = NULL; - struct kdbus_cmd *cmd; - struct kdbus_ep *ep = NULL; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_MAKE_NAME, .mandatory = true }, - { .type = KDBUS_ITEM_BLOOM_PARAMETER, .mandatory = true }, - { .type = KDBUS_ITEM_ATTACH_FLAGS_SEND }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE | - KDBUS_MAKE_ACCESS_GROUP | - KDBUS_MAKE_ACCESS_WORLD, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret < 0) - return ERR_PTR(ret); - if (ret > 0) - return NULL; - - bus = kdbus_bus_new(domain, - argv[1].item->str, &argv[2].item->bloom_parameter, - argv[3].item ? argv[3].item->data64 : NULL, - cmd->flags, current_euid(), current_egid()); - if (IS_ERR(bus)) { - ret = PTR_ERR(bus); - bus = NULL; - goto exit; - } - - if (atomic_inc_return(&bus->creator->buses) > KDBUS_USER_MAX_BUSES) { - atomic_dec(&bus->creator->buses); - ret = -EMFILE; - goto exit; - } - - if (!kdbus_node_activate(&bus->node)) { - atomic_dec(&bus->creator->buses); - ret = -ESHUTDOWN; - goto exit; - } - - ep = kdbus_ep_new(bus, "bus", cmd->flags, bus->node.uid, bus->node.gid, - false); - if (IS_ERR(ep)) { - ret = PTR_ERR(ep); - ep = NULL; - goto exit; - } - - if (!kdbus_node_activate(&ep->node)) { - ret = -ESHUTDOWN; - goto exit; - } - - /* - * Drop our own reference, effectively causing the endpoint to be - * deactivated and released when the parent bus is. - */ - ep = kdbus_ep_unref(ep); - -exit: - ret = kdbus_args_clear(&args, ret); - if (ret < 0) { - if (ep) { - kdbus_node_drain(&ep->node); - kdbus_ep_unref(ep); - } - if (bus) { - kdbus_node_drain(&bus->node); - kdbus_bus_unref(bus); - } - return ERR_PTR(ret); - } - return bus; -} - -/** - * kdbus_cmd_bus_creator_info() - handle KDBUS_CMD_BUS_CREATOR_INFO - * @conn: connection to operate on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp) -{ - struct kdbus_cmd_info *cmd; - struct kdbus_bus *bus = conn->ep->bus; - struct kdbus_pool_slice *slice = NULL; - struct kdbus_item *meta_items = NULL; - struct kdbus_item_header item_hdr; - struct kdbus_info info = {}; - size_t meta_size, name_len, cnt = 0; - struct kvec kvec[6]; - u64 attach_flags, size = 0; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - ret = kdbus_sanitize_attach_flags(cmd->attach_flags, &attach_flags); - if (ret < 0) - goto exit; - - attach_flags &= bus->attach_flags_owner; - - ret = kdbus_meta_emit(bus->creator_meta, NULL, NULL, conn, - attach_flags, &meta_items, &meta_size); - if (ret < 0) - goto exit; - - name_len = strlen(bus->node.name) + 1; - info.id = bus->id; - info.flags = bus->bus_flags; - item_hdr.type = KDBUS_ITEM_MAKE_NAME; - item_hdr.size = KDBUS_ITEM_HEADER_SIZE + name_len; - - kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &size); - kdbus_kvec_set(&kvec[cnt++], &item_hdr, sizeof(item_hdr), &size); - kdbus_kvec_set(&kvec[cnt++], bus->node.name, name_len, &size); - cnt += !!kdbus_kvec_pad(&kvec[cnt], &size); - if (meta_size > 0) { - kdbus_kvec_set(&kvec[cnt++], meta_items, meta_size, &size); - cnt += !!kdbus_kvec_pad(&kvec[cnt], &size); - } - - info.size = size; - - slice = kdbus_pool_slice_alloc(conn->pool, size, false); - if (IS_ERR(slice)) { - ret = PTR_ERR(slice); - slice = NULL; - goto exit; - } - - ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, size); - if (ret < 0) - goto exit; - - kdbus_pool_slice_publish(slice, &cmd->offset, &cmd->info_size); - - if (kdbus_member_set_user(&cmd->offset, argp, typeof(*cmd), offset) || - kdbus_member_set_user(&cmd->info_size, argp, - typeof(*cmd), info_size)) - ret = -EFAULT; - -exit: - kdbus_pool_slice_release(slice); - kfree(meta_items); - return kdbus_args_clear(&args, ret); -} diff --git a/ipc/kdbus/bus.h b/ipc/kdbus/bus.h deleted file mode 100644 index 8c2acaed6..000000000 --- a/ipc/kdbus/bus.h +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_BUS_H -#define __KDBUS_BUS_H - -#include <linux/hashtable.h> -#include <linux/list.h> -#include <linux/mutex.h> -#include <linux/rwsem.h> -#include <linux/spinlock.h> -#include <uapi/linux/kdbus.h> - -#include "metadata.h" -#include "names.h" -#include "node.h" -#include "policy.h" - -struct kdbus_conn; -struct kdbus_domain; -struct kdbus_staging; -struct kdbus_user; - -/** - * struct kdbus_bus - bus in a domain - * @node: kdbus_node - * @id: ID of this bus in the domain - * @bus_flags: Simple pass-through flags from userspace to userspace - * @attach_flags_owner: KDBUS_ATTACH_* flags of bus creator that other - * connections can see or query - * @id128: Unique random 128 bit ID of this bus - * @bloom: Bloom parameters - * @domain: Domain of this bus - * @creator: Creator of the bus - * @creator_meta: Meta information about the bus creator - * @last_message_id: Last used message id - * @policy_db: Policy database for this bus - * @name_registry: Name registry of this bus - * @conn_rwlock: Read/Write lock for all lists of child connections - * @conn_hash: Map of connection IDs - * @monitors_list: Connections that monitor this bus - * @notify_list: List of pending kernel-generated messages - * @notify_lock: Notification list lock - * @notify_flush_lock: Notification flushing lock - */ -struct kdbus_bus { - struct kdbus_node node; - - /* static */ - u64 id; - u64 bus_flags; - u64 attach_flags_owner; - u8 id128[16]; - struct kdbus_bloom_parameter bloom; - struct kdbus_domain *domain; - struct kdbus_user *creator; - struct kdbus_meta_proc *creator_meta; - - /* protected by own locks */ - atomic64_t last_message_id; - struct kdbus_policy_db policy_db; - struct kdbus_name_registry *name_registry; - - /* protected by conn_rwlock */ - struct rw_semaphore conn_rwlock; - DECLARE_HASHTABLE(conn_hash, 8); - struct list_head monitors_list; - - /* protected by notify_lock */ - struct list_head notify_list; - spinlock_t notify_lock; - struct mutex notify_flush_lock; -}; - -struct kdbus_bus *kdbus_bus_ref(struct kdbus_bus *bus); -struct kdbus_bus *kdbus_bus_unref(struct kdbus_bus *bus); - -struct kdbus_conn *kdbus_bus_find_conn_by_id(struct kdbus_bus *bus, u64 id); -void kdbus_bus_broadcast(struct kdbus_bus *bus, - struct kdbus_conn *conn_src, - struct kdbus_staging *staging); -void kdbus_bus_eavesdrop(struct kdbus_bus *bus, - struct kdbus_conn *conn_src, - struct kdbus_staging *staging); - -struct kdbus_bus *kdbus_cmd_bus_make(struct kdbus_domain *domain, - void __user *argp); -int kdbus_cmd_bus_creator_info(struct kdbus_conn *conn, void __user *argp); - -#endif diff --git a/ipc/kdbus/connection.c b/ipc/kdbus/connection.c deleted file mode 100644 index ef63d6533..000000000 --- a/ipc/kdbus/connection.c +++ /dev/null @@ -1,2227 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/audit.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/fs_struct.h> -#include <linux/hashtable.h> -#include <linux/idr.h> -#include <linux/init.h> -#include <linux/math64.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/path.h> -#include <linux/poll.h> -#include <linux/sched.h> -#include <linux/shmem_fs.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/syscalls.h> -#include <linux/uio.h> - -#include "bus.h" -#include "connection.h" -#include "endpoint.h" -#include "handle.h" -#include "match.h" -#include "message.h" -#include "metadata.h" -#include "names.h" -#include "domain.h" -#include "item.h" -#include "notify.h" -#include "policy.h" -#include "pool.h" -#include "reply.h" -#include "util.h" -#include "queue.h" - -#define KDBUS_CONN_ACTIVE_BIAS (INT_MIN + 2) -#define KDBUS_CONN_ACTIVE_NEW (INT_MIN + 1) - -static struct kdbus_conn *kdbus_conn_new(struct kdbus_ep *ep, - struct file *file, - struct kdbus_cmd_hello *hello, - const char *name, - const struct kdbus_creds *creds, - const struct kdbus_pids *pids, - const char *seclabel, - const char *conn_description) -{ -#ifdef CONFIG_DEBUG_LOCK_ALLOC - static struct lock_class_key __key; -#endif - struct kdbus_pool_slice *slice = NULL; - struct kdbus_bus *bus = ep->bus; - struct kdbus_conn *conn; - u64 attach_flags_send; - u64 attach_flags_recv; - u64 items_size = 0; - bool is_policy_holder; - bool is_activator; - bool is_monitor; - bool privileged; - bool owner; - struct kvec kvec; - int ret; - - struct { - u64 size; - u64 type; - struct kdbus_bloom_parameter bloom; - } bloom_item; - - privileged = kdbus_ep_is_privileged(ep, file); - owner = kdbus_ep_is_owner(ep, file); - - is_monitor = hello->flags & KDBUS_HELLO_MONITOR; - is_activator = hello->flags & KDBUS_HELLO_ACTIVATOR; - is_policy_holder = hello->flags & KDBUS_HELLO_POLICY_HOLDER; - - if (!hello->pool_size || !IS_ALIGNED(hello->pool_size, PAGE_SIZE)) - return ERR_PTR(-EINVAL); - if (is_monitor + is_activator + is_policy_holder > 1) - return ERR_PTR(-EINVAL); - if (name && !is_activator && !is_policy_holder) - return ERR_PTR(-EINVAL); - if (!name && (is_activator || is_policy_holder)) - return ERR_PTR(-EINVAL); - if (name && !kdbus_name_is_valid(name, true)) - return ERR_PTR(-EINVAL); - if (is_monitor && ep->user) - return ERR_PTR(-EOPNOTSUPP); - if (!owner && (is_activator || is_policy_holder || is_monitor)) - return ERR_PTR(-EPERM); - if (!owner && (creds || pids || seclabel)) - return ERR_PTR(-EPERM); - - ret = kdbus_sanitize_attach_flags(hello->attach_flags_send, - &attach_flags_send); - if (ret < 0) - return ERR_PTR(ret); - - ret = kdbus_sanitize_attach_flags(hello->attach_flags_recv, - &attach_flags_recv); - if (ret < 0) - return ERR_PTR(ret); - - conn = kzalloc(sizeof(*conn), GFP_KERNEL); - if (!conn) - return ERR_PTR(-ENOMEM); - - kref_init(&conn->kref); - atomic_set(&conn->active, KDBUS_CONN_ACTIVE_NEW); -#ifdef CONFIG_DEBUG_LOCK_ALLOC - lockdep_init_map(&conn->dep_map, "s_active", &__key, 0); -#endif - mutex_init(&conn->lock); - INIT_LIST_HEAD(&conn->names_list); - INIT_LIST_HEAD(&conn->reply_list); - atomic_set(&conn->request_count, 0); - atomic_set(&conn->lost_count, 0); - INIT_DELAYED_WORK(&conn->work, kdbus_reply_list_scan_work); - conn->cred = get_cred(file->f_cred); - conn->pid = get_pid(task_pid(current)); - get_fs_root(current->fs, &conn->root_path); - init_waitqueue_head(&conn->wait); - kdbus_queue_init(&conn->queue); - conn->privileged = privileged; - conn->owner = owner; - conn->ep = kdbus_ep_ref(ep); - conn->id = atomic64_inc_return(&bus->domain->last_id); - conn->flags = hello->flags; - atomic64_set(&conn->attach_flags_send, attach_flags_send); - atomic64_set(&conn->attach_flags_recv, attach_flags_recv); - INIT_LIST_HEAD(&conn->monitor_entry); - - if (conn_description) { - conn->description = kstrdup(conn_description, GFP_KERNEL); - if (!conn->description) { - ret = -ENOMEM; - goto exit_unref; - } - } - - conn->pool = kdbus_pool_new(conn->description, hello->pool_size); - if (IS_ERR(conn->pool)) { - ret = PTR_ERR(conn->pool); - conn->pool = NULL; - goto exit_unref; - } - - conn->match_db = kdbus_match_db_new(); - if (IS_ERR(conn->match_db)) { - ret = PTR_ERR(conn->match_db); - conn->match_db = NULL; - goto exit_unref; - } - - /* return properties of this connection to the caller */ - hello->bus_flags = bus->bus_flags; - hello->id = conn->id; - - BUILD_BUG_ON(sizeof(bus->id128) != sizeof(hello->id128)); - memcpy(hello->id128, bus->id128, sizeof(hello->id128)); - - /* privileged processes can impersonate somebody else */ - if (creds || pids || seclabel) { - conn->meta_fake = kdbus_meta_fake_new(); - if (IS_ERR(conn->meta_fake)) { - ret = PTR_ERR(conn->meta_fake); - conn->meta_fake = NULL; - goto exit_unref; - } - - ret = kdbus_meta_fake_collect(conn->meta_fake, - creds, pids, seclabel); - if (ret < 0) - goto exit_unref; - } else { - conn->meta_proc = kdbus_meta_proc_new(); - if (IS_ERR(conn->meta_proc)) { - ret = PTR_ERR(conn->meta_proc); - conn->meta_proc = NULL; - goto exit_unref; - } - - ret = kdbus_meta_proc_collect(conn->meta_proc, - KDBUS_ATTACH_CREDS | - KDBUS_ATTACH_PIDS | - KDBUS_ATTACH_AUXGROUPS | - KDBUS_ATTACH_TID_COMM | - KDBUS_ATTACH_PID_COMM | - KDBUS_ATTACH_EXE | - KDBUS_ATTACH_CMDLINE | - KDBUS_ATTACH_CGROUP | - KDBUS_ATTACH_CAPS | - KDBUS_ATTACH_SECLABEL | - KDBUS_ATTACH_AUDIT); - if (ret < 0) - goto exit_unref; - } - - /* - * Account the connection against the current user (UID), or for - * custom endpoints use the anonymous user assigned to the endpoint. - * Note that limits are always accounted against the real UID, not - * the effective UID (cred->user always points to the accounting of - * cred->uid, not cred->euid). - * In case the caller is privileged, we allow changing the accounting - * to the faked user. - */ - if (ep->user) { - conn->user = kdbus_user_ref(ep->user); - } else { - kuid_t uid; - - if (conn->meta_fake && uid_valid(conn->meta_fake->uid) && - conn->privileged) - uid = conn->meta_fake->uid; - else - uid = conn->cred->uid; - - conn->user = kdbus_user_lookup(ep->bus->domain, uid); - if (IS_ERR(conn->user)) { - ret = PTR_ERR(conn->user); - conn->user = NULL; - goto exit_unref; - } - } - - if (atomic_inc_return(&conn->user->connections) > KDBUS_USER_MAX_CONN) { - /* decremented by destructor as conn->user is valid */ - ret = -EMFILE; - goto exit_unref; - } - - bloom_item.size = sizeof(bloom_item); - bloom_item.type = KDBUS_ITEM_BLOOM_PARAMETER; - bloom_item.bloom = bus->bloom; - kdbus_kvec_set(&kvec, &bloom_item, bloom_item.size, &items_size); - - slice = kdbus_pool_slice_alloc(conn->pool, items_size, false); - if (IS_ERR(slice)) { - ret = PTR_ERR(slice); - slice = NULL; - goto exit_unref; - } - - ret = kdbus_pool_slice_copy_kvec(slice, 0, &kvec, 1, items_size); - if (ret < 0) - goto exit_unref; - - kdbus_pool_slice_publish(slice, &hello->offset, &hello->items_size); - kdbus_pool_slice_release(slice); - - return conn; - -exit_unref: - kdbus_pool_slice_release(slice); - kdbus_conn_unref(conn); - return ERR_PTR(ret); -} - -static void __kdbus_conn_free(struct kref *kref) -{ - struct kdbus_conn *conn = container_of(kref, struct kdbus_conn, kref); - - WARN_ON(kdbus_conn_active(conn)); - WARN_ON(delayed_work_pending(&conn->work)); - WARN_ON(!list_empty(&conn->queue.msg_list)); - WARN_ON(!list_empty(&conn->names_list)); - WARN_ON(!list_empty(&conn->reply_list)); - - if (conn->user) { - atomic_dec(&conn->user->connections); - kdbus_user_unref(conn->user); - } - - kdbus_meta_fake_free(conn->meta_fake); - kdbus_meta_proc_unref(conn->meta_proc); - kdbus_match_db_free(conn->match_db); - kdbus_pool_free(conn->pool); - kdbus_ep_unref(conn->ep); - path_put(&conn->root_path); - put_pid(conn->pid); - put_cred(conn->cred); - kfree(conn->description); - kfree(conn->quota); - kfree(conn); -} - -/** - * kdbus_conn_ref() - take a connection reference - * @conn: Connection, may be %NULL - * - * Return: the connection itself - */ -struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn) -{ - if (conn) - kref_get(&conn->kref); - return conn; -} - -/** - * kdbus_conn_unref() - drop a connection reference - * @conn: Connection (may be NULL) - * - * When the last reference is dropped, the connection's internal structure - * is freed. - * - * Return: NULL - */ -struct kdbus_conn *kdbus_conn_unref(struct kdbus_conn *conn) -{ - if (conn) - kref_put(&conn->kref, __kdbus_conn_free); - return NULL; -} - -/** - * kdbus_conn_active() - connection is not disconnected - * @conn: Connection to check - * - * Return true if the connection was not disconnected, yet. Note that a - * connection might be disconnected asynchronously, unless you hold the - * connection lock. If that's not suitable for you, see kdbus_conn_acquire() to - * suppress connection shutdown for a short period. - * - * Return: true if the connection is still active - */ -bool kdbus_conn_active(const struct kdbus_conn *conn) -{ - return atomic_read(&conn->active) >= 0; -} - -/** - * kdbus_conn_acquire() - acquire an active connection reference - * @conn: Connection - * - * Users can close a connection via KDBUS_BYEBYE (or by destroying the - * endpoint/bus/...) at any time. Whenever this happens, we should deny any - * user-visible action on this connection and signal ECONNRESET instead. - * To avoid testing for connection availability everytime you take the - * connection-lock, you can acquire a connection for short periods. - * - * By calling kdbus_conn_acquire(), you gain an "active reference" to the - * connection. You must also hold a regular reference at any time! As long as - * you hold the active-ref, the connection will not be shut down. However, if - * the connection was shut down, you can never acquire an active-ref again. - * - * kdbus_conn_disconnect() disables the connection and then waits for all active - * references to be dropped. It will also wake up any pending operation. - * However, you must not sleep for an indefinite period while holding an - * active-reference. Otherwise, kdbus_conn_disconnect() might stall. If you need - * to sleep for an indefinite period, either release the reference and try to - * acquire it again after waking up, or make kdbus_conn_disconnect() wake up - * your wait-queue. - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_conn_acquire(struct kdbus_conn *conn) -{ - if (!atomic_inc_unless_negative(&conn->active)) - return -ECONNRESET; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - rwsem_acquire_read(&conn->dep_map, 0, 1, _RET_IP_); -#endif - - return 0; -} - -/** - * kdbus_conn_release() - release an active connection reference - * @conn: Connection - * - * This releases an active reference that has been acquired via - * kdbus_conn_acquire(). If the connection was already disabled and this is the - * last active-ref that is dropped, the disconnect-waiter will be woken up and - * properly close the connection. - */ -void kdbus_conn_release(struct kdbus_conn *conn) -{ - int v; - - if (!conn) - return; - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - rwsem_release(&conn->dep_map, 1, _RET_IP_); -#endif - - v = atomic_dec_return(&conn->active); - if (v != KDBUS_CONN_ACTIVE_BIAS) - return; - - wake_up_all(&conn->wait); -} - -static int kdbus_conn_connect(struct kdbus_conn *conn, const char *name) -{ - struct kdbus_ep *ep = conn->ep; - struct kdbus_bus *bus = ep->bus; - int ret; - - if (WARN_ON(atomic_read(&conn->active) != KDBUS_CONN_ACTIVE_NEW)) - return -EALREADY; - - /* make sure the ep-node is active while we add our connection */ - if (!kdbus_node_acquire(&ep->node)) - return -ESHUTDOWN; - - /* lock order: domain -> bus -> ep -> names -> conn */ - mutex_lock(&ep->lock); - down_write(&bus->conn_rwlock); - - /* link into monitor list */ - if (kdbus_conn_is_monitor(conn)) - list_add_tail(&conn->monitor_entry, &bus->monitors_list); - - /* link into bus and endpoint */ - list_add_tail(&conn->ep_entry, &ep->conn_list); - hash_add(bus->conn_hash, &conn->hentry, conn->id); - - /* enable lookups and acquire active ref */ - atomic_set(&conn->active, 1); -#ifdef CONFIG_DEBUG_LOCK_ALLOC - rwsem_acquire_read(&conn->dep_map, 0, 1, _RET_IP_); -#endif - - up_write(&bus->conn_rwlock); - mutex_unlock(&ep->lock); - - kdbus_node_release(&ep->node); - - /* - * Notify subscribers about the new active connection, unless it is - * a monitor. Monitors are invisible on the bus, can't be addressed - * directly, and won't cause any notifications. - */ - if (!kdbus_conn_is_monitor(conn)) { - ret = kdbus_notify_id_change(bus, KDBUS_ITEM_ID_ADD, - conn->id, conn->flags); - if (ret < 0) - goto exit_disconnect; - } - - if (kdbus_conn_is_activator(conn)) { - u64 flags = KDBUS_NAME_ACTIVATOR; - - if (WARN_ON(!name)) { - ret = -EINVAL; - goto exit_disconnect; - } - - ret = kdbus_name_acquire(bus->name_registry, conn, name, - flags, NULL); - if (ret < 0) - goto exit_disconnect; - } - - kdbus_conn_release(conn); - kdbus_notify_flush(bus); - return 0; - -exit_disconnect: - kdbus_conn_release(conn); - kdbus_conn_disconnect(conn, false); - return ret; -} - -/** - * kdbus_conn_disconnect() - disconnect a connection - * @conn: The connection to disconnect - * @ensure_queue_empty: Flag to indicate if the call should fail in - * case the connection's message list is not - * empty - * - * If @ensure_msg_list_empty is true, and the connection has pending messages, - * -EBUSY is returned. - * - * Return: 0 on success, negative errno on failure - */ -int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty) -{ - struct kdbus_queue_entry *entry, *tmp; - struct kdbus_bus *bus = conn->ep->bus; - struct kdbus_reply *r, *r_tmp; - struct kdbus_conn *c; - int i, v; - - mutex_lock(&conn->lock); - v = atomic_read(&conn->active); - if (v == KDBUS_CONN_ACTIVE_NEW) { - /* was never connected */ - mutex_unlock(&conn->lock); - return 0; - } - if (v < 0) { - /* already dead */ - mutex_unlock(&conn->lock); - return -ECONNRESET; - } - if (ensure_queue_empty && !list_empty(&conn->queue.msg_list)) { - /* still busy */ - mutex_unlock(&conn->lock); - return -EBUSY; - } - - atomic_add(KDBUS_CONN_ACTIVE_BIAS, &conn->active); - mutex_unlock(&conn->lock); - - wake_up_interruptible(&conn->wait); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - rwsem_acquire(&conn->dep_map, 0, 0, _RET_IP_); - if (atomic_read(&conn->active) != KDBUS_CONN_ACTIVE_BIAS) - lock_contended(&conn->dep_map, _RET_IP_); -#endif - - wait_event(conn->wait, - atomic_read(&conn->active) == KDBUS_CONN_ACTIVE_BIAS); - -#ifdef CONFIG_DEBUG_LOCK_ALLOC - lock_acquired(&conn->dep_map, _RET_IP_); - rwsem_release(&conn->dep_map, 1, _RET_IP_); -#endif - - cancel_delayed_work_sync(&conn->work); - kdbus_policy_remove_owner(&conn->ep->bus->policy_db, conn); - - /* lock order: domain -> bus -> ep -> names -> conn */ - mutex_lock(&conn->ep->lock); - down_write(&bus->conn_rwlock); - - /* remove from bus and endpoint */ - hash_del(&conn->hentry); - list_del(&conn->monitor_entry); - list_del(&conn->ep_entry); - - up_write(&bus->conn_rwlock); - mutex_unlock(&conn->ep->lock); - - /* - * Remove all names associated with this connection; this possibly - * moves queued messages back to the activator connection. - */ - kdbus_name_release_all(bus->name_registry, conn); - - /* if we die while other connections wait for our reply, notify them */ - mutex_lock(&conn->lock); - list_for_each_entry_safe(entry, tmp, &conn->queue.msg_list, entry) { - if (entry->reply) - kdbus_notify_reply_dead(bus, - entry->reply->reply_dst->id, - entry->reply->cookie); - kdbus_queue_entry_free(entry); - } - - list_for_each_entry_safe(r, r_tmp, &conn->reply_list, entry) - kdbus_reply_unlink(r); - mutex_unlock(&conn->lock); - - /* lock order: domain -> bus -> ep -> names -> conn */ - down_read(&bus->conn_rwlock); - hash_for_each(bus->conn_hash, i, c, hentry) { - mutex_lock(&c->lock); - list_for_each_entry_safe(r, r_tmp, &c->reply_list, entry) { - if (r->reply_src != conn) - continue; - - if (r->sync) - kdbus_sync_reply_wakeup(r, -EPIPE); - else - /* send a 'connection dead' notification */ - kdbus_notify_reply_dead(bus, c->id, r->cookie); - - kdbus_reply_unlink(r); - } - mutex_unlock(&c->lock); - } - up_read(&bus->conn_rwlock); - - if (!kdbus_conn_is_monitor(conn)) - kdbus_notify_id_change(bus, KDBUS_ITEM_ID_REMOVE, - conn->id, conn->flags); - - kdbus_notify_flush(bus); - - return 0; -} - -/** - * kdbus_conn_has_name() - check if a connection owns a name - * @conn: Connection - * @name: Well-know name to check for - * - * The caller must hold the registry lock of conn->ep->bus. - * - * Return: true if the name is currently owned by the connection - */ -bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name) -{ - struct kdbus_name_owner *owner; - - lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); - - list_for_each_entry(owner, &conn->names_list, conn_entry) - if (!(owner->flags & KDBUS_NAME_IN_QUEUE) && - !strcmp(name, owner->name->name)) - return true; - - return false; -} - -struct kdbus_quota { - u32 memory; - u16 msgs; - u8 fds; -}; - -/** - * kdbus_conn_quota_inc() - increase quota accounting - * @c: connection owning the quota tracking - * @u: user to account for (or NULL for kernel accounting) - * @memory: size of memory to account for - * @fds: number of FDs to account for - * - * This call manages the quotas on resource @c. That is, it's used if other - * users want to use the resources of connection @c, which so far only concerns - * the receive queue of the destination. - * - * This increases the quota-accounting for user @u by @memory bytes and @fds - * file descriptors. If the user has already reached the quota limits, this call - * will not do any accounting but return a negative error code indicating the - * failure. - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u, - size_t memory, size_t fds) -{ - struct kdbus_quota *quota; - size_t available, accounted; - unsigned int id; - - /* - * Pool Layout: - * 50% of a pool is always owned by the connection. It is reserved for - * kernel queries, handling received messages and other tasks that are - * under control of the pool owner. The other 50% of the pool are used - * as incoming queue. - * As we optionally support user-space based policies, we need fair - * allocation schemes. Furthermore, resource utilization should be - * maximized, so only minimal resources stay reserved. However, we need - * to adapt to a dynamic number of users, as we cannot know how many - * users will talk to a connection. Therefore, the current allocation - * works like this: - * We limit the number of bytes in a destination's pool per sending - * user. The space available for a user is 33% of the unused pool space - * (whereas the space used by the user itself is also treated as - * 'unused'). This way, we favor users coming first, but keep enough - * pool space available for any following users. Given that messages are - * dequeued in FIFO order, this should balance nicely if the number of - * users grows. At the same time, this algorithm guarantees that the - * space available to a connection is reduced dynamically, the more - * concurrent users talk to a connection. - */ - - /* per user-accounting is expensive, so we keep state small */ - BUILD_BUG_ON(sizeof(quota->memory) != 4); - BUILD_BUG_ON(sizeof(quota->msgs) != 2); - BUILD_BUG_ON(sizeof(quota->fds) != 1); - BUILD_BUG_ON(KDBUS_CONN_MAX_MSGS > U16_MAX); - BUILD_BUG_ON(KDBUS_CONN_MAX_FDS_PER_USER > U8_MAX); - - id = u ? u->id : KDBUS_USER_KERNEL_ID; - if (id >= c->n_quota) { - unsigned int users; - - users = max(KDBUS_ALIGN8(id) + 8, id); - quota = krealloc(c->quota, users * sizeof(*quota), - GFP_KERNEL | __GFP_ZERO); - if (!quota) - return -ENOMEM; - - c->n_quota = users; - c->quota = quota; - } - - quota = &c->quota[id]; - kdbus_pool_accounted(c->pool, &available, &accounted); - - /* half the pool is _always_ reserved for the pool owner */ - available /= 2; - - /* - * Pool owner slices are un-accounted slices; they can claim more - * than 50% of the queue. However, the slices we're dealing with here - * belong to the incoming queue, hence they are 'accounted' slices - * to which the 50%-limit applies. - */ - if (available < accounted) - return -ENOBUFS; - - /* 1/3 of the remaining space (including your own memory) */ - available = (available - accounted + quota->memory) / 3; - - if (available < quota->memory || - available - quota->memory < memory || - quota->memory + memory > U32_MAX) - return -ENOBUFS; - if (quota->msgs >= KDBUS_CONN_MAX_MSGS) - return -ENOBUFS; - if (quota->fds + fds < quota->fds || - quota->fds + fds > KDBUS_CONN_MAX_FDS_PER_USER) - return -EMFILE; - - quota->memory += memory; - quota->fds += fds; - ++quota->msgs; - return 0; -} - -/** - * kdbus_conn_quota_dec() - decrease quota accounting - * @c: connection owning the quota tracking - * @u: user which was accounted for (or NULL for kernel accounting) - * @memory: size of memory which was accounted for - * @fds: number of FDs which were accounted for - * - * This does the reverse of kdbus_conn_quota_inc(). You have to release any - * accounted resources that you called kdbus_conn_quota_inc() for. However, you - * must not call kdbus_conn_quota_dec() if the accounting failed (that is, - * kdbus_conn_quota_inc() failed). - */ -void kdbus_conn_quota_dec(struct kdbus_conn *c, struct kdbus_user *u, - size_t memory, size_t fds) -{ - struct kdbus_quota *quota; - unsigned int id; - - id = u ? u->id : KDBUS_USER_KERNEL_ID; - if (WARN_ON(id >= c->n_quota)) - return; - - quota = &c->quota[id]; - - if (!WARN_ON(quota->msgs == 0)) - --quota->msgs; - if (!WARN_ON(quota->memory < memory)) - quota->memory -= memory; - if (!WARN_ON(quota->fds < fds)) - quota->fds -= fds; -} - -/** - * kdbus_conn_lost_message() - handle lost messages - * @c: connection that lost a message - * - * kdbus is reliable. That means, we try hard to never lose messages. However, - * memory is limited, so we cannot rely on transmissions to never fail. - * Therefore, we use quota-limits to let callers know if their unicast message - * cannot be transmitted to a peer. This works fine for unicasts, but for - * broadcasts we cannot make the caller handle the transmission failure. - * Instead, we must let the destination know that it couldn't receive a - * broadcast. - * As this is an unlikely scenario, we keep it simple. A single lost-counter - * remembers the number of lost messages since the last call to RECV. The next - * message retrieval will notify the connection that it lost messages since the - * last message retrieval and thus should resync its state. - */ -void kdbus_conn_lost_message(struct kdbus_conn *c) -{ - if (atomic_inc_return(&c->lost_count) == 1) - wake_up_interruptible(&c->wait); -} - -/* Callers should take the conn_dst lock */ -static struct kdbus_queue_entry * -kdbus_conn_entry_make(struct kdbus_conn *conn_src, - struct kdbus_conn *conn_dst, - struct kdbus_staging *staging) -{ - /* The remote connection was disconnected */ - if (!kdbus_conn_active(conn_dst)) - return ERR_PTR(-ECONNRESET); - - /* - * If the connection does not accept file descriptors but the message - * has some attached, refuse it. - * - * If this is a monitor connection, accept the message. In that - * case, all file descriptors will be set to -1 at receive time. - */ - if (!kdbus_conn_is_monitor(conn_dst) && - !(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) && - staging->gaps && staging->gaps->n_fds > 0) - return ERR_PTR(-ECOMM); - - return kdbus_queue_entry_new(conn_src, conn_dst, staging); -} - -/* - * Synchronously responding to a message, allocate a queue entry - * and attach it to the reply tracking object. - * The connection's queue will never get to see it. - */ -static int kdbus_conn_entry_sync_attach(struct kdbus_conn *conn_dst, - struct kdbus_staging *staging, - struct kdbus_reply *reply_wake) -{ - struct kdbus_queue_entry *entry; - int remote_ret, ret = 0; - - mutex_lock(&reply_wake->reply_dst->lock); - - /* - * If we are still waiting then proceed, allocate a queue - * entry and attach it to the reply object - */ - if (reply_wake->waiting) { - entry = kdbus_conn_entry_make(reply_wake->reply_src, conn_dst, - staging); - if (IS_ERR(entry)) - ret = PTR_ERR(entry); - else - /* Attach the entry to the reply object */ - reply_wake->queue_entry = entry; - } else { - ret = -ECONNRESET; - } - - /* - * Update the reply object and wake up remote peer only - * on appropriate return codes - * - * * -ECOMM: if the replying connection failed with -ECOMM - * then wakeup remote peer with -EREMOTEIO - * - * We do this to differenciate between -ECOMM errors - * from the original sender perspective: - * -ECOMM error during the sync send and - * -ECOMM error during the sync reply, this last - * one is rewritten to -EREMOTEIO - * - * * Wake up on all other return codes. - */ - remote_ret = ret; - - if (ret == -ECOMM) - remote_ret = -EREMOTEIO; - - kdbus_sync_reply_wakeup(reply_wake, remote_ret); - kdbus_reply_unlink(reply_wake); - mutex_unlock(&reply_wake->reply_dst->lock); - - return ret; -} - -/** - * kdbus_conn_entry_insert() - enqueue a message into the receiver's pool - * @conn_src: The sending connection - * @conn_dst: The connection to queue into - * @staging: Message to send - * @reply: The reply tracker to attach to the queue entry - * @name: Destination name this msg is sent to, or NULL - * - * Return: 0 on success. negative error otherwise. - */ -int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, - struct kdbus_conn *conn_dst, - struct kdbus_staging *staging, - struct kdbus_reply *reply, - const struct kdbus_name_entry *name) -{ - struct kdbus_queue_entry *entry; - int ret; - - kdbus_conn_lock2(conn_src, conn_dst); - - entry = kdbus_conn_entry_make(conn_src, conn_dst, staging); - if (IS_ERR(entry)) { - ret = PTR_ERR(entry); - goto exit_unlock; - } - - if (reply) { - kdbus_reply_link(reply); - if (!reply->sync) - schedule_delayed_work(&conn_src->work, 0); - } - - /* - * Record the sequence number of the registered name; it will - * be remembered by the queue, in case messages addressed to a - * name need to be moved from or to an activator. - */ - if (name) - entry->dst_name_id = name->name_id; - - kdbus_queue_entry_enqueue(entry, reply); - wake_up_interruptible(&conn_dst->wait); - - ret = 0; - -exit_unlock: - kdbus_conn_unlock2(conn_src, conn_dst); - return ret; -} - -static int kdbus_conn_wait_reply(struct kdbus_conn *conn_src, - struct kdbus_cmd_send *cmd_send, - struct file *ioctl_file, - struct file *cancel_fd, - struct kdbus_reply *reply_wait, - ktime_t expire) -{ - struct kdbus_queue_entry *entry; - struct poll_wqueues pwq = {}; - int ret; - - if (WARN_ON(!reply_wait)) - return -EIO; - - /* - * Block until the reply arrives. reply_wait is left untouched - * by the timeout scans that might be conducted for other, - * asynchronous replies of conn_src. - */ - - poll_initwait(&pwq); - poll_wait(ioctl_file, &conn_src->wait, &pwq.pt); - - for (;;) { - /* - * Any of the following conditions will stop our synchronously - * blocking SEND command: - * - * a) The origin sender closed its connection - * b) The remote peer answered, setting reply_wait->waiting = 0 - * c) The cancel FD was written to - * d) A signal was received - * e) The specified timeout was reached, and none of the above - * conditions kicked in. - */ - - /* - * We have already acquired an active reference when - * entering here, but another thread may call - * KDBUS_CMD_BYEBYE which does not acquire an active - * reference, therefore kdbus_conn_disconnect() will - * not wait for us. - */ - if (!kdbus_conn_active(conn_src)) { - ret = -ECONNRESET; - break; - } - - /* - * After the replying peer unset the waiting variable - * it will wake up us. - */ - if (!reply_wait->waiting) { - ret = reply_wait->err; - break; - } - - if (cancel_fd) { - unsigned int r; - - r = cancel_fd->f_op->poll(cancel_fd, &pwq.pt); - if (r & POLLIN) { - ret = -ECANCELED; - break; - } - } - - if (signal_pending(current)) { - ret = -EINTR; - break; - } - - if (!poll_schedule_timeout(&pwq, TASK_INTERRUPTIBLE, - &expire, 0)) { - ret = -ETIMEDOUT; - break; - } - - /* - * Reset the poll worker func, so the waitqueues are not - * added to the poll table again. We just reuse what we've - * collected earlier for further iterations. - */ - init_poll_funcptr(&pwq.pt, NULL); - } - - poll_freewait(&pwq); - - if (ret == -EINTR) { - /* - * Interrupted system call. Unref the reply object, and pass - * the return value down the chain. Mark the reply as - * interrupted, so the cleanup work can remove it, but do not - * unlink it from the list. Once the syscall restarts, we'll - * pick it up and wait on it again. - */ - mutex_lock(&conn_src->lock); - reply_wait->interrupted = true; - schedule_delayed_work(&conn_src->work, 0); - mutex_unlock(&conn_src->lock); - - return -ERESTARTSYS; - } - - mutex_lock(&conn_src->lock); - reply_wait->waiting = false; - entry = reply_wait->queue_entry; - if (entry) { - ret = kdbus_queue_entry_install(entry, - &cmd_send->reply.return_flags, - true); - kdbus_pool_slice_publish(entry->slice, &cmd_send->reply.offset, - &cmd_send->reply.msg_size); - kdbus_queue_entry_free(entry); - } - kdbus_reply_unlink(reply_wait); - mutex_unlock(&conn_src->lock); - - return ret; -} - -static int kdbus_pin_dst(struct kdbus_bus *bus, - struct kdbus_staging *staging, - struct kdbus_name_entry **out_name, - struct kdbus_conn **out_dst) -{ - const struct kdbus_msg *msg = staging->msg; - struct kdbus_name_owner *owner = NULL; - struct kdbus_name_entry *name = NULL; - struct kdbus_conn *dst = NULL; - int ret; - - lockdep_assert_held(&bus->name_registry->rwlock); - - if (!staging->dst_name) { - dst = kdbus_bus_find_conn_by_id(bus, msg->dst_id); - if (!dst) - return -ENXIO; - - if (!kdbus_conn_is_ordinary(dst)) { - ret = -ENXIO; - goto error; - } - } else { - name = kdbus_name_lookup_unlocked(bus->name_registry, - staging->dst_name); - if (name) - owner = kdbus_name_get_owner(name); - if (!owner) - return -ESRCH; - - /* - * If both a name and a connection ID are given as destination - * of a message, check that the currently owning connection of - * the name matches the specified ID. - * This way, we allow userspace to send the message to a - * specific connection by ID only if the connection currently - * owns the given name. - */ - if (msg->dst_id != KDBUS_DST_ID_NAME && - msg->dst_id != owner->conn->id) - return -EREMCHG; - - if ((msg->flags & KDBUS_MSG_NO_AUTO_START) && - kdbus_conn_is_activator(owner->conn)) - return -EADDRNOTAVAIL; - - dst = kdbus_conn_ref(owner->conn); - } - - *out_name = name; - *out_dst = dst; - return 0; - -error: - kdbus_conn_unref(dst); - return ret; -} - -static int kdbus_conn_reply(struct kdbus_conn *src, - struct kdbus_staging *staging) -{ - const struct kdbus_msg *msg = staging->msg; - struct kdbus_name_entry *name = NULL; - struct kdbus_reply *reply, *wake = NULL; - struct kdbus_conn *dst = NULL; - struct kdbus_bus *bus = src->ep->bus; - int ret; - - if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) || - WARN_ON(msg->flags & KDBUS_MSG_EXPECT_REPLY) || - WARN_ON(msg->flags & KDBUS_MSG_SIGNAL)) - return -EINVAL; - - /* name-registry must be locked for lookup *and* collecting data */ - down_read(&bus->name_registry->rwlock); - - /* find and pin destination */ - - ret = kdbus_pin_dst(bus, staging, &name, &dst); - if (ret < 0) - goto exit; - - mutex_lock(&dst->lock); - reply = kdbus_reply_find(src, dst, msg->cookie_reply); - if (reply) { - if (reply->sync) - wake = kdbus_reply_ref(reply); - kdbus_reply_unlink(reply); - } - mutex_unlock(&dst->lock); - - if (!reply) { - ret = -EBADSLT; - goto exit; - } - - /* send message */ - - kdbus_bus_eavesdrop(bus, src, staging); - - if (wake) - ret = kdbus_conn_entry_sync_attach(dst, staging, wake); - else - ret = kdbus_conn_entry_insert(src, dst, staging, NULL, name); - -exit: - up_read(&bus->name_registry->rwlock); - kdbus_reply_unref(wake); - kdbus_conn_unref(dst); - return ret; -} - -static struct kdbus_reply *kdbus_conn_call(struct kdbus_conn *src, - struct kdbus_staging *staging, - ktime_t exp) -{ - const struct kdbus_msg *msg = staging->msg; - struct kdbus_name_entry *name = NULL; - struct kdbus_reply *wait = NULL; - struct kdbus_conn *dst = NULL; - struct kdbus_bus *bus = src->ep->bus; - int ret; - - if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) || - WARN_ON(msg->flags & KDBUS_MSG_SIGNAL) || - WARN_ON(!(msg->flags & KDBUS_MSG_EXPECT_REPLY))) - return ERR_PTR(-EINVAL); - - /* resume previous wait-context, if available */ - - mutex_lock(&src->lock); - wait = kdbus_reply_find(NULL, src, msg->cookie); - if (wait) { - if (wait->interrupted) { - kdbus_reply_ref(wait); - wait->interrupted = false; - } else { - wait = NULL; - } - } - mutex_unlock(&src->lock); - - if (wait) - return wait; - - if (ktime_compare(ktime_get(), exp) >= 0) - return ERR_PTR(-ETIMEDOUT); - - /* name-registry must be locked for lookup *and* collecting data */ - down_read(&bus->name_registry->rwlock); - - /* find and pin destination */ - - ret = kdbus_pin_dst(bus, staging, &name, &dst); - if (ret < 0) - goto exit; - - if (!kdbus_conn_policy_talk(src, current_cred(), dst)) { - ret = -EPERM; - goto exit; - } - - wait = kdbus_reply_new(dst, src, msg, name, true); - if (IS_ERR(wait)) { - ret = PTR_ERR(wait); - wait = NULL; - goto exit; - } - - /* send message */ - - kdbus_bus_eavesdrop(bus, src, staging); - - ret = kdbus_conn_entry_insert(src, dst, staging, wait, name); - if (ret < 0) - goto exit; - - ret = 0; - -exit: - up_read(&bus->name_registry->rwlock); - if (ret < 0) { - kdbus_reply_unref(wait); - wait = ERR_PTR(ret); - } - kdbus_conn_unref(dst); - return wait; -} - -static int kdbus_conn_unicast(struct kdbus_conn *src, - struct kdbus_staging *staging) -{ - const struct kdbus_msg *msg = staging->msg; - struct kdbus_name_entry *name = NULL; - struct kdbus_reply *wait = NULL; - struct kdbus_conn *dst = NULL; - struct kdbus_bus *bus = src->ep->bus; - bool is_signal = (msg->flags & KDBUS_MSG_SIGNAL); - int ret = 0; - - if (WARN_ON(msg->dst_id == KDBUS_DST_ID_BROADCAST) || - WARN_ON(!(msg->flags & KDBUS_MSG_EXPECT_REPLY) && - msg->cookie_reply != 0)) - return -EINVAL; - - /* name-registry must be locked for lookup *and* collecting data */ - down_read(&bus->name_registry->rwlock); - - /* find and pin destination */ - - ret = kdbus_pin_dst(bus, staging, &name, &dst); - if (ret < 0) - goto exit; - - if (is_signal) { - /* like broadcasts we eavesdrop even if the msg is dropped */ - kdbus_bus_eavesdrop(bus, src, staging); - - /* drop silently if peer is not interested or not privileged */ - if (!kdbus_match_db_match_msg(dst->match_db, src, staging) || - !kdbus_conn_policy_talk(dst, NULL, src)) - goto exit; - } else if (!kdbus_conn_policy_talk(src, current_cred(), dst)) { - ret = -EPERM; - goto exit; - } else if (msg->flags & KDBUS_MSG_EXPECT_REPLY) { - wait = kdbus_reply_new(dst, src, msg, name, false); - if (IS_ERR(wait)) { - ret = PTR_ERR(wait); - wait = NULL; - goto exit; - } - } - - /* send message */ - - if (!is_signal) - kdbus_bus_eavesdrop(bus, src, staging); - - ret = kdbus_conn_entry_insert(src, dst, staging, wait, name); - if (ret < 0 && !is_signal) - goto exit; - - /* signals are treated like broadcasts, recv-errors are ignored */ - ret = 0; - -exit: - up_read(&bus->name_registry->rwlock); - kdbus_reply_unref(wait); - kdbus_conn_unref(dst); - return ret; -} - -/** - * kdbus_conn_move_messages() - move messages from one connection to another - * @conn_dst: Connection to copy to - * @conn_src: Connection to copy from - * @name_id: Filter for the sequence number of the registered - * name, 0 means no filtering. - * - * Move all messages from one connection to another. This is used when - * an implementer connection is taking over/giving back a well-known name - * from/to an activator connection. - */ -void kdbus_conn_move_messages(struct kdbus_conn *conn_dst, - struct kdbus_conn *conn_src, - u64 name_id) -{ - struct kdbus_queue_entry *e, *e_tmp; - struct kdbus_reply *r, *r_tmp; - struct kdbus_bus *bus; - struct kdbus_conn *c; - LIST_HEAD(msg_list); - int i, ret = 0; - - if (WARN_ON(conn_src == conn_dst)) - return; - - bus = conn_src->ep->bus; - - /* lock order: domain -> bus -> ep -> names -> conn */ - down_read(&bus->conn_rwlock); - hash_for_each(bus->conn_hash, i, c, hentry) { - if (c == conn_src || c == conn_dst) - continue; - - mutex_lock(&c->lock); - list_for_each_entry_safe(r, r_tmp, &c->reply_list, entry) { - if (r->reply_src != conn_src) - continue; - - /* filter messages for a specific name */ - if (name_id > 0 && r->name_id != name_id) - continue; - - kdbus_conn_unref(r->reply_src); - r->reply_src = kdbus_conn_ref(conn_dst); - } - mutex_unlock(&c->lock); - } - up_read(&bus->conn_rwlock); - - kdbus_conn_lock2(conn_src, conn_dst); - list_for_each_entry_safe(e, e_tmp, &conn_src->queue.msg_list, entry) { - /* filter messages for a specific name */ - if (name_id > 0 && e->dst_name_id != name_id) - continue; - - if (!(conn_dst->flags & KDBUS_HELLO_ACCEPT_FD) && - e->gaps && e->gaps->n_fds > 0) { - kdbus_conn_lost_message(conn_dst); - kdbus_queue_entry_free(e); - continue; - } - - ret = kdbus_queue_entry_move(e, conn_dst); - if (ret < 0) { - kdbus_conn_lost_message(conn_dst); - kdbus_queue_entry_free(e); - continue; - } - } - kdbus_conn_unlock2(conn_src, conn_dst); - - /* wake up poll() */ - wake_up_interruptible(&conn_dst->wait); -} - -/* query the policy-database for all names of @whom */ -static bool kdbus_conn_policy_query_all(struct kdbus_conn *conn, - const struct cred *conn_creds, - struct kdbus_policy_db *db, - struct kdbus_conn *whom, - unsigned int access) -{ - struct kdbus_name_owner *owner; - bool pass = false; - int res; - - lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); - - down_read(&db->entries_rwlock); - mutex_lock(&whom->lock); - - list_for_each_entry(owner, &whom->names_list, conn_entry) { - if (owner->flags & KDBUS_NAME_IN_QUEUE) - continue; - - res = kdbus_policy_query_unlocked(db, - conn_creds ? : conn->cred, - owner->name->name, - kdbus_strhash(owner->name->name)); - if (res >= (int)access) { - pass = true; - break; - } - } - - mutex_unlock(&whom->lock); - up_read(&db->entries_rwlock); - - return pass; -} - -/** - * kdbus_conn_policy_own_name() - verify a connection can own the given name - * @conn: Connection - * @conn_creds: Credentials of @conn to use for policy check - * @name: Name - * - * This verifies that @conn is allowed to acquire the well-known name @name. - * - * Return: true if allowed, false if not. - */ -bool kdbus_conn_policy_own_name(struct kdbus_conn *conn, - const struct cred *conn_creds, - const char *name) -{ - unsigned int hash = kdbus_strhash(name); - int res; - - if (!conn_creds) - conn_creds = conn->cred; - - if (conn->ep->user) { - res = kdbus_policy_query(&conn->ep->policy_db, conn_creds, - name, hash); - if (res < KDBUS_POLICY_OWN) - return false; - } - - if (conn->owner) - return true; - - res = kdbus_policy_query(&conn->ep->bus->policy_db, conn_creds, - name, hash); - return res >= KDBUS_POLICY_OWN; -} - -/** - * kdbus_conn_policy_talk() - verify a connection can talk to a given peer - * @conn: Connection that tries to talk - * @conn_creds: Credentials of @conn to use for policy check - * @to: Connection that is talked to - * - * This verifies that @conn is allowed to talk to @to. - * - * Return: true if allowed, false if not. - */ -bool kdbus_conn_policy_talk(struct kdbus_conn *conn, - const struct cred *conn_creds, - struct kdbus_conn *to) -{ - if (!conn_creds) - conn_creds = conn->cred; - - if (conn->ep->user && - !kdbus_conn_policy_query_all(conn, conn_creds, &conn->ep->policy_db, - to, KDBUS_POLICY_TALK)) - return false; - - if (conn->owner) - return true; - if (uid_eq(conn_creds->euid, to->cred->uid)) - return true; - - return kdbus_conn_policy_query_all(conn, conn_creds, - &conn->ep->bus->policy_db, to, - KDBUS_POLICY_TALK); -} - -/** - * kdbus_conn_policy_see_name_unlocked() - verify a connection can see a given - * name - * @conn: Connection - * @conn_creds: Credentials of @conn to use for policy check - * @name: Name - * - * This verifies that @conn is allowed to see the well-known name @name. Caller - * must hold policy-lock. - * - * Return: true if allowed, false if not. - */ -bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn, - const struct cred *conn_creds, - const char *name) -{ - int res; - - /* - * By default, all names are visible on a bus. SEE policies can only be - * installed on custom endpoints, where by default no name is visible. - */ - if (!conn->ep->user) - return true; - - res = kdbus_policy_query_unlocked(&conn->ep->policy_db, - conn_creds ? : conn->cred, - name, kdbus_strhash(name)); - return res >= KDBUS_POLICY_SEE; -} - -static bool kdbus_conn_policy_see_name(struct kdbus_conn *conn, - const struct cred *conn_creds, - const char *name) -{ - bool res; - - down_read(&conn->ep->policy_db.entries_rwlock); - res = kdbus_conn_policy_see_name_unlocked(conn, conn_creds, name); - up_read(&conn->ep->policy_db.entries_rwlock); - - return res; -} - -static bool kdbus_conn_policy_see(struct kdbus_conn *conn, - const struct cred *conn_creds, - struct kdbus_conn *whom) -{ - /* - * By default, all names are visible on a bus, so a connection can - * always see other connections. SEE policies can only be installed on - * custom endpoints, where by default no name is visible and we hide - * peers from each other, unless you see at least _one_ name of the - * peer. - */ - return !conn->ep->user || - kdbus_conn_policy_query_all(conn, conn_creds, - &conn->ep->policy_db, whom, - KDBUS_POLICY_SEE); -} - -/** - * kdbus_conn_policy_see_notification() - verify a connection is allowed to - * receive a given kernel notification - * @conn: Connection - * @conn_creds: Credentials of @conn to use for policy check - * @msg: Notification message - * - * This checks whether @conn is allowed to see the kernel notification. - * - * Return: true if allowed, false if not. - */ -bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - const struct cred *conn_creds, - const struct kdbus_msg *msg) -{ - /* - * Depending on the notification type, broadcasted kernel notifications - * have to be filtered: - * - * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}: This notification is forwarded - * to a peer if, and only if, that peer can see the name this - * notification is for. - * - * KDBUS_ITEM_ID_{ADD,REMOVE}: Notifications for ID changes are - * broadcast to everyone, to allow tracking peers. - */ - - switch (msg->items[0].type) { - case KDBUS_ITEM_NAME_ADD: - case KDBUS_ITEM_NAME_REMOVE: - case KDBUS_ITEM_NAME_CHANGE: - return kdbus_conn_policy_see_name(conn, conn_creds, - msg->items[0].name_change.name); - - case KDBUS_ITEM_ID_ADD: - case KDBUS_ITEM_ID_REMOVE: - return true; - - default: - WARN(1, "Invalid type for notification broadcast: %llu\n", - (unsigned long long)msg->items[0].type); - return false; - } -} - -/** - * kdbus_cmd_hello() - handle KDBUS_CMD_HELLO - * @ep: Endpoint to operate on - * @file: File this connection is opened on - * @argp: Command payload - * - * Return: NULL or newly created connection on success, ERR_PTR on failure. - */ -struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, struct file *file, - void __user *argp) -{ - struct kdbus_cmd_hello *cmd; - struct kdbus_conn *c = NULL; - const char *item_name; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_NAME }, - { .type = KDBUS_ITEM_CREDS }, - { .type = KDBUS_ITEM_PIDS }, - { .type = KDBUS_ITEM_SECLABEL }, - { .type = KDBUS_ITEM_CONN_DESCRIPTION }, - { .type = KDBUS_ITEM_POLICY_ACCESS, .multiple = true }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE | - KDBUS_HELLO_ACCEPT_FD | - KDBUS_HELLO_ACTIVATOR | - KDBUS_HELLO_POLICY_HOLDER | - KDBUS_HELLO_MONITOR, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret < 0) - return ERR_PTR(ret); - if (ret > 0) - return NULL; - - item_name = argv[1].item ? argv[1].item->str : NULL; - - c = kdbus_conn_new(ep, file, cmd, item_name, - argv[2].item ? &argv[2].item->creds : NULL, - argv[3].item ? &argv[3].item->pids : NULL, - argv[4].item ? argv[4].item->str : NULL, - argv[5].item ? argv[5].item->str : NULL); - if (IS_ERR(c)) { - ret = PTR_ERR(c); - c = NULL; - goto exit; - } - - ret = kdbus_conn_connect(c, item_name); - if (ret < 0) - goto exit; - - if (kdbus_conn_is_activator(c) || kdbus_conn_is_policy_holder(c)) { - ret = kdbus_conn_acquire(c); - if (ret < 0) - goto exit; - - ret = kdbus_policy_set(&c->ep->bus->policy_db, args.items, - args.items_size, 1, - kdbus_conn_is_policy_holder(c), c); - kdbus_conn_release(c); - if (ret < 0) - goto exit; - } - - if (copy_to_user(argp, cmd, sizeof(*cmd))) - ret = -EFAULT; - -exit: - ret = kdbus_args_clear(&args, ret); - if (ret < 0) { - if (c) { - kdbus_conn_disconnect(c, false); - kdbus_conn_unref(c); - } - return ERR_PTR(ret); - } - return c; -} - -/** - * kdbus_cmd_byebye_unlocked() - handle KDBUS_CMD_BYEBYE - * @conn: connection to operate on - * @argp: command payload - * - * The caller must not hold any active reference to @conn or this will deadlock. - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp) -{ - struct kdbus_cmd *cmd; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - if (!kdbus_conn_is_ordinary(conn)) - return -EOPNOTSUPP; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - ret = kdbus_conn_disconnect(conn, true); - return kdbus_args_clear(&args, ret); -} - -/** - * kdbus_cmd_conn_info() - handle KDBUS_CMD_CONN_INFO - * @conn: connection to operate on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp) -{ - struct kdbus_meta_conn *conn_meta = NULL; - struct kdbus_pool_slice *slice = NULL; - struct kdbus_name_entry *entry = NULL; - struct kdbus_name_owner *owner = NULL; - struct kdbus_conn *owner_conn = NULL; - struct kdbus_item *meta_items = NULL; - struct kdbus_info info = {}; - struct kdbus_cmd_info *cmd; - struct kdbus_bus *bus = conn->ep->bus; - struct kvec kvec[3]; - size_t meta_size, cnt = 0; - const char *name; - u64 attach_flags, size = 0; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_NAME }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - /* registry must be held throughout lookup *and* collecting data */ - down_read(&bus->name_registry->rwlock); - - ret = kdbus_sanitize_attach_flags(cmd->attach_flags, &attach_flags); - if (ret < 0) - goto exit; - - name = argv[1].item ? argv[1].item->str : NULL; - - if (name) { - entry = kdbus_name_lookup_unlocked(bus->name_registry, name); - if (entry) - owner = kdbus_name_get_owner(entry); - if (!owner || - !kdbus_conn_policy_see_name(conn, current_cred(), name) || - (cmd->id != 0 && owner->conn->id != cmd->id)) { - /* pretend a name doesn't exist if you cannot see it */ - ret = -ESRCH; - goto exit; - } - - owner_conn = kdbus_conn_ref(owner->conn); - } else if (cmd->id > 0) { - owner_conn = kdbus_bus_find_conn_by_id(bus, cmd->id); - if (!owner_conn || !kdbus_conn_policy_see(conn, current_cred(), - owner_conn)) { - /* pretend an id doesn't exist if you cannot see it */ - ret = -ENXIO; - goto exit; - } - } else { - ret = -EINVAL; - goto exit; - } - - attach_flags &= atomic64_read(&owner_conn->attach_flags_send); - - conn_meta = kdbus_meta_conn_new(); - if (IS_ERR(conn_meta)) { - ret = PTR_ERR(conn_meta); - conn_meta = NULL; - goto exit; - } - - ret = kdbus_meta_conn_collect(conn_meta, owner_conn, 0, attach_flags); - if (ret < 0) - goto exit; - - ret = kdbus_meta_emit(owner_conn->meta_proc, owner_conn->meta_fake, - conn_meta, conn, attach_flags, - &meta_items, &meta_size); - if (ret < 0) - goto exit; - - info.id = owner_conn->id; - info.flags = owner_conn->flags; - - kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &size); - if (meta_size > 0) { - kdbus_kvec_set(&kvec[cnt++], meta_items, meta_size, &size); - cnt += !!kdbus_kvec_pad(&kvec[cnt], &size); - } - - info.size = size; - - slice = kdbus_pool_slice_alloc(conn->pool, size, false); - if (IS_ERR(slice)) { - ret = PTR_ERR(slice); - slice = NULL; - goto exit; - } - - ret = kdbus_pool_slice_copy_kvec(slice, 0, kvec, cnt, size); - if (ret < 0) - goto exit; - - kdbus_pool_slice_publish(slice, &cmd->offset, &cmd->info_size); - - if (kdbus_member_set_user(&cmd->offset, argp, typeof(*cmd), offset) || - kdbus_member_set_user(&cmd->info_size, argp, - typeof(*cmd), info_size)) { - ret = -EFAULT; - goto exit; - } - - ret = 0; - -exit: - up_read(&bus->name_registry->rwlock); - kdbus_pool_slice_release(slice); - kfree(meta_items); - kdbus_meta_conn_unref(conn_meta); - kdbus_conn_unref(owner_conn); - return kdbus_args_clear(&args, ret); -} - -/** - * kdbus_cmd_update() - handle KDBUS_CMD_UPDATE - * @conn: connection to operate on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp) -{ - struct kdbus_item *item_policy; - u64 *item_attach_send = NULL; - u64 *item_attach_recv = NULL; - struct kdbus_cmd *cmd; - u64 attach_send; - u64 attach_recv; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_ATTACH_FLAGS_SEND }, - { .type = KDBUS_ITEM_ATTACH_FLAGS_RECV }, - { .type = KDBUS_ITEM_NAME, .multiple = true }, - { .type = KDBUS_ITEM_POLICY_ACCESS, .multiple = true }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - item_attach_send = argv[1].item ? &argv[1].item->data64[0] : NULL; - item_attach_recv = argv[2].item ? &argv[2].item->data64[0] : NULL; - item_policy = argv[3].item ? : argv[4].item; - - if (item_attach_send) { - if (!kdbus_conn_is_ordinary(conn) && - !kdbus_conn_is_monitor(conn)) { - ret = -EOPNOTSUPP; - goto exit; - } - - ret = kdbus_sanitize_attach_flags(*item_attach_send, - &attach_send); - if (ret < 0) - goto exit; - } - - if (item_attach_recv) { - if (!kdbus_conn_is_ordinary(conn) && - !kdbus_conn_is_monitor(conn) && - !kdbus_conn_is_activator(conn)) { - ret = -EOPNOTSUPP; - goto exit; - } - - ret = kdbus_sanitize_attach_flags(*item_attach_recv, - &attach_recv); - if (ret < 0) - goto exit; - } - - if (item_policy && !kdbus_conn_is_policy_holder(conn)) { - ret = -EOPNOTSUPP; - goto exit; - } - - /* now that we verified the input, update the connection */ - - if (item_policy) { - ret = kdbus_policy_set(&conn->ep->bus->policy_db, cmd->items, - KDBUS_ITEMS_SIZE(cmd, items), - 1, true, conn); - if (ret < 0) - goto exit; - } - - if (item_attach_send) - atomic64_set(&conn->attach_flags_send, attach_send); - - if (item_attach_recv) - atomic64_set(&conn->attach_flags_recv, attach_recv); - -exit: - return kdbus_args_clear(&args, ret); -} - -/** - * kdbus_cmd_send() - handle KDBUS_CMD_SEND - * @conn: connection to operate on - * @f: file this command was called on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp) -{ - struct kdbus_cmd_send *cmd; - struct kdbus_staging *staging = NULL; - struct kdbus_msg *msg = NULL; - struct file *cancel_fd = NULL; - int ret, ret2; - - /* command arguments */ - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_CANCEL_FD }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE | - KDBUS_SEND_SYNC_REPLY, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - /* message arguments */ - struct kdbus_arg msg_argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_PAYLOAD_VEC, .multiple = true }, - { .type = KDBUS_ITEM_PAYLOAD_MEMFD, .multiple = true }, - { .type = KDBUS_ITEM_FDS }, - { .type = KDBUS_ITEM_BLOOM_FILTER }, - { .type = KDBUS_ITEM_DST_NAME }, - }; - struct kdbus_args msg_args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE | - KDBUS_MSG_EXPECT_REPLY | - KDBUS_MSG_NO_AUTO_START | - KDBUS_MSG_SIGNAL, - .argv = msg_argv, - .argc = ARRAY_SIZE(msg_argv), - }; - - if (!kdbus_conn_is_ordinary(conn)) - return -EOPNOTSUPP; - - /* make sure to parse both, @cmd and @msg on negotiation */ - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret < 0) - goto exit; - else if (ret > 0 && !cmd->msg_address) /* negotiation without msg */ - goto exit; - - ret2 = kdbus_args_parse_msg(&msg_args, KDBUS_PTR(cmd->msg_address), - &msg); - if (ret2 < 0) { /* cannot parse message */ - ret = ret2; - goto exit; - } else if (ret2 > 0 && !ret) { /* msg-negot implies cmd-negot */ - ret = -EINVAL; - goto exit; - } else if (ret > 0) { /* negotiation */ - goto exit; - } - - /* here we parsed both, @cmd and @msg, and neither wants negotiation */ - - cmd->reply.return_flags = 0; - kdbus_pool_publish_empty(conn->pool, &cmd->reply.offset, - &cmd->reply.msg_size); - - if (argv[1].item) { - cancel_fd = fget(argv[1].item->fds[0]); - if (!cancel_fd) { - ret = -EBADF; - goto exit; - } - - if (!cancel_fd->f_op->poll) { - ret = -EINVAL; - goto exit; - } - } - - /* patch-in the source of this message */ - if (msg->src_id > 0 && msg->src_id != conn->id) { - ret = -EINVAL; - goto exit; - } - msg->src_id = conn->id; - - staging = kdbus_staging_new_user(conn->ep->bus, cmd, msg); - if (IS_ERR(staging)) { - ret = PTR_ERR(staging); - staging = NULL; - goto exit; - } - - if (msg->dst_id == KDBUS_DST_ID_BROADCAST) { - down_read(&conn->ep->bus->name_registry->rwlock); - kdbus_bus_broadcast(conn->ep->bus, conn, staging); - up_read(&conn->ep->bus->name_registry->rwlock); - } else if (cmd->flags & KDBUS_SEND_SYNC_REPLY) { - struct kdbus_reply *r; - ktime_t exp; - - exp = ns_to_ktime(msg->timeout_ns); - r = kdbus_conn_call(conn, staging, exp); - if (IS_ERR(r)) { - ret = PTR_ERR(r); - goto exit; - } - - ret = kdbus_conn_wait_reply(conn, cmd, f, cancel_fd, r, exp); - kdbus_reply_unref(r); - if (ret < 0) - goto exit; - } else if ((msg->flags & KDBUS_MSG_EXPECT_REPLY) || - msg->cookie_reply == 0) { - ret = kdbus_conn_unicast(conn, staging); - if (ret < 0) - goto exit; - } else { - ret = kdbus_conn_reply(conn, staging); - if (ret < 0) - goto exit; - } - - if (kdbus_member_set_user(&cmd->reply, argp, typeof(*cmd), reply)) - ret = -EFAULT; - -exit: - if (cancel_fd) - fput(cancel_fd); - kdbus_staging_free(staging); - ret = kdbus_args_clear(&msg_args, ret); - return kdbus_args_clear(&args, ret); -} - -/** - * kdbus_cmd_recv() - handle KDBUS_CMD_RECV - * @conn: connection to operate on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_recv(struct kdbus_conn *conn, void __user *argp) -{ - struct kdbus_queue_entry *entry; - struct kdbus_cmd_recv *cmd; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE | - KDBUS_RECV_PEEK | - KDBUS_RECV_DROP | - KDBUS_RECV_USE_PRIORITY, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - if (!kdbus_conn_is_ordinary(conn) && - !kdbus_conn_is_monitor(conn) && - !kdbus_conn_is_activator(conn)) - return -EOPNOTSUPP; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - cmd->dropped_msgs = 0; - cmd->msg.return_flags = 0; - kdbus_pool_publish_empty(conn->pool, &cmd->msg.offset, - &cmd->msg.msg_size); - - /* DROP+priority is not realiably, so prevent it */ - if ((cmd->flags & KDBUS_RECV_DROP) && - (cmd->flags & KDBUS_RECV_USE_PRIORITY)) { - ret = -EINVAL; - goto exit; - } - - mutex_lock(&conn->lock); - - entry = kdbus_queue_peek(&conn->queue, cmd->priority, - cmd->flags & KDBUS_RECV_USE_PRIORITY); - if (!entry) { - mutex_unlock(&conn->lock); - ret = -EAGAIN; - } else if (cmd->flags & KDBUS_RECV_DROP) { - struct kdbus_reply *reply = kdbus_reply_ref(entry->reply); - - kdbus_queue_entry_free(entry); - - mutex_unlock(&conn->lock); - - if (reply) { - mutex_lock(&reply->reply_dst->lock); - if (!list_empty(&reply->entry)) { - kdbus_reply_unlink(reply); - if (reply->sync) - kdbus_sync_reply_wakeup(reply, -EPIPE); - else - kdbus_notify_reply_dead(conn->ep->bus, - reply->reply_dst->id, - reply->cookie); - } - mutex_unlock(&reply->reply_dst->lock); - kdbus_notify_flush(conn->ep->bus); - } - - kdbus_reply_unref(reply); - } else { - bool install_fds; - - /* - * PEEK just returns the location of the next message. Do not - * install FDs nor memfds nor anything else. The only - * information of interest should be the message header and - * metadata. Any FD numbers in the payload is undefined for - * PEEK'ed messages. - * Also make sure to never install fds into a connection that - * has refused to receive any. Ordinary connections will not get - * messages with FDs queued (the receiver will get -ECOMM), but - * eavesdroppers might. - */ - install_fds = (conn->flags & KDBUS_HELLO_ACCEPT_FD) && - !(cmd->flags & KDBUS_RECV_PEEK); - - ret = kdbus_queue_entry_install(entry, - &cmd->msg.return_flags, - install_fds); - if (ret < 0) { - mutex_unlock(&conn->lock); - goto exit; - } - - kdbus_pool_slice_publish(entry->slice, &cmd->msg.offset, - &cmd->msg.msg_size); - - if (!(cmd->flags & KDBUS_RECV_PEEK)) - kdbus_queue_entry_free(entry); - - mutex_unlock(&conn->lock); - } - - cmd->dropped_msgs = atomic_xchg(&conn->lost_count, 0); - if (cmd->dropped_msgs > 0) - cmd->return_flags |= KDBUS_RECV_RETURN_DROPPED_MSGS; - - if (kdbus_member_set_user(&cmd->msg, argp, typeof(*cmd), msg) || - kdbus_member_set_user(&cmd->dropped_msgs, argp, typeof(*cmd), - dropped_msgs)) - ret = -EFAULT; - -exit: - return kdbus_args_clear(&args, ret); -} - -/** - * kdbus_cmd_free() - handle KDBUS_CMD_FREE - * @conn: connection to operate on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_free(struct kdbus_conn *conn, void __user *argp) -{ - struct kdbus_cmd_free *cmd; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - if (!kdbus_conn_is_ordinary(conn) && - !kdbus_conn_is_monitor(conn) && - !kdbus_conn_is_activator(conn)) - return -EOPNOTSUPP; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - ret = kdbus_pool_release_offset(conn->pool, cmd->offset); - - return kdbus_args_clear(&args, ret); -} diff --git a/ipc/kdbus/connection.h b/ipc/kdbus/connection.h deleted file mode 100644 index 1ad082014..000000000 --- a/ipc/kdbus/connection.h +++ /dev/null @@ -1,260 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_CONNECTION_H -#define __KDBUS_CONNECTION_H - -#include <linux/atomic.h> -#include <linux/kref.h> -#include <linux/lockdep.h> -#include <linux/path.h> - -#include "limits.h" -#include "metadata.h" -#include "pool.h" -#include "queue.h" -#include "util.h" - -#define KDBUS_HELLO_SPECIAL_CONN (KDBUS_HELLO_ACTIVATOR | \ - KDBUS_HELLO_POLICY_HOLDER | \ - KDBUS_HELLO_MONITOR) - -struct kdbus_name_entry; -struct kdbus_quota; -struct kdbus_staging; - -/** - * struct kdbus_conn - connection to a bus - * @kref: Reference count - * @active: Active references to the connection - * @id: Connection ID - * @flags: KDBUS_HELLO_* flags - * @attach_flags_send: KDBUS_ATTACH_* flags for sending - * @attach_flags_recv: KDBUS_ATTACH_* flags for receiving - * @description: Human-readable connection description, used for - * debugging. This field is only set when the - * connection is created. - * @ep: The endpoint this connection belongs to - * @lock: Connection data lock - * @hentry: Entry in ID <-> connection map - * @ep_entry: Entry in endpoint - * @monitor_entry: Entry in monitor, if the connection is a monitor - * @reply_list: List of connections this connection should - * reply to - * @work: Delayed work to handle timeouts - * activator for - * @match_db: Subscription filter to broadcast messages - * @meta_proc: Process metadata of connection creator, or NULL - * @meta_fake: Faked metadata, or NULL - * @pool: The user's buffer to receive messages - * @user: Owner of the connection - * @cred: The credentials of the connection at creation time - * @pid: Pid at creation time - * @root_path: Root path at creation time - * @request_count: Number of pending requests issued by this - * connection that are waiting for replies from - * other peers - * @lost_count: Number of lost broadcast messages - * @wait: Wake up this endpoint - * @queue: The message queue associated with this connection - * @quota: Array of per-user quota indexed by user->id - * @n_quota: Number of elements in quota array - * @names_list: List of well-known names - * @name_count: Number of owned well-known names - * @privileged: Whether this connection is privileged on the domain - * @owner: Owned by the same user as the bus owner - */ -struct kdbus_conn { - struct kref kref; - atomic_t active; -#ifdef CONFIG_DEBUG_LOCK_ALLOC - struct lockdep_map dep_map; -#endif - u64 id; - u64 flags; - atomic64_t attach_flags_send; - atomic64_t attach_flags_recv; - const char *description; - struct kdbus_ep *ep; - struct mutex lock; - struct hlist_node hentry; - struct list_head ep_entry; - struct list_head monitor_entry; - struct list_head reply_list; - struct delayed_work work; - struct kdbus_match_db *match_db; - struct kdbus_meta_proc *meta_proc; - struct kdbus_meta_fake *meta_fake; - struct kdbus_pool *pool; - struct kdbus_user *user; - const struct cred *cred; - struct pid *pid; - struct path root_path; - atomic_t request_count; - atomic_t lost_count; - wait_queue_head_t wait; - struct kdbus_queue queue; - - struct kdbus_quota *quota; - unsigned int n_quota; - - /* protected by registry->rwlock */ - struct list_head names_list; - unsigned int name_count; - - bool privileged:1; - bool owner:1; -}; - -struct kdbus_conn *kdbus_conn_ref(struct kdbus_conn *conn); -struct kdbus_conn *kdbus_conn_unref(struct kdbus_conn *conn); -bool kdbus_conn_active(const struct kdbus_conn *conn); -int kdbus_conn_acquire(struct kdbus_conn *conn); -void kdbus_conn_release(struct kdbus_conn *conn); -int kdbus_conn_disconnect(struct kdbus_conn *conn, bool ensure_queue_empty); -bool kdbus_conn_has_name(struct kdbus_conn *conn, const char *name); -int kdbus_conn_quota_inc(struct kdbus_conn *c, struct kdbus_user *u, - size_t memory, size_t fds); -void kdbus_conn_quota_dec(struct kdbus_conn *c, struct kdbus_user *u, - size_t memory, size_t fds); -void kdbus_conn_lost_message(struct kdbus_conn *c); -int kdbus_conn_entry_insert(struct kdbus_conn *conn_src, - struct kdbus_conn *conn_dst, - struct kdbus_staging *staging, - struct kdbus_reply *reply, - const struct kdbus_name_entry *name); -void kdbus_conn_move_messages(struct kdbus_conn *conn_dst, - struct kdbus_conn *conn_src, - u64 name_id); - -/* policy */ -bool kdbus_conn_policy_own_name(struct kdbus_conn *conn, - const struct cred *conn_creds, - const char *name); -bool kdbus_conn_policy_talk(struct kdbus_conn *conn, - const struct cred *conn_creds, - struct kdbus_conn *to); -bool kdbus_conn_policy_see_name_unlocked(struct kdbus_conn *conn, - const struct cred *curr_creds, - const char *name); -bool kdbus_conn_policy_see_notification(struct kdbus_conn *conn, - const struct cred *curr_creds, - const struct kdbus_msg *msg); - -/* command dispatcher */ -struct kdbus_conn *kdbus_cmd_hello(struct kdbus_ep *ep, struct file *file, - void __user *argp); -int kdbus_cmd_byebye_unlocked(struct kdbus_conn *conn, void __user *argp); -int kdbus_cmd_conn_info(struct kdbus_conn *conn, void __user *argp); -int kdbus_cmd_update(struct kdbus_conn *conn, void __user *argp); -int kdbus_cmd_send(struct kdbus_conn *conn, struct file *f, void __user *argp); -int kdbus_cmd_recv(struct kdbus_conn *conn, void __user *argp); -int kdbus_cmd_free(struct kdbus_conn *conn, void __user *argp); - -/** - * kdbus_conn_is_ordinary() - Check if connection is ordinary - * @conn: The connection to check - * - * Return: Non-zero if the connection is an ordinary connection - */ -static inline int kdbus_conn_is_ordinary(const struct kdbus_conn *conn) -{ - return !(conn->flags & KDBUS_HELLO_SPECIAL_CONN); -} - -/** - * kdbus_conn_is_activator() - Check if connection is an activator - * @conn: The connection to check - * - * Return: Non-zero if the connection is an activator - */ -static inline int kdbus_conn_is_activator(const struct kdbus_conn *conn) -{ - return conn->flags & KDBUS_HELLO_ACTIVATOR; -} - -/** - * kdbus_conn_is_policy_holder() - Check if connection is a policy holder - * @conn: The connection to check - * - * Return: Non-zero if the connection is a policy holder - */ -static inline int kdbus_conn_is_policy_holder(const struct kdbus_conn *conn) -{ - return conn->flags & KDBUS_HELLO_POLICY_HOLDER; -} - -/** - * kdbus_conn_is_monitor() - Check if connection is a monitor - * @conn: The connection to check - * - * Return: Non-zero if the connection is a monitor - */ -static inline int kdbus_conn_is_monitor(const struct kdbus_conn *conn) -{ - return conn->flags & KDBUS_HELLO_MONITOR; -} - -/** - * kdbus_conn_lock2() - Lock two connections - * @a: connection A to lock or NULL - * @b: connection B to lock or NULL - * - * Lock two connections at once. As we need to have a stable locking order, we - * always lock the connection with lower memory address first. - */ -static inline void kdbus_conn_lock2(struct kdbus_conn *a, struct kdbus_conn *b) -{ - if (a < b) { - if (a) - mutex_lock(&a->lock); - if (b && b != a) - mutex_lock_nested(&b->lock, !!a); - } else { - if (b) - mutex_lock(&b->lock); - if (a && a != b) - mutex_lock_nested(&a->lock, !!b); - } -} - -/** - * kdbus_conn_unlock2() - Unlock two connections - * @a: connection A to unlock or NULL - * @b: connection B to unlock or NULL - * - * Unlock two connections at once. See kdbus_conn_lock2(). - */ -static inline void kdbus_conn_unlock2(struct kdbus_conn *a, - struct kdbus_conn *b) -{ - if (a) - mutex_unlock(&a->lock); - if (b && b != a) - mutex_unlock(&b->lock); -} - -/** - * kdbus_conn_assert_active() - lockdep assert on active lock - * @conn: connection that shall be active - * - * This verifies via lockdep that the caller holds an active reference to the - * given connection. - */ -static inline void kdbus_conn_assert_active(struct kdbus_conn *conn) -{ - lockdep_assert_held(conn); -} - -#endif diff --git a/ipc/kdbus/domain.c b/ipc/kdbus/domain.c deleted file mode 100644 index 5d52d009d..000000000 --- a/ipc/kdbus/domain.c +++ /dev/null @@ -1,296 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/fs.h> -#include <linux/idr.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/uaccess.h> - -#include "bus.h" -#include "domain.h" -#include "handle.h" -#include "item.h" -#include "limits.h" -#include "util.h" - -static void kdbus_domain_control_free(struct kdbus_node *node) -{ - kfree(node); -} - -static struct kdbus_node *kdbus_domain_control_new(struct kdbus_domain *domain, - unsigned int access) -{ - struct kdbus_node *node; - int ret; - - node = kzalloc(sizeof(*node), GFP_KERNEL); - if (!node) - return ERR_PTR(-ENOMEM); - - kdbus_node_init(node, KDBUS_NODE_CONTROL); - - node->free_cb = kdbus_domain_control_free; - node->mode = domain->node.mode; - node->mode = S_IRUSR | S_IWUSR; - if (access & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD)) - node->mode |= S_IRGRP | S_IWGRP; - if (access & KDBUS_MAKE_ACCESS_WORLD) - node->mode |= S_IROTH | S_IWOTH; - - ret = kdbus_node_link(node, &domain->node, "control"); - if (ret < 0) - goto exit_free; - - return node; - -exit_free: - kdbus_node_drain(node); - kdbus_node_unref(node); - return ERR_PTR(ret); -} - -static void kdbus_domain_free(struct kdbus_node *node) -{ - struct kdbus_domain *domain = - container_of(node, struct kdbus_domain, node); - - put_user_ns(domain->user_namespace); - ida_destroy(&domain->user_ida); - idr_destroy(&domain->user_idr); - kfree(domain); -} - -/** - * kdbus_domain_new() - create a new domain - * @access: The access mode for this node (KDBUS_MAKE_ACCESS_*) - * - * Return: a new kdbus_domain on success, ERR_PTR on failure - */ -struct kdbus_domain *kdbus_domain_new(unsigned int access) -{ - struct kdbus_domain *d; - int ret; - - d = kzalloc(sizeof(*d), GFP_KERNEL); - if (!d) - return ERR_PTR(-ENOMEM); - - kdbus_node_init(&d->node, KDBUS_NODE_DOMAIN); - - d->node.free_cb = kdbus_domain_free; - d->node.mode = S_IRUSR | S_IXUSR; - if (access & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD)) - d->node.mode |= S_IRGRP | S_IXGRP; - if (access & KDBUS_MAKE_ACCESS_WORLD) - d->node.mode |= S_IROTH | S_IXOTH; - - mutex_init(&d->lock); - idr_init(&d->user_idr); - ida_init(&d->user_ida); - - /* Pin user namespace so we can guarantee domain-unique bus * names. */ - d->user_namespace = get_user_ns(current_user_ns()); - - ret = kdbus_node_link(&d->node, NULL, NULL); - if (ret < 0) - goto exit_unref; - - return d; - -exit_unref: - kdbus_node_drain(&d->node); - kdbus_node_unref(&d->node); - return ERR_PTR(ret); -} - -/** - * kdbus_domain_ref() - take a domain reference - * @domain: Domain - * - * Return: the domain itself - */ -struct kdbus_domain *kdbus_domain_ref(struct kdbus_domain *domain) -{ - if (domain) - kdbus_node_ref(&domain->node); - return domain; -} - -/** - * kdbus_domain_unref() - drop a domain reference - * @domain: Domain - * - * When the last reference is dropped, the domain internal structure - * is freed. - * - * Return: NULL - */ -struct kdbus_domain *kdbus_domain_unref(struct kdbus_domain *domain) -{ - if (domain) - kdbus_node_unref(&domain->node); - return NULL; -} - -/** - * kdbus_domain_populate() - populate static domain nodes - * @domain: domain to populate - * @access: KDBUS_MAKE_ACCESS_* access restrictions for new nodes - * - * Allocate and activate static sub-nodes of the given domain. This will fail if - * you call it on a non-active node or if the domain was already populated. - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_domain_populate(struct kdbus_domain *domain, unsigned int access) -{ - struct kdbus_node *control; - - /* - * Create a control-node for this domain. We drop our own reference - * immediately, effectively causing the node to be deactivated and - * released when the parent domain is. - */ - control = kdbus_domain_control_new(domain, access); - if (IS_ERR(control)) - return PTR_ERR(control); - - kdbus_node_activate(control); - kdbus_node_unref(control); - return 0; -} - -/** - * kdbus_user_lookup() - lookup a kdbus_user object - * @domain: domain of the user - * @uid: uid of the user; INVALID_UID for an anon user - * - * Lookup the kdbus user accounting object for the given domain. If INVALID_UID - * is passed, a new anonymous user is created which is private to the caller. - * - * Return: The user object is returned, ERR_PTR on failure. - */ -struct kdbus_user *kdbus_user_lookup(struct kdbus_domain *domain, kuid_t uid) -{ - struct kdbus_user *u = NULL, *old = NULL; - int ret; - - mutex_lock(&domain->lock); - - if (uid_valid(uid)) { - old = idr_find(&domain->user_idr, __kuid_val(uid)); - /* - * If the object is about to be destroyed, ignore it and - * replace the slot in the IDR later on. - */ - if (old && kref_get_unless_zero(&old->kref)) { - mutex_unlock(&domain->lock); - return old; - } - } - - u = kzalloc(sizeof(*u), GFP_KERNEL); - if (!u) { - ret = -ENOMEM; - goto exit; - } - - kref_init(&u->kref); - u->domain = kdbus_domain_ref(domain); - u->uid = uid; - atomic_set(&u->buses, 0); - atomic_set(&u->connections, 0); - - if (uid_valid(uid)) { - if (old) { - idr_replace(&domain->user_idr, u, __kuid_val(uid)); - old->uid = INVALID_UID; /* mark old as removed */ - } else { - ret = idr_alloc(&domain->user_idr, u, __kuid_val(uid), - __kuid_val(uid) + 1, GFP_KERNEL); - if (ret < 0) - goto exit; - } - } - - /* - * Allocate the smallest possible index for this user; used - * in arrays for accounting user quota in receiver queues. - */ - ret = ida_simple_get(&domain->user_ida, 1, 0, GFP_KERNEL); - if (ret < 0) - goto exit; - - u->id = ret; - mutex_unlock(&domain->lock); - return u; - -exit: - if (u) { - if (uid_valid(u->uid)) - idr_remove(&domain->user_idr, __kuid_val(u->uid)); - kdbus_domain_unref(u->domain); - kfree(u); - } - mutex_unlock(&domain->lock); - return ERR_PTR(ret); -} - -static void __kdbus_user_free(struct kref *kref) -{ - struct kdbus_user *user = container_of(kref, struct kdbus_user, kref); - - WARN_ON(atomic_read(&user->buses) > 0); - WARN_ON(atomic_read(&user->connections) > 0); - - mutex_lock(&user->domain->lock); - ida_simple_remove(&user->domain->user_ida, user->id); - if (uid_valid(user->uid)) - idr_remove(&user->domain->user_idr, __kuid_val(user->uid)); - mutex_unlock(&user->domain->lock); - - kdbus_domain_unref(user->domain); - kfree(user); -} - -/** - * kdbus_user_ref() - take a user reference - * @u: User - * - * Return: @u is returned - */ -struct kdbus_user *kdbus_user_ref(struct kdbus_user *u) -{ - if (u) - kref_get(&u->kref); - return u; -} - -/** - * kdbus_user_unref() - drop a user reference - * @u: User - * - * Return: NULL - */ -struct kdbus_user *kdbus_user_unref(struct kdbus_user *u) -{ - if (u) - kref_put(&u->kref, __kdbus_user_free); - return NULL; -} diff --git a/ipc/kdbus/domain.h b/ipc/kdbus/domain.h deleted file mode 100644 index 447a2bd4d..000000000 --- a/ipc/kdbus/domain.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_DOMAIN_H -#define __KDBUS_DOMAIN_H - -#include <linux/fs.h> -#include <linux/idr.h> -#include <linux/kref.h> -#include <linux/user_namespace.h> - -#include "node.h" - -/** - * struct kdbus_domain - domain for buses - * @node: Underlying API node - * @lock: Domain data lock - * @last_id: Last used object id - * @user_idr: Set of all users indexed by UID - * @user_ida: Set of all users to compute small indices - * @user_namespace: User namespace, pinned at creation time - * @dentry: Root dentry of VFS mount (don't use outside of kdbusfs) - */ -struct kdbus_domain { - struct kdbus_node node; - struct mutex lock; - atomic64_t last_id; - struct idr user_idr; - struct ida user_ida; - struct user_namespace *user_namespace; - struct dentry *dentry; -}; - -/** - * struct kdbus_user - resource accounting for users - * @kref: Reference counter - * @domain: Domain of the user - * @id: Index of this user - * @uid: UID of the user - * @buses: Number of buses the user has created - * @connections: Number of connections the user has created - */ -struct kdbus_user { - struct kref kref; - struct kdbus_domain *domain; - unsigned int id; - kuid_t uid; - atomic_t buses; - atomic_t connections; -}; - -#define kdbus_domain_from_node(_node) \ - container_of((_node), struct kdbus_domain, node) - -struct kdbus_domain *kdbus_domain_new(unsigned int access); -struct kdbus_domain *kdbus_domain_ref(struct kdbus_domain *domain); -struct kdbus_domain *kdbus_domain_unref(struct kdbus_domain *domain); -int kdbus_domain_populate(struct kdbus_domain *domain, unsigned int access); - -#define KDBUS_USER_KERNEL_ID 0 /* ID 0 is reserved for kernel accounting */ - -struct kdbus_user *kdbus_user_lookup(struct kdbus_domain *domain, kuid_t uid); -struct kdbus_user *kdbus_user_ref(struct kdbus_user *u); -struct kdbus_user *kdbus_user_unref(struct kdbus_user *u); - -#endif diff --git a/ipc/kdbus/endpoint.c b/ipc/kdbus/endpoint.c deleted file mode 100644 index 5694ff6dc..000000000 --- a/ipc/kdbus/endpoint.c +++ /dev/null @@ -1,303 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/fs.h> -#include <linux/idr.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/sched.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/uio.h> - -#include "bus.h" -#include "connection.h" -#include "domain.h" -#include "endpoint.h" -#include "handle.h" -#include "item.h" -#include "message.h" -#include "policy.h" - -static void kdbus_ep_free(struct kdbus_node *node) -{ - struct kdbus_ep *ep = container_of(node, struct kdbus_ep, node); - - WARN_ON(!list_empty(&ep->conn_list)); - - kdbus_policy_db_clear(&ep->policy_db); - kdbus_bus_unref(ep->bus); - kdbus_user_unref(ep->user); - kfree(ep); -} - -static void kdbus_ep_release(struct kdbus_node *node, bool was_active) -{ - struct kdbus_ep *ep = container_of(node, struct kdbus_ep, node); - - /* disconnect all connections to this endpoint */ - for (;;) { - struct kdbus_conn *conn; - - mutex_lock(&ep->lock); - conn = list_first_entry_or_null(&ep->conn_list, - struct kdbus_conn, - ep_entry); - if (!conn) { - mutex_unlock(&ep->lock); - break; - } - - /* take reference, release lock, disconnect without lock */ - kdbus_conn_ref(conn); - mutex_unlock(&ep->lock); - - kdbus_conn_disconnect(conn, false); - kdbus_conn_unref(conn); - } -} - -/** - * kdbus_ep_new() - create a new endpoint - * @bus: The bus this endpoint will be created for - * @name: The name of the endpoint - * @access: The access flags for this node (KDBUS_MAKE_ACCESS_*) - * @uid: The uid of the node - * @gid: The gid of the node - * @is_custom: Whether this is a custom endpoint - * - * This function will create a new endpoint with the given - * name and properties for a given bus. - * - * Return: a new kdbus_ep on success, ERR_PTR on failure. - */ -struct kdbus_ep *kdbus_ep_new(struct kdbus_bus *bus, const char *name, - unsigned int access, kuid_t uid, kgid_t gid, - bool is_custom) -{ - struct kdbus_ep *e; - int ret; - - /* - * Validate only custom endpoints names, default endpoints - * with a "bus" name are created when the bus is created - */ - if (is_custom) { - ret = kdbus_verify_uid_prefix(name, bus->domain->user_namespace, - uid); - if (ret < 0) - return ERR_PTR(ret); - } - - e = kzalloc(sizeof(*e), GFP_KERNEL); - if (!e) - return ERR_PTR(-ENOMEM); - - kdbus_node_init(&e->node, KDBUS_NODE_ENDPOINT); - - e->node.free_cb = kdbus_ep_free; - e->node.release_cb = kdbus_ep_release; - e->node.uid = uid; - e->node.gid = gid; - e->node.mode = S_IRUSR | S_IWUSR; - if (access & (KDBUS_MAKE_ACCESS_GROUP | KDBUS_MAKE_ACCESS_WORLD)) - e->node.mode |= S_IRGRP | S_IWGRP; - if (access & KDBUS_MAKE_ACCESS_WORLD) - e->node.mode |= S_IROTH | S_IWOTH; - - mutex_init(&e->lock); - INIT_LIST_HEAD(&e->conn_list); - kdbus_policy_db_init(&e->policy_db); - e->bus = kdbus_bus_ref(bus); - - ret = kdbus_node_link(&e->node, &bus->node, name); - if (ret < 0) - goto exit_unref; - - /* - * Transactions on custom endpoints are never accounted on the global - * user limits. Instead, for each custom endpoint, we create a custom, - * unique user, which all transactions are accounted on. Regardless of - * the user using that endpoint, it is always accounted on the same - * user-object. This budget is not shared with ordinary users on - * non-custom endpoints. - */ - if (is_custom) { - e->user = kdbus_user_lookup(bus->domain, INVALID_UID); - if (IS_ERR(e->user)) { - ret = PTR_ERR(e->user); - e->user = NULL; - goto exit_unref; - } - } - - return e; - -exit_unref: - kdbus_node_drain(&e->node); - kdbus_node_unref(&e->node); - return ERR_PTR(ret); -} - -/** - * kdbus_ep_ref() - increase the reference counter of a kdbus_ep - * @ep: The endpoint to reference - * - * Every user of an endpoint, except for its creator, must add a reference to - * the kdbus_ep instance using this function. - * - * Return: the ep itself - */ -struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep) -{ - if (ep) - kdbus_node_ref(&ep->node); - return ep; -} - -/** - * kdbus_ep_unref() - decrease the reference counter of a kdbus_ep - * @ep: The ep to unref - * - * Release a reference. If the reference count drops to 0, the ep will be - * freed. - * - * Return: NULL - */ -struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep) -{ - if (ep) - kdbus_node_unref(&ep->node); - return NULL; -} - -/** - * kdbus_ep_is_privileged() - check whether a file is privileged - * @ep: endpoint to operate on - * @file: file to test - * - * Return: True if @file is privileged in the domain of @ep. - */ -bool kdbus_ep_is_privileged(struct kdbus_ep *ep, struct file *file) -{ - return !ep->user && - file_ns_capable(file, ep->bus->domain->user_namespace, - CAP_IPC_OWNER); -} - -/** - * kdbus_ep_is_owner() - check whether a file should be treated as bus owner - * @ep: endpoint to operate on - * @file: file to test - * - * Return: True if @file should be treated as bus owner on @ep - */ -bool kdbus_ep_is_owner(struct kdbus_ep *ep, struct file *file) -{ - return !ep->user && - (uid_eq(file->f_cred->euid, ep->bus->node.uid) || - kdbus_ep_is_privileged(ep, file)); -} - -/** - * kdbus_cmd_ep_make() - handle KDBUS_CMD_ENDPOINT_MAKE - * @bus: bus to operate on - * @argp: command payload - * - * Return: NULL or newly created endpoint on success, ERR_PTR on failure. - */ -struct kdbus_ep *kdbus_cmd_ep_make(struct kdbus_bus *bus, void __user *argp) -{ - const char *item_make_name; - struct kdbus_ep *ep = NULL; - struct kdbus_cmd *cmd; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_MAKE_NAME, .mandatory = true }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE | - KDBUS_MAKE_ACCESS_GROUP | - KDBUS_MAKE_ACCESS_WORLD, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret < 0) - return ERR_PTR(ret); - if (ret > 0) - return NULL; - - item_make_name = argv[1].item->str; - - ep = kdbus_ep_new(bus, item_make_name, cmd->flags, - current_euid(), current_egid(), true); - if (IS_ERR(ep)) { - ret = PTR_ERR(ep); - ep = NULL; - goto exit; - } - - if (!kdbus_node_activate(&ep->node)) { - ret = -ESHUTDOWN; - goto exit; - } - -exit: - ret = kdbus_args_clear(&args, ret); - if (ret < 0) { - if (ep) { - kdbus_node_drain(&ep->node); - kdbus_ep_unref(ep); - } - return ERR_PTR(ret); - } - return ep; -} - -/** - * kdbus_cmd_ep_update() - handle KDBUS_CMD_ENDPOINT_UPDATE - * @ep: endpoint to operate on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_ep_update(struct kdbus_ep *ep, void __user *argp) -{ - struct kdbus_cmd *cmd; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_NAME, .multiple = true }, - { .type = KDBUS_ITEM_POLICY_ACCESS, .multiple = true }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - ret = kdbus_policy_set(&ep->policy_db, args.items, args.items_size, - 0, true, ep); - return kdbus_args_clear(&args, ret); -} diff --git a/ipc/kdbus/endpoint.h b/ipc/kdbus/endpoint.h deleted file mode 100644 index e0da59f01..000000000 --- a/ipc/kdbus/endpoint.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_ENDPOINT_H -#define __KDBUS_ENDPOINT_H - -#include <linux/list.h> -#include <linux/mutex.h> -#include <linux/uidgid.h> -#include "node.h" -#include "policy.h" - -struct kdbus_bus; -struct kdbus_user; - -/** - * struct kdbus_ep - endpoint to access a bus - * @node: The kdbus node - * @lock: Endpoint data lock - * @bus: Bus behind this endpoint - * @user: Custom enpoints account against an anonymous user - * @policy_db: Uploaded policy - * @conn_list: Connections of this endpoint - * - * An endpoint offers access to a bus; the default endpoint node name is "bus". - * Additional custom endpoints to the same bus can be created and they can - * carry their own policies/filters. - */ -struct kdbus_ep { - struct kdbus_node node; - struct mutex lock; - - /* static */ - struct kdbus_bus *bus; - struct kdbus_user *user; - - /* protected by own locks */ - struct kdbus_policy_db policy_db; - - /* protected by ep->lock */ - struct list_head conn_list; -}; - -#define kdbus_ep_from_node(_node) \ - container_of((_node), struct kdbus_ep, node) - -struct kdbus_ep *kdbus_ep_new(struct kdbus_bus *bus, const char *name, - unsigned int access, kuid_t uid, kgid_t gid, - bool policy); -struct kdbus_ep *kdbus_ep_ref(struct kdbus_ep *ep); -struct kdbus_ep *kdbus_ep_unref(struct kdbus_ep *ep); - -bool kdbus_ep_is_privileged(struct kdbus_ep *ep, struct file *file); -bool kdbus_ep_is_owner(struct kdbus_ep *ep, struct file *file); - -struct kdbus_ep *kdbus_cmd_ep_make(struct kdbus_bus *bus, void __user *argp); -int kdbus_cmd_ep_update(struct kdbus_ep *ep, void __user *argp); - -#endif diff --git a/ipc/kdbus/fs.c b/ipc/kdbus/fs.c deleted file mode 100644 index 6330c61e5..000000000 --- a/ipc/kdbus/fs.c +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/dcache.h> -#include <linux/fs.h> -#include <linux/fsnotify.h> -#include <linux/init.h> -#include <linux/ipc_namespace.h> -#include <linux/magic.h> -#include <linux/module.h> -#include <linux/mount.h> -#include <linux/mutex.h> -#include <linux/namei.h> -#include <linux/pagemap.h> -#include <linux/sched.h> -#include <linux/slab.h> - -#include "bus.h" -#include "domain.h" -#include "endpoint.h" -#include "fs.h" -#include "handle.h" -#include "node.h" - -#define kdbus_node_from_dentry(_dentry) \ - ((struct kdbus_node *)(_dentry)->d_fsdata) - -static struct inode *fs_inode_get(struct super_block *sb, - struct kdbus_node *node); - -/* - * Directory Management - */ - -static inline unsigned char kdbus_dt_type(struct kdbus_node *node) -{ - switch (node->type) { - case KDBUS_NODE_DOMAIN: - case KDBUS_NODE_BUS: - return DT_DIR; - case KDBUS_NODE_CONTROL: - case KDBUS_NODE_ENDPOINT: - return DT_REG; - } - - return DT_UNKNOWN; -} - -static int fs_dir_fop_iterate(struct file *file, struct dir_context *ctx) -{ - struct dentry *dentry = file->f_path.dentry; - struct kdbus_node *parent = kdbus_node_from_dentry(dentry); - struct kdbus_node *old, *next = file->private_data; - - /* - * kdbusfs directory iterator (modelled after sysfs/kernfs) - * When iterating kdbusfs directories, we iterate all children of the - * parent kdbus_node object. We use ctx->pos to store the hash of the - * child and file->private_data to store a reference to the next node - * object. If ctx->pos is not modified via llseek while you iterate a - * directory, then we use the file->private_data node pointer to - * directly access the next node in the tree. - * However, if you directly seek on the directory, we have to find the - * closest node to that position and cannot use our node pointer. This - * means iterating the rb-tree to find the closest match and start over - * from there. - * Note that hash values are not necessarily unique. Therefore, llseek - * is not guaranteed to seek to the same node that you got when you - * retrieved the position. Seeking to 0, 1, 2 and >=INT_MAX is safe, - * though. We could use the inode-number as position, but this would - * require another rb-tree for fast access. Kernfs and others already - * ignore those conflicts, so we should be fine, too. - */ - - if (!dir_emit_dots(file, ctx)) - return 0; - - /* acquire @next; if deactivated, or seek detected, find next node */ - old = next; - if (next && ctx->pos == next->hash) { - if (kdbus_node_acquire(next)) - kdbus_node_ref(next); - else - next = kdbus_node_next_child(parent, next); - } else { - next = kdbus_node_find_closest(parent, ctx->pos); - } - kdbus_node_unref(old); - - while (next) { - /* emit @next */ - file->private_data = next; - ctx->pos = next->hash; - - kdbus_node_release(next); - - if (!dir_emit(ctx, next->name, strlen(next->name), next->id, - kdbus_dt_type(next))) - return 0; - - /* find next node after @next */ - old = next; - next = kdbus_node_next_child(parent, next); - kdbus_node_unref(old); - } - - file->private_data = NULL; - ctx->pos = INT_MAX; - - return 0; -} - -static loff_t fs_dir_fop_llseek(struct file *file, loff_t offset, int whence) -{ - struct inode *inode = file_inode(file); - loff_t ret; - - /* protect f_off against fop_iterate */ - mutex_lock(&inode->i_mutex); - ret = generic_file_llseek(file, offset, whence); - mutex_unlock(&inode->i_mutex); - - return ret; -} - -static int fs_dir_fop_release(struct inode *inode, struct file *file) -{ - kdbus_node_unref(file->private_data); - return 0; -} - -static const struct file_operations fs_dir_fops = { - .read = generic_read_dir, - .iterate = fs_dir_fop_iterate, - .llseek = fs_dir_fop_llseek, - .release = fs_dir_fop_release, -}; - -static struct dentry *fs_dir_iop_lookup(struct inode *dir, - struct dentry *dentry, - unsigned int flags) -{ - struct dentry *dnew = NULL; - struct kdbus_node *parent; - struct kdbus_node *node; - struct inode *inode; - - parent = kdbus_node_from_dentry(dentry->d_parent); - if (!kdbus_node_acquire(parent)) - return NULL; - - /* returns reference to _acquired_ child node */ - node = kdbus_node_find_child(parent, dentry->d_name.name); - if (node) { - dentry->d_fsdata = node; - inode = fs_inode_get(dir->i_sb, node); - if (IS_ERR(inode)) - dnew = ERR_CAST(inode); - else - dnew = d_splice_alias(inode, dentry); - - kdbus_node_release(node); - } - - kdbus_node_release(parent); - return dnew; -} - -static const struct inode_operations fs_dir_iops = { - .permission = generic_permission, - .lookup = fs_dir_iop_lookup, -}; - -/* - * Inode Management - */ - -static const struct inode_operations fs_inode_iops = { - .permission = generic_permission, -}; - -static struct inode *fs_inode_get(struct super_block *sb, - struct kdbus_node *node) -{ - struct inode *inode; - - inode = iget_locked(sb, node->id); - if (!inode) - return ERR_PTR(-ENOMEM); - if (!(inode->i_state & I_NEW)) - return inode; - - inode->i_private = kdbus_node_ref(node); - inode->i_mapping->a_ops = &empty_aops; - inode->i_mode = node->mode & S_IALLUGO; - inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; - inode->i_uid = node->uid; - inode->i_gid = node->gid; - - switch (node->type) { - case KDBUS_NODE_DOMAIN: - case KDBUS_NODE_BUS: - inode->i_mode |= S_IFDIR; - inode->i_op = &fs_dir_iops; - inode->i_fop = &fs_dir_fops; - set_nlink(inode, 2); - break; - case KDBUS_NODE_CONTROL: - case KDBUS_NODE_ENDPOINT: - inode->i_mode |= S_IFREG; - inode->i_op = &fs_inode_iops; - inode->i_fop = &kdbus_handle_ops; - break; - } - - unlock_new_inode(inode); - - return inode; -} - -/* - * Superblock Management - */ - -static int fs_super_dop_revalidate(struct dentry *dentry, unsigned int flags) -{ - struct kdbus_node *node; - - /* Force lookup on negatives */ - if (!dentry->d_inode) - return 0; - - node = kdbus_node_from_dentry(dentry); - - /* see whether the node has been removed */ - if (!kdbus_node_is_active(node)) - return 0; - - return 1; -} - -static void fs_super_dop_release(struct dentry *dentry) -{ - kdbus_node_unref(dentry->d_fsdata); -} - -static const struct dentry_operations fs_super_dops = { - .d_revalidate = fs_super_dop_revalidate, - .d_release = fs_super_dop_release, -}; - -static void fs_super_sop_evict_inode(struct inode *inode) -{ - struct kdbus_node *node = kdbus_node_from_inode(inode); - - truncate_inode_pages_final(&inode->i_data); - clear_inode(inode); - kdbus_node_unref(node); -} - -static const struct super_operations fs_super_sops = { - .statfs = simple_statfs, - .drop_inode = generic_delete_inode, - .evict_inode = fs_super_sop_evict_inode, -}; - -static int fs_super_fill(struct super_block *sb) -{ - struct kdbus_domain *domain = sb->s_fs_info; - struct inode *inode; - int ret; - - sb->s_blocksize = PAGE_CACHE_SIZE; - sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = KDBUS_SUPER_MAGIC; - sb->s_maxbytes = MAX_LFS_FILESIZE; - sb->s_op = &fs_super_sops; - sb->s_time_gran = 1; - - inode = fs_inode_get(sb, &domain->node); - if (IS_ERR(inode)) - return PTR_ERR(inode); - - sb->s_root = d_make_root(inode); - if (!sb->s_root) { - /* d_make_root iput()s the inode on failure */ - return -ENOMEM; - } - - /* sb holds domain reference */ - sb->s_root->d_fsdata = &domain->node; - sb->s_d_op = &fs_super_dops; - - /* sb holds root reference */ - domain->dentry = sb->s_root; - - if (!kdbus_node_activate(&domain->node)) - return -ESHUTDOWN; - - ret = kdbus_domain_populate(domain, KDBUS_MAKE_ACCESS_WORLD); - if (ret < 0) - return ret; - - sb->s_flags |= MS_ACTIVE; - return 0; -} - -static void fs_super_kill(struct super_block *sb) -{ - struct kdbus_domain *domain = sb->s_fs_info; - - if (domain) { - kdbus_node_drain(&domain->node); - domain->dentry = NULL; - } - - kill_anon_super(sb); - kdbus_domain_unref(domain); -} - -static int fs_super_set(struct super_block *sb, void *data) -{ - int ret; - - ret = set_anon_super(sb, data); - if (!ret) - sb->s_fs_info = data; - - return ret; -} - -static struct dentry *fs_super_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, - void *data) -{ - struct kdbus_domain *domain; - struct super_block *sb; - int ret; - - domain = kdbus_domain_new(KDBUS_MAKE_ACCESS_WORLD); - if (IS_ERR(domain)) - return ERR_CAST(domain); - - sb = sget(fs_type, NULL, fs_super_set, flags, domain); - if (IS_ERR(sb)) { - kdbus_node_drain(&domain->node); - kdbus_domain_unref(domain); - return ERR_CAST(sb); - } - - WARN_ON(sb->s_fs_info != domain); - WARN_ON(sb->s_root); - - ret = fs_super_fill(sb); - if (ret < 0) { - /* calls into ->kill_sb() when done */ - deactivate_locked_super(sb); - return ERR_PTR(ret); - } - - return dget(sb->s_root); -} - -static struct file_system_type fs_type = { - .name = KBUILD_MODNAME "fs", - .owner = THIS_MODULE, - .mount = fs_super_mount, - .kill_sb = fs_super_kill, - .fs_flags = FS_USERNS_MOUNT, -}; - -/** - * kdbus_fs_init() - register kdbus filesystem - * - * This registers a filesystem with the VFS layer. The filesystem is called - * `KBUILD_MODNAME "fs"', which usually resolves to `kdbusfs'. The nameing - * scheme allows to set KBUILD_MODNAME to "kdbus2" and you will get an - * independent filesystem for developers. - * - * Each mount of the kdbusfs filesystem has an kdbus_domain attached. - * Operations on this mount will only affect the attached domain. On each mount - * a new domain is automatically created and used for this mount exclusively. - * If you want to share a domain across multiple mounts, you need to bind-mount - * it. - * - * Mounts of kdbusfs (with a different domain each) are unrelated to each other - * and will never have any effect on any domain but their own. - * - * Return: 0 on success, negative error otherwise. - */ -int kdbus_fs_init(void) -{ - return register_filesystem(&fs_type); -} - -/** - * kdbus_fs_exit() - unregister kdbus filesystem - * - * This does the reverse to kdbus_fs_init(). It unregisters the kdbusfs - * filesystem from VFS and cleans up any allocated resources. - */ -void kdbus_fs_exit(void) -{ - unregister_filesystem(&fs_type); -} - -/* acquire domain of @node, making sure all ancestors are active */ -static struct kdbus_domain *fs_acquire_domain(struct kdbus_node *node) -{ - struct kdbus_domain *domain; - struct kdbus_node *iter; - - /* caller must guarantee that @node is linked */ - for (iter = node; iter->parent; iter = iter->parent) - if (!kdbus_node_is_active(iter->parent)) - return NULL; - - /* root nodes are always domains */ - if (WARN_ON(iter->type != KDBUS_NODE_DOMAIN)) - return NULL; - - domain = kdbus_domain_from_node(iter); - if (!kdbus_node_acquire(&domain->node)) - return NULL; - - return domain; -} - -/** - * kdbus_fs_flush() - flush dcache entries of a node - * @node: Node to flush entries of - * - * This flushes all VFS filesystem cache entries for a node and all its - * children. This should be called whenever a node is destroyed during - * runtime. It will flush the cache entries so the linked objects can be - * deallocated. - * - * This is a no-op if you call it on active nodes (they really should stay in - * cache) or on nodes with deactivated parents (flushing the parent is enough). - * Furthermore, there is no need to call it on nodes whose lifetime is bound to - * their parents'. In those cases, the parent-flush will always also flush the - * children. - */ -void kdbus_fs_flush(struct kdbus_node *node) -{ - struct dentry *dentry, *parent_dentry = NULL; - struct kdbus_domain *domain; - struct qstr name; - - /* active nodes should remain in cache */ - if (!kdbus_node_is_deactivated(node)) - return; - - /* nodes that were never linked were never instantiated */ - if (!node->parent) - return; - - /* acquire domain and verify all ancestors are active */ - domain = fs_acquire_domain(node); - if (!domain) - return; - - switch (node->type) { - case KDBUS_NODE_ENDPOINT: - if (WARN_ON(!node->parent || !node->parent->name)) - goto exit; - - name.name = node->parent->name; - name.len = strlen(node->parent->name); - parent_dentry = d_hash_and_lookup(domain->dentry, &name); - if (IS_ERR_OR_NULL(parent_dentry)) - goto exit; - - /* fallthrough */ - case KDBUS_NODE_BUS: - if (WARN_ON(!node->name)) - goto exit; - - name.name = node->name; - name.len = strlen(node->name); - dentry = d_hash_and_lookup(parent_dentry ? : domain->dentry, - &name); - if (!IS_ERR_OR_NULL(dentry)) { - d_invalidate(dentry); - dput(dentry); - } - - dput(parent_dentry); - break; - - default: - /* all other types are bound to their parent lifetime */ - break; - } - -exit: - kdbus_node_release(&domain->node); -} diff --git a/ipc/kdbus/fs.h b/ipc/kdbus/fs.h deleted file mode 100644 index 62f7d6abf..000000000 --- a/ipc/kdbus/fs.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUSFS_H -#define __KDBUSFS_H - -#include <linux/kernel.h> - -struct kdbus_node; - -int kdbus_fs_init(void); -void kdbus_fs_exit(void); -void kdbus_fs_flush(struct kdbus_node *node); - -#define kdbus_node_from_inode(_inode) \ - ((struct kdbus_node *)(_inode)->i_private) - -#endif diff --git a/ipc/kdbus/handle.c b/ipc/kdbus/handle.c deleted file mode 100644 index 2f82c2a32..000000000 --- a/ipc/kdbus/handle.c +++ /dev/null @@ -1,691 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/idr.h> -#include <linux/init.h> -#include <linux/kdev_t.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/poll.h> -#include <linux/rwsem.h> -#include <linux/sched.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/syscalls.h> - -#include "bus.h" -#include "connection.h" -#include "endpoint.h" -#include "fs.h" -#include "handle.h" -#include "item.h" -#include "match.h" -#include "message.h" -#include "names.h" -#include "domain.h" -#include "policy.h" - -static int kdbus_args_verify(struct kdbus_args *args) -{ - struct kdbus_item *item; - size_t i; - int ret; - - KDBUS_ITEMS_FOREACH(item, args->items, args->items_size) { - struct kdbus_arg *arg = NULL; - - if (!KDBUS_ITEM_VALID(item, args->items, args->items_size)) - return -EINVAL; - - for (i = 0; i < args->argc; ++i) - if (args->argv[i].type == item->type) - break; - if (i >= args->argc) - return -EINVAL; - - arg = &args->argv[i]; - - ret = kdbus_item_validate(item); - if (ret < 0) - return ret; - - if (arg->item && !arg->multiple) - return -EINVAL; - - arg->item = item; - } - - if (!KDBUS_ITEMS_END(item, args->items, args->items_size)) - return -EINVAL; - - return 0; -} - -static int kdbus_args_negotiate(struct kdbus_args *args) -{ - struct kdbus_item __user *user; - struct kdbus_item *negotiation; - size_t i, j, num; - - /* - * If KDBUS_FLAG_NEGOTIATE is set, we overwrite the flags field with - * the set of supported flags. Furthermore, if an KDBUS_ITEM_NEGOTIATE - * item is passed, we iterate its payload (array of u64, each set to an - * item type) and clear all unsupported item-types to 0. - * The caller might do this recursively, if other flags or objects are - * embedded in the payload itself. - */ - - if (args->cmd->flags & KDBUS_FLAG_NEGOTIATE) { - if (put_user(args->allowed_flags & ~KDBUS_FLAG_NEGOTIATE, - &args->user->flags)) - return -EFAULT; - } - - if (args->argc < 1 || args->argv[0].type != KDBUS_ITEM_NEGOTIATE || - !args->argv[0].item) - return 0; - - negotiation = args->argv[0].item; - user = (struct kdbus_item __user *) - ((u8 __user *)args->user + - ((u8 *)negotiation - (u8 *)args->cmd)); - num = KDBUS_ITEM_PAYLOAD_SIZE(negotiation) / sizeof(u64); - - for (i = 0; i < num; ++i) { - for (j = 0; j < args->argc; ++j) - if (negotiation->data64[i] == args->argv[j].type) - break; - - if (j < args->argc) - continue; - - /* this item is not supported, clear it out */ - negotiation->data64[i] = 0; - if (put_user(negotiation->data64[i], &user->data64[i])) - return -EFAULT; - } - - return 0; -} - -/** - * __kdbus_args_parse() - parse payload of kdbus command - * @args: object to parse data into - * @is_cmd: whether this is a command or msg payload - * @argp: user-space location of command payload to parse - * @type_size: overall size of command payload to parse - * @items_offset: offset of items array in command payload - * @out: output variable to store pointer to copied payload - * - * This parses the ioctl payload at user-space location @argp into @args. @args - * must be pre-initialized by the caller to reflect the supported flags and - * items of this command. This parser will then copy the command payload into - * kernel-space, verify correctness and consistency and cache pointers to parsed - * items and other data in @args. - * - * If this function succeeded, you must call kdbus_args_clear() to release - * allocated resources before destroying @args. - * - * This can also be used to import kdbus_msg objects. In that case, @is_cmd must - * be set to 'false' and the 'return_flags' field will not be touched (as it - * doesn't exist on kdbus_msg). - * - * Return: On failure a negative error code is returned. Otherwise, 1 is - * returned if negotiation was requested, 0 if not. - */ -int __kdbus_args_parse(struct kdbus_args *args, bool is_cmd, void __user *argp, - size_t type_size, size_t items_offset, void **out) -{ - u64 user_size; - int ret, i; - - ret = kdbus_copy_from_user(&user_size, argp, sizeof(user_size)); - if (ret < 0) - return ret; - - if (user_size < type_size) - return -EINVAL; - if (user_size > KDBUS_CMD_MAX_SIZE) - return -EMSGSIZE; - - if (user_size <= sizeof(args->cmd_buf)) { - if (copy_from_user(args->cmd_buf, argp, user_size)) - return -EFAULT; - args->cmd = (void*)args->cmd_buf; - } else { - args->cmd = memdup_user(argp, user_size); - if (IS_ERR(args->cmd)) - return PTR_ERR(args->cmd); - } - - if (args->cmd->size != user_size) { - ret = -EINVAL; - goto error; - } - - if (is_cmd) - args->cmd->return_flags = 0; - args->user = argp; - args->items = (void *)((u8 *)args->cmd + items_offset); - args->items_size = args->cmd->size - items_offset; - args->is_cmd = is_cmd; - - if (args->cmd->flags & ~args->allowed_flags) { - ret = -EINVAL; - goto error; - } - - ret = kdbus_args_verify(args); - if (ret < 0) - goto error; - - ret = kdbus_args_negotiate(args); - if (ret < 0) - goto error; - - /* mandatory items must be given (but not on negotiation) */ - if (!(args->cmd->flags & KDBUS_FLAG_NEGOTIATE)) { - for (i = 0; i < args->argc; ++i) - if (args->argv[i].mandatory && !args->argv[i].item) { - ret = -EINVAL; - goto error; - } - } - - *out = args->cmd; - return !!(args->cmd->flags & KDBUS_FLAG_NEGOTIATE); - -error: - return kdbus_args_clear(args, ret); -} - -/** - * kdbus_args_clear() - release allocated command resources - * @args: object to release resources of - * @ret: return value of this command - * - * This frees all allocated resources on @args and copies the command result - * flags into user-space. @ret is usually returned unchanged by this function, - * so it can be used in the final 'return' statement of the command handler. - * - * Return: -EFAULT if return values cannot be copied into user-space, otherwise - * @ret is returned unchanged. - */ -int kdbus_args_clear(struct kdbus_args *args, int ret) -{ - if (!args) - return ret; - - if (!IS_ERR_OR_NULL(args->cmd)) { - if (args->is_cmd && put_user(args->cmd->return_flags, - &args->user->return_flags)) - ret = -EFAULT; - if (args->cmd != (void*)args->cmd_buf) - kfree(args->cmd); - args->cmd = NULL; - } - - return ret; -} - -/** - * enum kdbus_handle_type - type an handle can be of - * @KDBUS_HANDLE_NONE: no type set, yet - * @KDBUS_HANDLE_BUS_OWNER: bus owner - * @KDBUS_HANDLE_EP_OWNER: endpoint owner - * @KDBUS_HANDLE_CONNECTED: endpoint connection after HELLO - */ -enum kdbus_handle_type { - KDBUS_HANDLE_NONE, - KDBUS_HANDLE_BUS_OWNER, - KDBUS_HANDLE_EP_OWNER, - KDBUS_HANDLE_CONNECTED, -}; - -/** - * struct kdbus_handle - handle to the kdbus system - * @lock: handle lock - * @type: type of this handle (KDBUS_HANDLE_*) - * @bus_owner: bus this handle owns - * @ep_owner: endpoint this handle owns - * @conn: connection this handle owns - */ -struct kdbus_handle { - struct mutex lock; - - enum kdbus_handle_type type; - union { - struct kdbus_bus *bus_owner; - struct kdbus_ep *ep_owner; - struct kdbus_conn *conn; - }; -}; - -static int kdbus_handle_open(struct inode *inode, struct file *file) -{ - struct kdbus_handle *handle; - struct kdbus_node *node; - int ret; - - node = kdbus_node_from_inode(inode); - if (!kdbus_node_acquire(node)) - return -ESHUTDOWN; - - handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (!handle) { - ret = -ENOMEM; - goto exit; - } - - mutex_init(&handle->lock); - handle->type = KDBUS_HANDLE_NONE; - - file->private_data = handle; - ret = 0; - -exit: - kdbus_node_release(node); - return ret; -} - -static int kdbus_handle_release(struct inode *inode, struct file *file) -{ - struct kdbus_handle *handle = file->private_data; - - switch (handle->type) { - case KDBUS_HANDLE_BUS_OWNER: - if (handle->bus_owner) { - kdbus_node_drain(&handle->bus_owner->node); - kdbus_bus_unref(handle->bus_owner); - } - break; - case KDBUS_HANDLE_EP_OWNER: - if (handle->ep_owner) { - kdbus_node_drain(&handle->ep_owner->node); - kdbus_ep_unref(handle->ep_owner); - } - break; - case KDBUS_HANDLE_CONNECTED: - kdbus_conn_disconnect(handle->conn, false); - kdbus_conn_unref(handle->conn); - break; - case KDBUS_HANDLE_NONE: - /* nothing to clean up */ - break; - } - - kfree(handle); - - return 0; -} - -static long kdbus_handle_ioctl_control(struct file *file, unsigned int cmd, - void __user *argp) -{ - struct kdbus_handle *handle = file->private_data; - struct kdbus_node *node = file_inode(file)->i_private; - struct kdbus_domain *domain; - int ret = 0; - - if (!kdbus_node_acquire(node)) - return -ESHUTDOWN; - - /* - * The parent of control-nodes is always a domain, make sure to pin it - * so the parent is actually valid. - */ - domain = kdbus_domain_from_node(node->parent); - if (!kdbus_node_acquire(&domain->node)) { - kdbus_node_release(node); - return -ESHUTDOWN; - } - - switch (cmd) { - case KDBUS_CMD_BUS_MAKE: { - struct kdbus_bus *bus; - - bus = kdbus_cmd_bus_make(domain, argp); - if (IS_ERR_OR_NULL(bus)) { - ret = PTR_ERR_OR_ZERO(bus); - break; - } - - handle->bus_owner = bus; - ret = KDBUS_HANDLE_BUS_OWNER; - break; - } - - default: - ret = -EBADFD; - break; - } - - kdbus_node_release(&domain->node); - kdbus_node_release(node); - return ret; -} - -static long kdbus_handle_ioctl_ep(struct file *file, unsigned int cmd, - void __user *buf) -{ - struct kdbus_handle *handle = file->private_data; - struct kdbus_node *node = file_inode(file)->i_private; - struct kdbus_ep *ep, *file_ep = kdbus_ep_from_node(node); - struct kdbus_bus *bus = file_ep->bus; - struct kdbus_conn *conn; - int ret = 0; - - if (!kdbus_node_acquire(node)) - return -ESHUTDOWN; - - switch (cmd) { - case KDBUS_CMD_ENDPOINT_MAKE: { - /* creating custom endpoints is a privileged operation */ - if (!kdbus_ep_is_owner(file_ep, file)) { - ret = -EPERM; - break; - } - - ep = kdbus_cmd_ep_make(bus, buf); - if (IS_ERR_OR_NULL(ep)) { - ret = PTR_ERR_OR_ZERO(ep); - break; - } - - handle->ep_owner = ep; - ret = KDBUS_HANDLE_EP_OWNER; - break; - } - - case KDBUS_CMD_HELLO: - conn = kdbus_cmd_hello(file_ep, file, buf); - if (IS_ERR_OR_NULL(conn)) { - ret = PTR_ERR_OR_ZERO(conn); - break; - } - - handle->conn = conn; - ret = KDBUS_HANDLE_CONNECTED; - break; - - default: - ret = -EBADFD; - break; - } - - kdbus_node_release(node); - return ret; -} - -static long kdbus_handle_ioctl_ep_owner(struct file *file, unsigned int command, - void __user *buf) -{ - struct kdbus_handle *handle = file->private_data; - struct kdbus_ep *ep = handle->ep_owner; - int ret; - - if (!kdbus_node_acquire(&ep->node)) - return -ESHUTDOWN; - - switch (command) { - case KDBUS_CMD_ENDPOINT_UPDATE: - ret = kdbus_cmd_ep_update(ep, buf); - break; - default: - ret = -EBADFD; - break; - } - - kdbus_node_release(&ep->node); - return ret; -} - -static long kdbus_handle_ioctl_connected(struct file *file, - unsigned int command, void __user *buf) -{ - struct kdbus_handle *handle = file->private_data; - struct kdbus_conn *conn = handle->conn; - struct kdbus_conn *release_conn = NULL; - int ret; - - release_conn = conn; - ret = kdbus_conn_acquire(release_conn); - if (ret < 0) - return ret; - - switch (command) { - case KDBUS_CMD_BYEBYE: - /* - * BYEBYE is special; we must not acquire a connection when - * calling into kdbus_conn_disconnect() or we will deadlock, - * because kdbus_conn_disconnect() will wait for all acquired - * references to be dropped. - */ - kdbus_conn_release(release_conn); - release_conn = NULL; - ret = kdbus_cmd_byebye_unlocked(conn, buf); - break; - case KDBUS_CMD_NAME_ACQUIRE: - ret = kdbus_cmd_name_acquire(conn, buf); - break; - case KDBUS_CMD_NAME_RELEASE: - ret = kdbus_cmd_name_release(conn, buf); - break; - case KDBUS_CMD_LIST: - ret = kdbus_cmd_list(conn, buf); - break; - case KDBUS_CMD_CONN_INFO: - ret = kdbus_cmd_conn_info(conn, buf); - break; - case KDBUS_CMD_BUS_CREATOR_INFO: - ret = kdbus_cmd_bus_creator_info(conn, buf); - break; - case KDBUS_CMD_UPDATE: - ret = kdbus_cmd_update(conn, buf); - break; - case KDBUS_CMD_MATCH_ADD: - ret = kdbus_cmd_match_add(conn, buf); - break; - case KDBUS_CMD_MATCH_REMOVE: - ret = kdbus_cmd_match_remove(conn, buf); - break; - case KDBUS_CMD_SEND: - ret = kdbus_cmd_send(conn, file, buf); - break; - case KDBUS_CMD_RECV: - ret = kdbus_cmd_recv(conn, buf); - break; - case KDBUS_CMD_FREE: - ret = kdbus_cmd_free(conn, buf); - break; - default: - ret = -EBADFD; - break; - } - - kdbus_conn_release(release_conn); - return ret; -} - -static long kdbus_handle_ioctl(struct file *file, unsigned int cmd, - unsigned long arg) -{ - struct kdbus_handle *handle = file->private_data; - struct kdbus_node *node = kdbus_node_from_inode(file_inode(file)); - void __user *argp = (void __user *)arg; - long ret = -EBADFD; - - switch (cmd) { - case KDBUS_CMD_BUS_MAKE: - case KDBUS_CMD_ENDPOINT_MAKE: - case KDBUS_CMD_HELLO: - mutex_lock(&handle->lock); - if (handle->type == KDBUS_HANDLE_NONE) { - if (node->type == KDBUS_NODE_CONTROL) - ret = kdbus_handle_ioctl_control(file, cmd, - argp); - else if (node->type == KDBUS_NODE_ENDPOINT) - ret = kdbus_handle_ioctl_ep(file, cmd, argp); - - if (ret > 0) { - /* - * The data given via open() is not sufficient - * to setup a kdbus handle. Hence, we require - * the user to perform a setup ioctl. This setup - * can only be performed once and defines the - * type of the handle. The different setup - * ioctls are locked against each other so they - * cannot race. Once the handle type is set, - * the type-dependent ioctls are enabled. To - * improve performance, we don't lock those via - * handle->lock. Instead, we issue a - * write-barrier before performing the - * type-change, which pairs with smp_rmb() in - * all handlers that access the type field. This - * guarantees the handle is fully setup, if - * handle->type is set. If handle->type is - * unset, you must not make any assumptions - * without taking handle->lock. - * Note that handle->type is only set once. It - * will never change afterwards. - */ - smp_wmb(); - handle->type = ret; - } - } - mutex_unlock(&handle->lock); - break; - - case KDBUS_CMD_ENDPOINT_UPDATE: - case KDBUS_CMD_BYEBYE: - case KDBUS_CMD_NAME_ACQUIRE: - case KDBUS_CMD_NAME_RELEASE: - case KDBUS_CMD_LIST: - case KDBUS_CMD_CONN_INFO: - case KDBUS_CMD_BUS_CREATOR_INFO: - case KDBUS_CMD_UPDATE: - case KDBUS_CMD_MATCH_ADD: - case KDBUS_CMD_MATCH_REMOVE: - case KDBUS_CMD_SEND: - case KDBUS_CMD_RECV: - case KDBUS_CMD_FREE: { - enum kdbus_handle_type type; - - /* - * This read-barrier pairs with smp_wmb() of the handle setup. - * it guarantees the handle is fully written, in case the - * type has been set. It allows us to access the handle without - * taking handle->lock, given the guarantee that the type is - * only ever set once, and stays constant afterwards. - * Furthermore, the handle object itself is not modified in any - * way after the type is set. That is, the type-field is the - * last field that is written on any handle. If it has not been - * set, we must not access the handle here. - */ - type = handle->type; - smp_rmb(); - - if (type == KDBUS_HANDLE_EP_OWNER) - ret = kdbus_handle_ioctl_ep_owner(file, cmd, argp); - else if (type == KDBUS_HANDLE_CONNECTED) - ret = kdbus_handle_ioctl_connected(file, cmd, argp); - - break; - } - default: - ret = -ENOTTY; - break; - } - - return ret < 0 ? ret : 0; -} - -static unsigned int kdbus_handle_poll(struct file *file, - struct poll_table_struct *wait) -{ - struct kdbus_handle *handle = file->private_data; - enum kdbus_handle_type type; - unsigned int mask = POLLOUT | POLLWRNORM; - - /* - * This pairs with smp_wmb() during handle setup. It guarantees that - * _iff_ the handle type is set, handle->conn is valid. Furthermore, - * _iff_ the type is set, the handle object is constant and never - * changed again. If it's not set, we must not access the handle but - * bail out. We also must assume no setup has taken place, yet. - */ - type = handle->type; - smp_rmb(); - - /* Only a connected endpoint can read/write data */ - if (type != KDBUS_HANDLE_CONNECTED) - return POLLERR | POLLHUP; - - poll_wait(file, &handle->conn->wait, wait); - - /* - * Verify the connection hasn't been deactivated _after_ adding the - * wait-queue. This guarantees, that if the connection is deactivated - * after we checked it, the waitqueue is signaled and we're called - * again. - */ - if (!kdbus_conn_active(handle->conn)) - return POLLERR | POLLHUP; - - if (!list_empty(&handle->conn->queue.msg_list) || - atomic_read(&handle->conn->lost_count) > 0) - mask |= POLLIN | POLLRDNORM; - - return mask; -} - -static int kdbus_handle_mmap(struct file *file, struct vm_area_struct *vma) -{ - struct kdbus_handle *handle = file->private_data; - enum kdbus_handle_type type; - int ret = -EBADFD; - - /* - * This pairs with smp_wmb() during handle setup. It guarantees that - * _iff_ the handle type is set, handle->conn is valid. Furthermore, - * _iff_ the type is set, the handle object is constant and never - * changed again. If it's not set, we must not access the handle but - * bail out. We also must assume no setup has taken place, yet. - */ - type = handle->type; - smp_rmb(); - - /* Only connected handles have a pool we can map */ - if (type == KDBUS_HANDLE_CONNECTED) - ret = kdbus_pool_mmap(handle->conn->pool, vma); - - return ret; -} - -const struct file_operations kdbus_handle_ops = { - .owner = THIS_MODULE, - .open = kdbus_handle_open, - .release = kdbus_handle_release, - .poll = kdbus_handle_poll, - .llseek = noop_llseek, - .unlocked_ioctl = kdbus_handle_ioctl, - .mmap = kdbus_handle_mmap, -#ifdef CONFIG_COMPAT - .compat_ioctl = kdbus_handle_ioctl, -#endif -}; diff --git a/ipc/kdbus/handle.h b/ipc/kdbus/handle.h deleted file mode 100644 index 5dde2c10b..000000000 --- a/ipc/kdbus/handle.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_HANDLE_H -#define __KDBUS_HANDLE_H - -#include <linux/fs.h> -#include <uapi/linux/kdbus.h> - -extern const struct file_operations kdbus_handle_ops; - -/** - * kdbus_arg - information and state of a single ioctl command item - * @type: item type - * @item: set by the parser to the first found item of this type - * @multiple: whether multiple items of this type are allowed - * @mandatory: whether at least one item of this type is required - * - * This structure describes a single item in an ioctl command payload. The - * caller has to pre-fill the type and flags, the parser will then use this - * information to verify the ioctl payload. @item is set by the parser to point - * to the first occurrence of the item. - */ -struct kdbus_arg { - u64 type; - struct kdbus_item *item; - bool multiple : 1; - bool mandatory : 1; -}; - -/** - * kdbus_args - information and state of ioctl command parser - * @allowed_flags: set of flags this command supports - * @argc: number of items in @argv - * @argv: array of items this command supports - * @user: set by parser to user-space location of current command - * @cmd: set by parser to kernel copy of command payload - * @cmd_buf: inline buf to avoid kmalloc() on small cmds - * @items: points to item array in @cmd - * @items_size: size of @items in bytes - * @is_cmd: whether this is a command-payload or msg-payload - * - * This structure is used to parse ioctl command payloads on each invocation. - * The ioctl handler has to pre-fill the flags and allowed items before passing - * the object to kdbus_args_parse(). The parser will copy the command payload - * into kernel-space and verify the correctness of the data. - * - * We use a 256 bytes buffer for small command payloads, to be allocated on - * stack on syscall entrance. - */ -struct kdbus_args { - u64 allowed_flags; - size_t argc; - struct kdbus_arg *argv; - - struct kdbus_cmd __user *user; - struct kdbus_cmd *cmd; - u8 cmd_buf[256]; - - struct kdbus_item *items; - size_t items_size; - bool is_cmd : 1; -}; - -int __kdbus_args_parse(struct kdbus_args *args, bool is_cmd, void __user *argp, - size_t type_size, size_t items_offset, void **out); -int kdbus_args_clear(struct kdbus_args *args, int ret); - -#define kdbus_args_parse(_args, _argp, _v) \ - ({ \ - BUILD_BUG_ON(offsetof(typeof(**(_v)), size) != \ - offsetof(struct kdbus_cmd, size)); \ - BUILD_BUG_ON(offsetof(typeof(**(_v)), flags) != \ - offsetof(struct kdbus_cmd, flags)); \ - BUILD_BUG_ON(offsetof(typeof(**(_v)), return_flags) != \ - offsetof(struct kdbus_cmd, return_flags)); \ - __kdbus_args_parse((_args), 1, (_argp), sizeof(**(_v)), \ - offsetof(typeof(**(_v)), items), \ - (void **)(_v)); \ - }) - -#define kdbus_args_parse_msg(_args, _argp, _v) \ - ({ \ - BUILD_BUG_ON(offsetof(typeof(**(_v)), size) != \ - offsetof(struct kdbus_cmd, size)); \ - BUILD_BUG_ON(offsetof(typeof(**(_v)), flags) != \ - offsetof(struct kdbus_cmd, flags)); \ - __kdbus_args_parse((_args), 0, (_argp), sizeof(**(_v)), \ - offsetof(typeof(**(_v)), items), \ - (void **)(_v)); \ - }) - -#endif diff --git a/ipc/kdbus/item.c b/ipc/kdbus/item.c deleted file mode 100644 index ce78dba03..000000000 --- a/ipc/kdbus/item.c +++ /dev/null @@ -1,293 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/ctype.h> -#include <linux/fs.h> -#include <linux/string.h> - -#include "item.h" -#include "limits.h" -#include "util.h" - -/* - * This verifies the string at position @str with size @size is properly - * zero-terminated and does not contain a 0-byte but at the end. - */ -static bool kdbus_str_valid(const char *str, size_t size) -{ - return size > 0 && memchr(str, '\0', size) == str + size - 1; -} - -/** - * kdbus_item_validate_name() - validate an item containing a name - * @item: Item to validate - * - * Return: zero on success or an negative error code on failure - */ -int kdbus_item_validate_name(const struct kdbus_item *item) -{ - const char *name = item->str; - unsigned int i; - size_t len; - - if (item->size < KDBUS_ITEM_HEADER_SIZE + 2) - return -EINVAL; - - if (item->size > KDBUS_ITEM_HEADER_SIZE + - KDBUS_SYSNAME_MAX_LEN + 1) - return -ENAMETOOLONG; - - if (!kdbus_str_valid(name, KDBUS_ITEM_PAYLOAD_SIZE(item))) - return -EINVAL; - - len = strlen(name); - if (len == 0) - return -EINVAL; - - for (i = 0; i < len; i++) { - if (isalpha(name[i])) - continue; - if (isdigit(name[i])) - continue; - if (name[i] == '_') - continue; - if (i > 0 && i + 1 < len && (name[i] == '-' || name[i] == '.')) - continue; - - return -EINVAL; - } - - return 0; -} - -/** - * kdbus_item_validate() - validate a single item - * @item: item to validate - * - * Return: 0 if item is valid, negative error code if not. - */ -int kdbus_item_validate(const struct kdbus_item *item) -{ - size_t payload_size = KDBUS_ITEM_PAYLOAD_SIZE(item); - size_t l; - int ret; - - BUILD_BUG_ON(KDBUS_ITEM_HEADER_SIZE != - sizeof(struct kdbus_item_header)); - - if (item->size < KDBUS_ITEM_HEADER_SIZE) - return -EINVAL; - - switch (item->type) { - case KDBUS_ITEM_NEGOTIATE: - if (payload_size % sizeof(u64) != 0) - return -EINVAL; - break; - - case KDBUS_ITEM_PAYLOAD_VEC: - case KDBUS_ITEM_PAYLOAD_OFF: - if (payload_size != sizeof(struct kdbus_vec)) - return -EINVAL; - if (item->vec.size == 0 || item->vec.size > SIZE_MAX) - return -EINVAL; - break; - - case KDBUS_ITEM_PAYLOAD_MEMFD: - if (payload_size != sizeof(struct kdbus_memfd)) - return -EINVAL; - if (item->memfd.size == 0 || item->memfd.size > SIZE_MAX) - return -EINVAL; - if (item->memfd.fd < 0) - return -EBADF; - break; - - case KDBUS_ITEM_FDS: - if (payload_size % sizeof(int) != 0) - return -EINVAL; - break; - - case KDBUS_ITEM_CANCEL_FD: - if (payload_size != sizeof(int)) - return -EINVAL; - break; - - case KDBUS_ITEM_BLOOM_PARAMETER: - if (payload_size != sizeof(struct kdbus_bloom_parameter)) - return -EINVAL; - break; - - case KDBUS_ITEM_BLOOM_FILTER: - /* followed by the bloom-mask, depends on the bloom-size */ - if (payload_size < sizeof(struct kdbus_bloom_filter)) - return -EINVAL; - break; - - case KDBUS_ITEM_BLOOM_MASK: - /* size depends on bloom-size of bus */ - break; - - case KDBUS_ITEM_CONN_DESCRIPTION: - case KDBUS_ITEM_MAKE_NAME: - ret = kdbus_item_validate_name(item); - if (ret < 0) - return ret; - break; - - case KDBUS_ITEM_ATTACH_FLAGS_SEND: - case KDBUS_ITEM_ATTACH_FLAGS_RECV: - case KDBUS_ITEM_ID: - case KDBUS_ITEM_DST_ID: - if (payload_size != sizeof(u64)) - return -EINVAL; - break; - - case KDBUS_ITEM_TIMESTAMP: - if (payload_size != sizeof(struct kdbus_timestamp)) - return -EINVAL; - break; - - case KDBUS_ITEM_CREDS: - if (payload_size != sizeof(struct kdbus_creds)) - return -EINVAL; - break; - - case KDBUS_ITEM_AUXGROUPS: - if (payload_size % sizeof(u32) != 0) - return -EINVAL; - break; - - case KDBUS_ITEM_NAME: - case KDBUS_ITEM_DST_NAME: - case KDBUS_ITEM_PID_COMM: - case KDBUS_ITEM_TID_COMM: - case KDBUS_ITEM_EXE: - case KDBUS_ITEM_CMDLINE: - case KDBUS_ITEM_CGROUP: - case KDBUS_ITEM_SECLABEL: - if (!kdbus_str_valid(item->str, payload_size)) - return -EINVAL; - break; - - case KDBUS_ITEM_CAPS: - if (payload_size < sizeof(u32)) - return -EINVAL; - if (payload_size < sizeof(u32) + - 4 * CAP_TO_INDEX(item->caps.last_cap) * sizeof(u32)) - return -EINVAL; - break; - - case KDBUS_ITEM_AUDIT: - if (payload_size != sizeof(struct kdbus_audit)) - return -EINVAL; - break; - - case KDBUS_ITEM_POLICY_ACCESS: - if (payload_size != sizeof(struct kdbus_policy_access)) - return -EINVAL; - break; - - case KDBUS_ITEM_NAME_ADD: - case KDBUS_ITEM_NAME_REMOVE: - case KDBUS_ITEM_NAME_CHANGE: - if (payload_size < sizeof(struct kdbus_notify_name_change)) - return -EINVAL; - l = payload_size - offsetof(struct kdbus_notify_name_change, - name); - if (l > 0 && !kdbus_str_valid(item->name_change.name, l)) - return -EINVAL; - break; - - case KDBUS_ITEM_ID_ADD: - case KDBUS_ITEM_ID_REMOVE: - if (payload_size != sizeof(struct kdbus_notify_id_change)) - return -EINVAL; - break; - - case KDBUS_ITEM_REPLY_TIMEOUT: - case KDBUS_ITEM_REPLY_DEAD: - if (payload_size != 0) - return -EINVAL; - break; - - default: - break; - } - - return 0; -} - -/** - * kdbus_items_validate() - validate items passed by user-space - * @items: items to validate - * @items_size: number of items - * - * This verifies that the passed items pointer is consistent and valid. - * Furthermore, each item is checked for: - * - valid "size" value - * - payload is of expected type - * - payload is fully included in the item - * - string payloads are zero-terminated - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_items_validate(const struct kdbus_item *items, size_t items_size) -{ - const struct kdbus_item *item; - int ret; - - KDBUS_ITEMS_FOREACH(item, items, items_size) { - if (!KDBUS_ITEM_VALID(item, items, items_size)) - return -EINVAL; - - ret = kdbus_item_validate(item); - if (ret < 0) - return ret; - } - - if (!KDBUS_ITEMS_END(item, items, items_size)) - return -EINVAL; - - return 0; -} - -/** - * kdbus_item_set() - Set item content - * @item: The item to modify - * @type: The item type to set (KDBUS_ITEM_*) - * @data: Data to copy to item->data, may be %NULL - * @len: Number of bytes in @data - * - * This sets type, size and data fields of an item. If @data is NULL, the data - * memory is cleared. - * - * Note that you must align your @data memory to 8 bytes. Trailing padding (in - * case @len is not 8byte aligned) is cleared by this call. - * - * Returns: Pointer to the following item. - */ -struct kdbus_item *kdbus_item_set(struct kdbus_item *item, u64 type, - const void *data, size_t len) -{ - item->type = type; - item->size = KDBUS_ITEM_HEADER_SIZE + len; - - if (data) { - memcpy(item->data, data, len); - memset(item->data + len, 0, KDBUS_ALIGN8(len) - len); - } else { - memset(item->data, 0, KDBUS_ALIGN8(len)); - } - - return KDBUS_ITEM_NEXT(item); -} diff --git a/ipc/kdbus/item.h b/ipc/kdbus/item.h deleted file mode 100644 index 3a7e6ccc2..000000000 --- a/ipc/kdbus/item.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_ITEM_H -#define __KDBUS_ITEM_H - -#include <linux/kernel.h> -#include <uapi/linux/kdbus.h> - -#include "util.h" - -/* generic access and iterators over a stream of items */ -#define KDBUS_ITEM_NEXT(_i) (typeof(_i))((u8 *)(_i) + KDBUS_ALIGN8((_i)->size)) -#define KDBUS_ITEMS_SIZE(_h, _is) ((_h)->size - offsetof(typeof(*(_h)), _is)) -#define KDBUS_ITEM_HEADER_SIZE offsetof(struct kdbus_item, data) -#define KDBUS_ITEM_SIZE(_s) KDBUS_ALIGN8(KDBUS_ITEM_HEADER_SIZE + (_s)) -#define KDBUS_ITEM_PAYLOAD_SIZE(_i) ((_i)->size - KDBUS_ITEM_HEADER_SIZE) - -#define KDBUS_ITEMS_FOREACH(_i, _is, _s) \ - for ((_i) = (_is); \ - ((u8 *)(_i) < (u8 *)(_is) + (_s)) && \ - ((u8 *)(_i) >= (u8 *)(_is)); \ - (_i) = KDBUS_ITEM_NEXT(_i)) - -#define KDBUS_ITEM_VALID(_i, _is, _s) \ - ((_i)->size >= KDBUS_ITEM_HEADER_SIZE && \ - (u8 *)(_i) + (_i)->size > (u8 *)(_i) && \ - (u8 *)(_i) + (_i)->size <= (u8 *)(_is) + (_s) && \ - (u8 *)(_i) >= (u8 *)(_is)) - -#define KDBUS_ITEMS_END(_i, _is, _s) \ - ((u8 *)(_i) == ((u8 *)(_is) + KDBUS_ALIGN8(_s))) - -/** - * struct kdbus_item_header - Describes the fix part of an item - * @size: The total size of the item - * @type: The item type, one of KDBUS_ITEM_* - */ -struct kdbus_item_header { - u64 size; - u64 type; -}; - -int kdbus_item_validate_name(const struct kdbus_item *item); -int kdbus_item_validate(const struct kdbus_item *item); -int kdbus_items_validate(const struct kdbus_item *items, size_t items_size); -struct kdbus_item *kdbus_item_set(struct kdbus_item *item, u64 type, - const void *data, size_t len); - -#endif diff --git a/ipc/kdbus/limits.h b/ipc/kdbus/limits.h deleted file mode 100644 index bd47119cd..000000000 --- a/ipc/kdbus/limits.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_DEFAULTS_H -#define __KDBUS_DEFAULTS_H - -#include <linux/kernel.h> - -/* maximum size of message header and items */ -#define KDBUS_MSG_MAX_SIZE SZ_8K - -/* maximum number of memfd items per message */ -#define KDBUS_MSG_MAX_MEMFD_ITEMS 16 - -/* max size of ioctl command data */ -#define KDBUS_CMD_MAX_SIZE SZ_32K - -/* maximum number of inflight fds in a target queue per user */ -#define KDBUS_CONN_MAX_FDS_PER_USER 16 - -/* maximum message payload size */ -#define KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE SZ_2M - -/* maximum size of bloom bit field in bytes */ -#define KDBUS_BUS_BLOOM_MAX_SIZE SZ_4K - -/* maximum length of well-known bus name */ -#define KDBUS_NAME_MAX_LEN 255 - -/* maximum length of bus, domain, ep name */ -#define KDBUS_SYSNAME_MAX_LEN 63 - -/* maximum number of matches per connection */ -#define KDBUS_MATCH_MAX 4096 - -/* maximum number of queued messages from the same individual user */ -#define KDBUS_CONN_MAX_MSGS 256 - -/* maximum number of well-known names per connection */ -#define KDBUS_CONN_MAX_NAMES 256 - -/* maximum number of queued requests waiting for a reply */ -#define KDBUS_CONN_MAX_REQUESTS_PENDING 128 - -/* maximum number of connections per user in one domain */ -#define KDBUS_USER_MAX_CONN 1024 - -/* maximum number of buses per user in one domain */ -#define KDBUS_USER_MAX_BUSES 16 - -#endif diff --git a/ipc/kdbus/main.c b/ipc/kdbus/main.c deleted file mode 100644 index c2117ea53..000000000 --- a/ipc/kdbus/main.c +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -#include <linux/fs.h> -#include <linux/init.h> -#include <linux/module.h> - -#include "util.h" -#include "fs.h" -#include "handle.h" -#include "metadata.h" -#include "node.h" - -/* - * This is a simplified outline of the internal kdbus object relations, for - * those interested in the inner life of the driver implementation. - * - * From a mount point's (domain's) perspective: - * - * struct kdbus_domain - * |» struct kdbus_user *user (many, owned) - * '» struct kdbus_node node (embedded) - * |» struct kdbus_node children (many, referenced) - * |» struct kdbus_node *parent (pinned) - * '» struct kdbus_bus (many, pinned) - * |» struct kdbus_node node (embedded) - * '» struct kdbus_ep (many, pinned) - * |» struct kdbus_node node (embedded) - * |» struct kdbus_bus *bus (pinned) - * |» struct kdbus_conn conn_list (many, pinned) - * | |» struct kdbus_ep *ep (pinned) - * | |» struct kdbus_name_entry *activator_of (owned) - * | |» struct kdbus_match_db *match_db (owned) - * | |» struct kdbus_meta *meta (owned) - * | |» struct kdbus_match_db *match_db (owned) - * | | '» struct kdbus_match_entry (many, owned) - * | | - * | |» struct kdbus_pool *pool (owned) - * | | '» struct kdbus_pool_slice *slices (many, owned) - * | | '» struct kdbus_pool *pool (pinned) - * | | - * | |» struct kdbus_user *user (pinned) - * | `» struct kdbus_queue_entry entries (many, embedded) - * | |» struct kdbus_pool_slice *slice (pinned) - * | |» struct kdbus_conn_reply *reply (owned) - * | '» struct kdbus_user *user (pinned) - * | - * '» struct kdbus_user *user (pinned) - * '» struct kdbus_policy_db policy_db (embedded) - * |» struct kdbus_policy_db_entry (many, owned) - * | |» struct kdbus_conn (pinned) - * | '» struct kdbus_ep (pinned) - * | - * '» struct kdbus_policy_db_cache_entry (many, owned) - * '» struct kdbus_conn (pinned) - * - * For the life-time of a file descriptor derived from calling open() on a file - * inside the mount point: - * - * struct kdbus_handle - * |» struct kdbus_meta *meta (owned) - * |» struct kdbus_ep *ep (pinned) - * |» struct kdbus_conn *conn (owned) - * '» struct kdbus_ep *ep (owned) - */ - -static int __init kdbus_init(void) -{ - int ret; - - ret = sysfs_create_mount_point(fs_kobj, KBUILD_MODNAME); - if (ret) - return ret; - - ret = kdbus_fs_init(); - if (ret < 0) { - pr_err("cannot register filesystem: %d\n", ret); - goto exit_dir; - } - - pr_info("initialized\n"); - return 0; - -exit_dir: - sysfs_remove_mount_point(fs_kobj, KBUILD_MODNAME); - return ret; -} - -static void __exit kdbus_exit(void) -{ - kdbus_fs_exit(); - sysfs_remove_mount_point(fs_kobj, KBUILD_MODNAME); - ida_destroy(&kdbus_node_ida); -} - -module_init(kdbus_init); -module_exit(kdbus_exit); -MODULE_LICENSE("GPL"); -MODULE_DESCRIPTION("D-Bus, powerful, easy to use interprocess communication"); -MODULE_ALIAS_FS(KBUILD_MODNAME "fs"); diff --git a/ipc/kdbus/match.c b/ipc/kdbus/match.c deleted file mode 100644 index 4ee6a1f2e..000000000 --- a/ipc/kdbus/match.c +++ /dev/null @@ -1,546 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/fs.h> -#include <linux/hash.h> -#include <linux/init.h> -#include <linux/mutex.h> -#include <linux/sched.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/uaccess.h> - -#include "bus.h" -#include "connection.h" -#include "endpoint.h" -#include "handle.h" -#include "item.h" -#include "match.h" -#include "message.h" -#include "names.h" - -/** - * struct kdbus_match_db - message filters - * @entries_list: List of matches - * @mdb_rwlock: Match data lock - * @entries_count: Number of entries in database - */ -struct kdbus_match_db { - struct list_head entries_list; - struct rw_semaphore mdb_rwlock; - unsigned int entries_count; -}; - -/** - * struct kdbus_match_entry - a match database entry - * @cookie: User-supplied cookie to lookup the entry - * @list_entry: The list entry element for the db list - * @rules_list: The list head for tracking rules of this entry - */ -struct kdbus_match_entry { - u64 cookie; - struct list_head list_entry; - struct list_head rules_list; -}; - -/** - * struct kdbus_bloom_mask - mask to match against filter - * @generations: Number of generations carried - * @data: Array of bloom bit fields - */ -struct kdbus_bloom_mask { - u64 generations; - u64 *data; -}; - -/** - * struct kdbus_match_rule - a rule appended to a match entry - * @type: An item type to match against - * @bloom_mask: Bloom mask to match a message's filter against, used - * with KDBUS_ITEM_BLOOM_MASK - * @name: Name to match against, used with KDBUS_ITEM_NAME, - * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE} - * @old_id: ID to match against, used with - * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}, - * KDBUS_ITEM_ID_REMOVE - * @new_id: ID to match against, used with - * KDBUS_ITEM_NAME_{ADD,REMOVE,CHANGE}, - * KDBUS_ITEM_ID_REMOVE - * @src_id: ID to match against, used with KDBUS_ITEM_ID - * @dst_id: Message destination ID, used with KDBUS_ITEM_DST_ID - * @rules_entry: Entry in the entry's rules list - */ -struct kdbus_match_rule { - u64 type; - union { - struct kdbus_bloom_mask bloom_mask; - struct { - char *name; - u64 old_id; - u64 new_id; - }; - u64 src_id; - u64 dst_id; - }; - struct list_head rules_entry; -}; - -static void kdbus_match_rule_free(struct kdbus_match_rule *rule) -{ - if (!rule) - return; - - switch (rule->type) { - case KDBUS_ITEM_BLOOM_MASK: - kfree(rule->bloom_mask.data); - break; - - case KDBUS_ITEM_NAME: - case KDBUS_ITEM_NAME_ADD: - case KDBUS_ITEM_NAME_REMOVE: - case KDBUS_ITEM_NAME_CHANGE: - kfree(rule->name); - break; - - case KDBUS_ITEM_ID: - case KDBUS_ITEM_DST_ID: - case KDBUS_ITEM_ID_ADD: - case KDBUS_ITEM_ID_REMOVE: - break; - - default: - BUG(); - } - - list_del(&rule->rules_entry); - kfree(rule); -} - -static void kdbus_match_entry_free(struct kdbus_match_entry *entry) -{ - struct kdbus_match_rule *r, *tmp; - - if (!entry) - return; - - list_for_each_entry_safe(r, tmp, &entry->rules_list, rules_entry) - kdbus_match_rule_free(r); - - list_del(&entry->list_entry); - kfree(entry); -} - -/** - * kdbus_match_db_free() - free match db resources - * @mdb: The match database - */ -void kdbus_match_db_free(struct kdbus_match_db *mdb) -{ - struct kdbus_match_entry *entry, *tmp; - - if (!mdb) - return; - - list_for_each_entry_safe(entry, tmp, &mdb->entries_list, list_entry) - kdbus_match_entry_free(entry); - - kfree(mdb); -} - -/** - * kdbus_match_db_new() - create a new match database - * - * Return: a new kdbus_match_db on success, ERR_PTR on failure. - */ -struct kdbus_match_db *kdbus_match_db_new(void) -{ - struct kdbus_match_db *d; - - d = kzalloc(sizeof(*d), GFP_KERNEL); - if (!d) - return ERR_PTR(-ENOMEM); - - init_rwsem(&d->mdb_rwlock); - INIT_LIST_HEAD(&d->entries_list); - - return d; -} - -static bool kdbus_match_bloom(const struct kdbus_bloom_filter *filter, - const struct kdbus_bloom_mask *mask, - const struct kdbus_conn *conn) -{ - size_t n = conn->ep->bus->bloom.size / sizeof(u64); - const u64 *m; - size_t i; - - /* - * The message's filter carries a generation identifier, the - * match's mask possibly carries an array of multiple generations - * of the mask. Select the mask with the closest match of the - * filter's generation. - */ - m = mask->data + (min(filter->generation, mask->generations - 1) * n); - - /* - * The message's filter contains the messages properties, - * the match's mask contains the properties to look for in the - * message. Check the mask bit field against the filter bit field, - * if the message possibly carries the properties the connection - * has subscribed to. - */ - for (i = 0; i < n; i++) - if ((filter->data[i] & m[i]) != m[i]) - return false; - - return true; -} - -static bool kdbus_match_rule_conn(const struct kdbus_match_rule *r, - struct kdbus_conn *c, - const struct kdbus_staging *s) -{ - lockdep_assert_held(&c->ep->bus->name_registry->rwlock); - - switch (r->type) { - case KDBUS_ITEM_BLOOM_MASK: - return kdbus_match_bloom(s->bloom_filter, &r->bloom_mask, c); - case KDBUS_ITEM_ID: - return r->src_id == c->id || r->src_id == KDBUS_MATCH_ID_ANY; - case KDBUS_ITEM_DST_ID: - return r->dst_id == s->msg->dst_id || - r->dst_id == KDBUS_MATCH_ID_ANY; - case KDBUS_ITEM_NAME: - return kdbus_conn_has_name(c, r->name); - default: - return false; - } -} - -static bool kdbus_match_rule_kernel(const struct kdbus_match_rule *r, - const struct kdbus_staging *s) -{ - struct kdbus_item *n = s->notify; - - if (WARN_ON(!n) || n->type != r->type) - return false; - - switch (r->type) { - case KDBUS_ITEM_ID_ADD: - return r->new_id == KDBUS_MATCH_ID_ANY || - r->new_id == n->id_change.id; - case KDBUS_ITEM_ID_REMOVE: - return r->old_id == KDBUS_MATCH_ID_ANY || - r->old_id == n->id_change.id; - case KDBUS_ITEM_NAME_ADD: - case KDBUS_ITEM_NAME_CHANGE: - case KDBUS_ITEM_NAME_REMOVE: - return (r->old_id == KDBUS_MATCH_ID_ANY || - r->old_id == n->name_change.old_id.id) && - (r->new_id == KDBUS_MATCH_ID_ANY || - r->new_id == n->name_change.new_id.id) && - (!r->name || !strcmp(r->name, n->name_change.name)); - default: - return false; - } -} - -static bool kdbus_match_rules(const struct kdbus_match_entry *entry, - struct kdbus_conn *c, - const struct kdbus_staging *s) -{ - struct kdbus_match_rule *r; - - list_for_each_entry(r, &entry->rules_list, rules_entry) - if ((c && !kdbus_match_rule_conn(r, c, s)) || - (!c && !kdbus_match_rule_kernel(r, s))) - return false; - - return true; -} - -/** - * kdbus_match_db_match_msg() - match a msg object agains the database entries - * @mdb: The match database - * @conn_src: The connection object originating the message - * @staging: Staging object containing the message to match against - * - * This function will walk through all the database entries previously uploaded - * with kdbus_match_db_add(). As soon as any of them has an all-satisfied rule - * set, this function will return true. - * - * The caller must hold the registry lock of conn_src->ep->bus, in case conn_src - * is non-NULL. - * - * Return: true if there was a matching database entry, false otherwise. - */ -bool kdbus_match_db_match_msg(struct kdbus_match_db *mdb, - struct kdbus_conn *conn_src, - const struct kdbus_staging *staging) -{ - struct kdbus_match_entry *entry; - bool matched = false; - - down_read(&mdb->mdb_rwlock); - list_for_each_entry(entry, &mdb->entries_list, list_entry) { - matched = kdbus_match_rules(entry, conn_src, staging); - if (matched) - break; - } - up_read(&mdb->mdb_rwlock); - - return matched; -} - -static int kdbus_match_db_remove_unlocked(struct kdbus_match_db *mdb, - u64 cookie) -{ - struct kdbus_match_entry *entry, *tmp; - bool found = false; - - list_for_each_entry_safe(entry, tmp, &mdb->entries_list, list_entry) - if (entry->cookie == cookie) { - kdbus_match_entry_free(entry); - --mdb->entries_count; - found = true; - } - - return found ? 0 : -EBADSLT; -} - -/** - * kdbus_cmd_match_add() - handle KDBUS_CMD_MATCH_ADD - * @conn: connection to operate on - * @argp: command payload - * - * One call to this function (or one ioctl(KDBUS_CMD_MATCH_ADD), respectively, - * adds one new database entry with n rules attached to it. Each rule is - * described with an kdbus_item, and an entry is considered matching if all - * its rules are satisfied. - * - * The items attached to a kdbus_cmd_match struct have the following mapping: - * - * KDBUS_ITEM_BLOOM_MASK: A bloom mask - * KDBUS_ITEM_NAME: A connection's source name - * KDBUS_ITEM_ID: A connection ID - * KDBUS_ITEM_DST_ID: A connection ID - * KDBUS_ITEM_NAME_ADD: - * KDBUS_ITEM_NAME_REMOVE: - * KDBUS_ITEM_NAME_CHANGE: Well-known name changes, carry - * kdbus_notify_name_change - * KDBUS_ITEM_ID_ADD: - * KDBUS_ITEM_ID_REMOVE: Connection ID changes, carry - * kdbus_notify_id_change - * - * For kdbus_notify_{id,name}_change structs, only the ID and name fields - * are looked at when adding an entry. The flags are unused. - * - * Also note that KDBUS_ITEM_BLOOM_MASK, KDBUS_ITEM_NAME, KDBUS_ITEM_ID, - * and KDBUS_ITEM_DST_ID are used to match messages from userspace, while the - * others apply to kernel-generated notifications. - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp) -{ - struct kdbus_match_db *mdb = conn->match_db; - struct kdbus_match_entry *entry = NULL; - struct kdbus_cmd_match *cmd; - struct kdbus_item *item; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_BLOOM_MASK, .multiple = true }, - { .type = KDBUS_ITEM_NAME, .multiple = true }, - { .type = KDBUS_ITEM_ID, .multiple = true }, - { .type = KDBUS_ITEM_DST_ID, .multiple = true }, - { .type = KDBUS_ITEM_NAME_ADD, .multiple = true }, - { .type = KDBUS_ITEM_NAME_REMOVE, .multiple = true }, - { .type = KDBUS_ITEM_NAME_CHANGE, .multiple = true }, - { .type = KDBUS_ITEM_ID_ADD, .multiple = true }, - { .type = KDBUS_ITEM_ID_REMOVE, .multiple = true }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE | - KDBUS_MATCH_REPLACE, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - if (!kdbus_conn_is_ordinary(conn)) - return -EOPNOTSUPP; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) { - ret = -ENOMEM; - goto exit; - } - - entry->cookie = cmd->cookie; - INIT_LIST_HEAD(&entry->list_entry); - INIT_LIST_HEAD(&entry->rules_list); - - KDBUS_ITEMS_FOREACH(item, cmd->items, KDBUS_ITEMS_SIZE(cmd, items)) { - struct kdbus_match_rule *rule; - size_t size = item->size - offsetof(struct kdbus_item, data); - - rule = kzalloc(sizeof(*rule), GFP_KERNEL); - if (!rule) { - ret = -ENOMEM; - goto exit; - } - - rule->type = item->type; - INIT_LIST_HEAD(&rule->rules_entry); - - switch (item->type) { - case KDBUS_ITEM_BLOOM_MASK: { - u64 bsize = conn->ep->bus->bloom.size; - u64 generations; - u64 remainder; - - generations = div64_u64_rem(size, bsize, &remainder); - if (size < bsize || remainder > 0) { - ret = -EDOM; - break; - } - - rule->bloom_mask.data = kmemdup(item->data, - size, GFP_KERNEL); - if (!rule->bloom_mask.data) { - ret = -ENOMEM; - break; - } - - rule->bloom_mask.generations = generations; - break; - } - - case KDBUS_ITEM_NAME: - if (!kdbus_name_is_valid(item->str, false)) { - ret = -EINVAL; - break; - } - - rule->name = kstrdup(item->str, GFP_KERNEL); - if (!rule->name) - ret = -ENOMEM; - - break; - - case KDBUS_ITEM_ID: - rule->src_id = item->id; - break; - - case KDBUS_ITEM_DST_ID: - rule->dst_id = item->id; - break; - - case KDBUS_ITEM_NAME_ADD: - case KDBUS_ITEM_NAME_REMOVE: - case KDBUS_ITEM_NAME_CHANGE: - rule->old_id = item->name_change.old_id.id; - rule->new_id = item->name_change.new_id.id; - - if (size > sizeof(struct kdbus_notify_name_change)) { - rule->name = kstrdup(item->name_change.name, - GFP_KERNEL); - if (!rule->name) - ret = -ENOMEM; - } - - break; - - case KDBUS_ITEM_ID_ADD: - case KDBUS_ITEM_ID_REMOVE: - if (item->type == KDBUS_ITEM_ID_ADD) - rule->new_id = item->id_change.id; - else - rule->old_id = item->id_change.id; - - break; - } - - if (ret < 0) { - kdbus_match_rule_free(rule); - goto exit; - } - - list_add_tail(&rule->rules_entry, &entry->rules_list); - } - - down_write(&mdb->mdb_rwlock); - - /* Remove any entry that has the same cookie as the current one. */ - if (cmd->flags & KDBUS_MATCH_REPLACE) - kdbus_match_db_remove_unlocked(mdb, entry->cookie); - - /* - * If the above removal caught any entry, there will be room for the - * new one. - */ - if (++mdb->entries_count > KDBUS_MATCH_MAX) { - --mdb->entries_count; - ret = -EMFILE; - } else { - list_add_tail(&entry->list_entry, &mdb->entries_list); - entry = NULL; - } - - up_write(&mdb->mdb_rwlock); - -exit: - kdbus_match_entry_free(entry); - return kdbus_args_clear(&args, ret); -} - -/** - * kdbus_cmd_match_remove() - handle KDBUS_CMD_MATCH_REMOVE - * @conn: connection to operate on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_match_remove(struct kdbus_conn *conn, void __user *argp) -{ - struct kdbus_cmd_match *cmd; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - if (!kdbus_conn_is_ordinary(conn)) - return -EOPNOTSUPP; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - down_write(&conn->match_db->mdb_rwlock); - ret = kdbus_match_db_remove_unlocked(conn->match_db, cmd->cookie); - up_write(&conn->match_db->mdb_rwlock); - - return kdbus_args_clear(&args, ret); -} diff --git a/ipc/kdbus/match.h b/ipc/kdbus/match.h deleted file mode 100644 index ceb492f8e..000000000 --- a/ipc/kdbus/match.h +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_MATCH_H -#define __KDBUS_MATCH_H - -struct kdbus_conn; -struct kdbus_match_db; -struct kdbus_staging; - -struct kdbus_match_db *kdbus_match_db_new(void); -void kdbus_match_db_free(struct kdbus_match_db *db); -int kdbus_match_db_add(struct kdbus_conn *conn, - struct kdbus_cmd_match *cmd); -int kdbus_match_db_remove(struct kdbus_conn *conn, - struct kdbus_cmd_match *cmd); -bool kdbus_match_db_match_msg(struct kdbus_match_db *db, - struct kdbus_conn *conn_src, - const struct kdbus_staging *staging); - -int kdbus_cmd_match_add(struct kdbus_conn *conn, void __user *argp); -int kdbus_cmd_match_remove(struct kdbus_conn *conn, void __user *argp); - -#endif diff --git a/ipc/kdbus/message.c b/ipc/kdbus/message.c deleted file mode 100644 index ae565cd34..000000000 --- a/ipc/kdbus/message.c +++ /dev/null @@ -1,1040 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/capability.h> -#include <linux/cgroup.h> -#include <linux/cred.h> -#include <linux/file.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/sched.h> -#include <linux/shmem_fs.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <net/sock.h> - -#include "bus.h" -#include "connection.h" -#include "domain.h" -#include "endpoint.h" -#include "handle.h" -#include "item.h" -#include "match.h" -#include "message.h" -#include "names.h" -#include "policy.h" - -static const char * const zeros = "\0\0\0\0\0\0\0"; - -static struct kdbus_gaps *kdbus_gaps_new(size_t n_memfds, size_t n_fds) -{ - size_t size_offsets, size_memfds, size_fds, size; - struct kdbus_gaps *gaps; - - size_offsets = n_memfds * sizeof(*gaps->memfd_offsets); - size_memfds = n_memfds * sizeof(*gaps->memfd_files); - size_fds = n_fds * sizeof(*gaps->fd_files); - size = sizeof(*gaps) + size_offsets + size_memfds + size_fds; - - gaps = kzalloc(size, GFP_KERNEL); - if (!gaps) - return ERR_PTR(-ENOMEM); - - kref_init(&gaps->kref); - gaps->n_memfds = 0; /* we reserve n_memfds, but don't enforce them */ - gaps->memfd_offsets = (void *)(gaps + 1); - gaps->memfd_files = (void *)((u8 *)gaps->memfd_offsets + size_offsets); - gaps->n_fds = 0; /* we reserve n_fds, but don't enforce them */ - gaps->fd_files = (void *)((u8 *)gaps->memfd_files + size_memfds); - - return gaps; -} - -static void kdbus_gaps_free(struct kref *kref) -{ - struct kdbus_gaps *gaps = container_of(kref, struct kdbus_gaps, kref); - size_t i; - - for (i = 0; i < gaps->n_fds; ++i) - if (gaps->fd_files[i]) - fput(gaps->fd_files[i]); - for (i = 0; i < gaps->n_memfds; ++i) - if (gaps->memfd_files[i]) - fput(gaps->memfd_files[i]); - - kfree(gaps); -} - -/** - * kdbus_gaps_ref() - gain reference - * @gaps: gaps object - * - * Return: @gaps is returned - */ -struct kdbus_gaps *kdbus_gaps_ref(struct kdbus_gaps *gaps) -{ - if (gaps) - kref_get(&gaps->kref); - return gaps; -} - -/** - * kdbus_gaps_unref() - drop reference - * @gaps: gaps object - * - * Return: NULL - */ -struct kdbus_gaps *kdbus_gaps_unref(struct kdbus_gaps *gaps) -{ - if (gaps) - kref_put(&gaps->kref, kdbus_gaps_free); - return NULL; -} - -/** - * kdbus_gaps_install() - install file-descriptors - * @gaps: gaps object, or NULL - * @slice: pool slice that contains the message - * @out_incomplete output variable to note incomplete fds - * - * This function installs all file-descriptors of @gaps into the current - * process and copies the file-descriptor numbers into the target pool slice. - * - * If the file-descriptors were only partially installed, then @out_incomplete - * will be set to true. Otherwise, it's set to false. - * - * Return: 0 on success, negative error code on failure - */ -int kdbus_gaps_install(struct kdbus_gaps *gaps, struct kdbus_pool_slice *slice, - bool *out_incomplete) -{ - bool incomplete_fds = false; - struct kvec kvec; - size_t i, n_fds; - int ret, *fds; - - if (!gaps) { - /* nothing to do */ - *out_incomplete = incomplete_fds; - return 0; - } - - n_fds = gaps->n_fds + gaps->n_memfds; - if (n_fds < 1) { - /* nothing to do */ - *out_incomplete = incomplete_fds; - return 0; - } - - fds = kmalloc_array(n_fds, sizeof(*fds), GFP_TEMPORARY); - n_fds = 0; - if (!fds) - return -ENOMEM; - - /* 1) allocate fds and copy them over */ - - if (gaps->n_fds > 0) { - for (i = 0; i < gaps->n_fds; ++i) { - int fd; - - fd = get_unused_fd_flags(O_CLOEXEC); - if (fd < 0) - incomplete_fds = true; - - WARN_ON(!gaps->fd_files[i]); - - fds[n_fds++] = fd < 0 ? -1 : fd; - } - - /* - * The file-descriptor array can only be present once per - * message. Hence, prepare all fds and then copy them over with - * a single kvec. - */ - - WARN_ON(!gaps->fd_offset); - - kvec.iov_base = fds; - kvec.iov_len = gaps->n_fds * sizeof(*fds); - ret = kdbus_pool_slice_copy_kvec(slice, gaps->fd_offset, - &kvec, 1, kvec.iov_len); - if (ret < 0) - goto exit; - } - - for (i = 0; i < gaps->n_memfds; ++i) { - int memfd; - - memfd = get_unused_fd_flags(O_CLOEXEC); - if (memfd < 0) { - incomplete_fds = true; - /* memfds are initialized to -1, skip copying it */ - continue; - } - - fds[n_fds++] = memfd; - - /* - * memfds have to be copied individually as they each are put - * into a separate item. This should not be an issue, though, - * as usually there is no need to send more than one memfd per - * message. - */ - - WARN_ON(!gaps->memfd_offsets[i]); - WARN_ON(!gaps->memfd_files[i]); - - kvec.iov_base = &memfd; - kvec.iov_len = sizeof(memfd); - ret = kdbus_pool_slice_copy_kvec(slice, gaps->memfd_offsets[i], - &kvec, 1, kvec.iov_len); - if (ret < 0) - goto exit; - } - - /* 2) install fds now that everything was successful */ - - for (i = 0; i < gaps->n_fds; ++i) - if (fds[i] >= 0) - fd_install(fds[i], get_file(gaps->fd_files[i])); - for (i = 0; i < gaps->n_memfds; ++i) - if (fds[gaps->n_fds + i] >= 0) - fd_install(fds[gaps->n_fds + i], - get_file(gaps->memfd_files[i])); - - ret = 0; - -exit: - if (ret < 0) - for (i = 0; i < n_fds; ++i) - put_unused_fd(fds[i]); - kfree(fds); - *out_incomplete = incomplete_fds; - return ret; -} - -static struct file *kdbus_get_fd(int fd) -{ - struct file *f, *ret; - struct inode *inode; - struct socket *sock; - - if (fd < 0) - return ERR_PTR(-EBADF); - - f = fget_raw(fd); - if (!f) - return ERR_PTR(-EBADF); - - inode = file_inode(f); - sock = S_ISSOCK(inode->i_mode) ? SOCKET_I(inode) : NULL; - - if (f->f_mode & FMODE_PATH) - ret = f; /* O_PATH is always allowed */ - else if (f->f_op == &kdbus_handle_ops) - ret = ERR_PTR(-EOPNOTSUPP); /* disallow kdbus-fd over kdbus */ - else if (sock && sock->sk && sock->ops && sock->ops->family == PF_UNIX) - ret = ERR_PTR(-EOPNOTSUPP); /* disallow UDS over kdbus */ - else - ret = f; /* all other are allowed */ - - if (f != ret) - fput(f); - - return ret; -} - -static struct file *kdbus_get_memfd(const struct kdbus_memfd *memfd) -{ - const int m = F_SEAL_SHRINK | F_SEAL_GROW | F_SEAL_WRITE | F_SEAL_SEAL; - struct file *f, *ret; - int s; - - if (memfd->fd < 0) - return ERR_PTR(-EBADF); - - f = fget(memfd->fd); - if (!f) - return ERR_PTR(-EBADF); - - s = shmem_get_seals(f); - if (s < 0) - ret = ERR_PTR(-EMEDIUMTYPE); - else if ((s & m) != m) - ret = ERR_PTR(-ETXTBSY); - else if (memfd->start + memfd->size > (u64)i_size_read(file_inode(f))) - ret = ERR_PTR(-EFAULT); - else - ret = f; - - if (f != ret) - fput(f); - - return ret; -} - -static int kdbus_msg_examine(struct kdbus_msg *msg, struct kdbus_bus *bus, - struct kdbus_cmd_send *cmd, size_t *out_n_memfds, - size_t *out_n_fds, size_t *out_n_parts) -{ - struct kdbus_item *item, *fds = NULL, *bloom = NULL, *dstname = NULL; - u64 n_parts, n_memfds, n_fds, vec_size; - - /* - * Step 1: - * Validate the message and command parameters. - */ - - /* KDBUS_PAYLOAD_KERNEL is reserved to kernel messages */ - if (msg->payload_type == KDBUS_PAYLOAD_KERNEL) - return -EINVAL; - - if (msg->dst_id == KDBUS_DST_ID_BROADCAST) { - /* broadcasts must be marked as signals */ - if (!(msg->flags & KDBUS_MSG_SIGNAL)) - return -EBADMSG; - /* broadcasts cannot have timeouts */ - if (msg->timeout_ns > 0) - return -ENOTUNIQ; - } - - if (msg->flags & KDBUS_MSG_EXPECT_REPLY) { - /* if you expect a reply, you must specify a timeout */ - if (msg->timeout_ns == 0) - return -EINVAL; - /* signals cannot have replies */ - if (msg->flags & KDBUS_MSG_SIGNAL) - return -ENOTUNIQ; - } else { - /* must expect reply if sent as synchronous call */ - if (cmd->flags & KDBUS_SEND_SYNC_REPLY) - return -EINVAL; - /* cannot mark replies as signal */ - if (msg->cookie_reply && (msg->flags & KDBUS_MSG_SIGNAL)) - return -EINVAL; - } - - /* - * Step 2: - * Validate all passed items. While at it, select some statistics that - * are required to allocate state objects later on. - * - * Generic item validation has already been done via - * kdbus_item_validate(). Furthermore, the number of items is naturally - * limited by the maximum message size. Hence, only non-generic item - * checks are performed here (mainly integer overflow tests). - */ - - n_parts = 0; - n_memfds = 0; - n_fds = 0; - vec_size = 0; - - KDBUS_ITEMS_FOREACH(item, msg->items, KDBUS_ITEMS_SIZE(msg, items)) { - switch (item->type) { - case KDBUS_ITEM_PAYLOAD_VEC: { - void __force __user *ptr = KDBUS_PTR(item->vec.address); - u64 size = item->vec.size; - - if (vec_size + size < vec_size) - return -EMSGSIZE; - if (vec_size + size > KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE) - return -EMSGSIZE; - if (ptr && unlikely(!access_ok(VERIFY_READ, ptr, size))) - return -EFAULT; - - if (ptr || size % 8) /* data or padding */ - ++n_parts; - break; - } - case KDBUS_ITEM_PAYLOAD_MEMFD: { - u64 start = item->memfd.start; - u64 size = item->memfd.size; - - if (start + size < start) - return -EMSGSIZE; - if (n_memfds >= KDBUS_MSG_MAX_MEMFD_ITEMS) - return -E2BIG; - - ++n_memfds; - if (size % 8) /* vec-padding required */ - ++n_parts; - break; - } - case KDBUS_ITEM_FDS: { - if (fds) - return -EEXIST; - - fds = item; - n_fds = KDBUS_ITEM_PAYLOAD_SIZE(item) / sizeof(int); - if (n_fds > KDBUS_CONN_MAX_FDS_PER_USER) - return -EMFILE; - - break; - } - case KDBUS_ITEM_BLOOM_FILTER: { - u64 bloom_size; - - if (bloom) - return -EEXIST; - - bloom = item; - bloom_size = KDBUS_ITEM_PAYLOAD_SIZE(item) - - offsetof(struct kdbus_bloom_filter, data); - if (!KDBUS_IS_ALIGNED8(bloom_size)) - return -EFAULT; - if (bloom_size != bus->bloom.size) - return -EDOM; - - break; - } - case KDBUS_ITEM_DST_NAME: { - if (dstname) - return -EEXIST; - - dstname = item; - if (!kdbus_name_is_valid(item->str, false)) - return -EINVAL; - if (msg->dst_id == KDBUS_DST_ID_BROADCAST) - return -EBADMSG; - - break; - } - default: - return -EINVAL; - } - } - - /* - * Step 3: - * Validate that required items were actually passed, and that no item - * contradicts the message flags. - */ - - /* bloom filters must be attached _iff_ it's a signal */ - if (!(msg->flags & KDBUS_MSG_SIGNAL) != !bloom) - return -EBADMSG; - /* destination name is required if no ID is given */ - if (msg->dst_id == KDBUS_DST_ID_NAME && !dstname) - return -EDESTADDRREQ; - /* cannot send file-descriptors attached to broadcasts */ - if (msg->dst_id == KDBUS_DST_ID_BROADCAST && fds) - return -ENOTUNIQ; - - *out_n_memfds = n_memfds; - *out_n_fds = n_fds; - *out_n_parts = n_parts; - - return 0; -} - -static bool kdbus_staging_merge_vecs(struct kdbus_staging *staging, - struct kdbus_item **prev_item, - struct iovec **prev_vec, - const struct kdbus_item *merge) -{ - void __user *ptr = (void __user *)KDBUS_PTR(merge->vec.address); - u64 padding = merge->vec.size % 8; - struct kdbus_item *prev = *prev_item; - struct iovec *vec = *prev_vec; - - /* XXX: merging is disabled so far */ - if (0 && prev && prev->type == KDBUS_ITEM_PAYLOAD_OFF && - !merge->vec.address == !prev->vec.address) { - /* - * If we merge two VECs, we can always drop the second - * PAYLOAD_VEC item. Hence, include its size in the previous - * one. - */ - prev->vec.size += merge->vec.size; - - if (ptr) { - /* - * If we merge two data VECs, we need two iovecs to copy - * the data. But the items can be easily merged by - * summing their lengths. - */ - vec = &staging->parts[staging->n_parts++]; - vec->iov_len = merge->vec.size; - vec->iov_base = ptr; - staging->n_payload += vec->iov_len; - } else if (padding) { - /* - * If we merge two 0-vecs with the second 0-vec - * requiring padding, we need to insert an iovec to copy - * the 0-padding. We try merging it with the previous - * 0-padding iovec. This might end up with an - * iov_len==0, in which case we simply drop the iovec. - */ - if (vec) { - staging->n_payload -= vec->iov_len; - vec->iov_len = prev->vec.size % 8; - if (!vec->iov_len) { - --staging->n_parts; - vec = NULL; - } else { - staging->n_payload += vec->iov_len; - } - } else { - vec = &staging->parts[staging->n_parts++]; - vec->iov_len = padding; - vec->iov_base = (char __user *)zeros; - staging->n_payload += vec->iov_len; - } - } else { - /* - * If we merge two 0-vecs with the second 0-vec having - * no padding, we know the padding of the first stays - * the same. Hence, @vec needs no adjustment. - */ - } - - /* successfully merged with previous item */ - merge = prev; - } else { - /* - * If we cannot merge the payload item with the previous one, - * we simply insert a new iovec for the data/padding. - */ - if (ptr) { - vec = &staging->parts[staging->n_parts++]; - vec->iov_len = merge->vec.size; - vec->iov_base = ptr; - staging->n_payload += vec->iov_len; - } else if (padding) { - vec = &staging->parts[staging->n_parts++]; - vec->iov_len = padding; - vec->iov_base = (char __user *)zeros; - staging->n_payload += vec->iov_len; - } else { - vec = NULL; - } - } - - *prev_item = (struct kdbus_item *)merge; - *prev_vec = vec; - - return merge == prev; -} - -static int kdbus_staging_import(struct kdbus_staging *staging) -{ - struct kdbus_item *it, *item, *last, *prev_payload; - struct kdbus_gaps *gaps = staging->gaps; - struct kdbus_msg *msg = staging->msg; - struct iovec *part, *prev_part; - bool drop_item; - - drop_item = false; - last = NULL; - prev_payload = NULL; - prev_part = NULL; - - /* - * We modify msg->items along the way; make sure to use @item as offset - * to the next item (instead of the iterator @it). - */ - for (it = item = msg->items; - it >= msg->items && - (u8 *)it < (u8 *)msg + msg->size && - (u8 *)it + it->size <= (u8 *)msg + msg->size; ) { - /* - * If we dropped items along the way, move current item to - * front. We must not access @it afterwards, but use @item - * instead! - */ - if (it != item) - memmove(item, it, it->size); - it = (void *)((u8 *)it + KDBUS_ALIGN8(item->size)); - - switch (item->type) { - case KDBUS_ITEM_PAYLOAD_VEC: { - size_t offset = staging->n_payload; - - if (kdbus_staging_merge_vecs(staging, &prev_payload, - &prev_part, item)) { - drop_item = true; - } else if (item->vec.address) { - /* real offset is patched later on */ - item->type = KDBUS_ITEM_PAYLOAD_OFF; - item->vec.offset = offset; - } else { - item->type = KDBUS_ITEM_PAYLOAD_OFF; - item->vec.offset = ~0ULL; - } - - break; - } - case KDBUS_ITEM_PAYLOAD_MEMFD: { - struct file *f; - - f = kdbus_get_memfd(&item->memfd); - if (IS_ERR(f)) - return PTR_ERR(f); - - gaps->memfd_files[gaps->n_memfds] = f; - gaps->memfd_offsets[gaps->n_memfds] = - (u8 *)&item->memfd.fd - (u8 *)msg; - ++gaps->n_memfds; - - /* memfds cannot be merged */ - prev_payload = item; - prev_part = NULL; - - /* insert padding to make following VECs aligned */ - if (item->memfd.size % 8) { - part = &staging->parts[staging->n_parts++]; - part->iov_len = item->memfd.size % 8; - part->iov_base = (char __user *)zeros; - staging->n_payload += part->iov_len; - } - - break; - } - case KDBUS_ITEM_FDS: { - size_t i, n_fds; - - n_fds = KDBUS_ITEM_PAYLOAD_SIZE(item) / sizeof(int); - for (i = 0; i < n_fds; ++i) { - struct file *f; - - f = kdbus_get_fd(item->fds[i]); - if (IS_ERR(f)) - return PTR_ERR(f); - - gaps->fd_files[gaps->n_fds++] = f; - } - - gaps->fd_offset = (u8 *)item->fds - (u8 *)msg; - - break; - } - case KDBUS_ITEM_BLOOM_FILTER: - staging->bloom_filter = &item->bloom_filter; - break; - case KDBUS_ITEM_DST_NAME: - staging->dst_name = item->str; - break; - } - - /* drop item if we merged it with a previous one */ - if (drop_item) { - drop_item = false; - } else { - last = item; - item = KDBUS_ITEM_NEXT(item); - } - } - - /* adjust message size regarding dropped items */ - msg->size = offsetof(struct kdbus_msg, items); - if (last) - msg->size += ((u8 *)last - (u8 *)msg->items) + last->size; - - return 0; -} - -static void kdbus_staging_reserve(struct kdbus_staging *staging) -{ - struct iovec *part; - - part = &staging->parts[staging->n_parts++]; - part->iov_base = (void __user *)zeros; - part->iov_len = 0; -} - -static struct kdbus_staging *kdbus_staging_new(struct kdbus_bus *bus, - size_t n_parts, - size_t msg_extra_size) -{ - const size_t reserved_parts = 5; /* see below for explanation */ - struct kdbus_staging *staging; - int ret; - - n_parts += reserved_parts; - - staging = kzalloc(sizeof(*staging) + n_parts * sizeof(*staging->parts) + - msg_extra_size, GFP_TEMPORARY); - if (!staging) - return ERR_PTR(-ENOMEM); - - staging->msg_seqnum = atomic64_inc_return(&bus->last_message_id); - staging->n_parts = 0; /* we reserve n_parts, but don't enforce them */ - staging->parts = (void *)(staging + 1); - - if (msg_extra_size) /* if requested, allocate message, too */ - staging->msg = (void *)((u8 *)staging->parts + - n_parts * sizeof(*staging->parts)); - - staging->meta_proc = kdbus_meta_proc_new(); - if (IS_ERR(staging->meta_proc)) { - ret = PTR_ERR(staging->meta_proc); - staging->meta_proc = NULL; - goto error; - } - - staging->meta_conn = kdbus_meta_conn_new(); - if (IS_ERR(staging->meta_conn)) { - ret = PTR_ERR(staging->meta_conn); - staging->meta_conn = NULL; - goto error; - } - - /* - * Prepare iovecs to copy the message into the target pool. We use the - * following iovecs: - * * iovec to copy "kdbus_msg.size" - * * iovec to copy "struct kdbus_msg" (minus size) plus items - * * iovec for possible padding after the items - * * iovec for metadata items - * * iovec for possible padding after the items - * - * Make sure to update @reserved_parts if you add more parts here. - */ - - kdbus_staging_reserve(staging); /* msg.size */ - kdbus_staging_reserve(staging); /* msg (minus msg.size) plus items */ - kdbus_staging_reserve(staging); /* msg padding */ - kdbus_staging_reserve(staging); /* meta */ - kdbus_staging_reserve(staging); /* meta padding */ - - return staging; - -error: - kdbus_staging_free(staging); - return ERR_PTR(ret); -} - -struct kdbus_staging *kdbus_staging_new_kernel(struct kdbus_bus *bus, - u64 dst, u64 cookie_timeout, - size_t it_size, size_t it_type) -{ - struct kdbus_staging *staging; - size_t size; - - size = offsetof(struct kdbus_msg, items) + - KDBUS_ITEM_HEADER_SIZE + it_size; - - staging = kdbus_staging_new(bus, 0, KDBUS_ALIGN8(size)); - if (IS_ERR(staging)) - return ERR_CAST(staging); - - staging->msg->size = size; - staging->msg->flags = (dst == KDBUS_DST_ID_BROADCAST) ? - KDBUS_MSG_SIGNAL : 0; - staging->msg->dst_id = dst; - staging->msg->src_id = KDBUS_SRC_ID_KERNEL; - staging->msg->payload_type = KDBUS_PAYLOAD_KERNEL; - staging->msg->cookie_reply = cookie_timeout; - staging->notify = staging->msg->items; - staging->notify->size = KDBUS_ITEM_HEADER_SIZE + it_size; - staging->notify->type = it_type; - - return staging; -} - -struct kdbus_staging *kdbus_staging_new_user(struct kdbus_bus *bus, - struct kdbus_cmd_send *cmd, - struct kdbus_msg *msg) -{ - const size_t reserved_parts = 1; /* see below for explanation */ - size_t n_memfds, n_fds, n_parts; - struct kdbus_staging *staging; - int ret; - - /* - * Examine user-supplied message and figure out how many resources we - * need to allocate in our staging area. This requires us to iterate - * the message twice, but saves us from re-allocating our resources - * all the time. - */ - - ret = kdbus_msg_examine(msg, bus, cmd, &n_memfds, &n_fds, &n_parts); - if (ret < 0) - return ERR_PTR(ret); - - n_parts += reserved_parts; - - /* - * Allocate staging area with the number of required resources. Make - * sure that we have enough iovecs for all required parts pre-allocated - * so this will hopefully be the only memory allocation for this - * message transaction. - */ - - staging = kdbus_staging_new(bus, n_parts, 0); - if (IS_ERR(staging)) - return ERR_CAST(staging); - - staging->msg = msg; - - /* - * If the message contains memfds or fd items, we need to remember some - * state so we can fill in the requested information at RECV time. - * File-descriptors cannot be passed at SEND time. Hence, allocate a - * gaps-object to remember that state. That gaps object is linked to - * from the staging area, but will also be linked to from the message - * queue of each peer. Hence, each receiver owns a reference to it, and - * it will later be used to fill the 'gaps' in message that couldn't be - * filled at SEND time. - * Note that the 'gaps' object is read-only once the staging-allocator - * returns. There might be connections receiving a queued message while - * the sender still broadcasts the message to other receivers. - */ - - if (n_memfds > 0 || n_fds > 0) { - staging->gaps = kdbus_gaps_new(n_memfds, n_fds); - if (IS_ERR(staging->gaps)) { - ret = PTR_ERR(staging->gaps); - staging->gaps = NULL; - kdbus_staging_free(staging); - return ERR_PTR(ret); - } - } - - /* - * kdbus_staging_new() already reserves parts for message setup. For - * user-supplied messages, we add the following iovecs: - * ... variable number of iovecs for payload ... - * * final iovec for possible padding of payload - * - * Make sure to update @reserved_parts if you add more parts here. - */ - - ret = kdbus_staging_import(staging); /* payload */ - kdbus_staging_reserve(staging); /* payload padding */ - - if (ret < 0) - goto error; - - return staging; - -error: - kdbus_staging_free(staging); - return ERR_PTR(ret); -} - -struct kdbus_staging *kdbus_staging_free(struct kdbus_staging *staging) -{ - if (!staging) - return NULL; - - kdbus_meta_conn_unref(staging->meta_conn); - kdbus_meta_proc_unref(staging->meta_proc); - kdbus_gaps_unref(staging->gaps); - kfree(staging); - - return NULL; -} - -static int kdbus_staging_collect_metadata(struct kdbus_staging *staging, - struct kdbus_conn *src, - struct kdbus_conn *dst, - u64 *out_attach) -{ - u64 attach; - int ret; - - if (src) - attach = kdbus_meta_msg_mask(src, dst); - else - attach = KDBUS_ATTACH_TIMESTAMP; /* metadata for kernel msgs */ - - if (src && !src->meta_fake) { - ret = kdbus_meta_proc_collect(staging->meta_proc, attach); - if (ret < 0) - return ret; - } - - ret = kdbus_meta_conn_collect(staging->meta_conn, src, - staging->msg_seqnum, attach); - if (ret < 0) - return ret; - - *out_attach = attach; - return 0; -} - -/** - * kdbus_staging_emit() - emit linearized message in target pool - * @staging: staging object to create message from - * @src: sender of the message (or NULL) - * @dst: target connection to allocate message for - * - * This allocates a pool-slice for @dst and copies the message provided by - * @staging into it. The new slice is then returned to the caller for further - * processing. It's not linked into any queue, yet. - * - * Return: Newly allocated slice or ERR_PTR on failure. - */ -struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, - struct kdbus_conn *src, - struct kdbus_conn *dst) -{ - struct kdbus_item *item, *meta_items = NULL; - struct kdbus_pool_slice *slice = NULL; - size_t off, size, meta_size; - struct iovec *v; - u64 attach, msg_size; - int ret; - - /* - * Step 1: - * Collect metadata from @src depending on the attach-flags allowed for - * @dst. Translate it into the namespaces pinned by @dst. - */ - - ret = kdbus_staging_collect_metadata(staging, src, dst, &attach); - if (ret < 0) - goto error; - - ret = kdbus_meta_emit(staging->meta_proc, NULL, staging->meta_conn, - dst, attach, &meta_items, &meta_size); - if (ret < 0) - goto error; - - /* - * Step 2: - * Setup iovecs for the message. See kdbus_staging_new() for allocation - * of those iovecs. All reserved iovecs have been initialized with - * iov_len=0 + iov_base=zeros. Furthermore, the iovecs to copy the - * actual message payload have already been initialized and need not be - * touched. - */ - - v = staging->parts; - msg_size = staging->msg->size; - - /* msg.size */ - v->iov_len = sizeof(msg_size); - v->iov_base = (void __user *)&msg_size; - ++v; - - /* msg (after msg.size) plus items */ - v->iov_len = staging->msg->size - sizeof(staging->msg->size); - v->iov_base = (void __user *)((u8 *)staging->msg + - sizeof(staging->msg->size)); - ++v; - - /* padding after msg */ - v->iov_len = KDBUS_ALIGN8(staging->msg->size) - staging->msg->size; - v->iov_base = (void __user *)zeros; - ++v; - - if (meta_size > 0) { - /* metadata items */ - v->iov_len = meta_size; - v->iov_base = (void __user *)meta_items; - ++v; - - /* padding after metadata */ - v->iov_len = KDBUS_ALIGN8(meta_size) - meta_size; - v->iov_base = (void __user *)zeros; - ++v; - - msg_size = KDBUS_ALIGN8(msg_size) + meta_size; - } else { - /* metadata items */ - v->iov_len = 0; - v->iov_base = (void __user *)zeros; - ++v; - - /* padding after metadata */ - v->iov_len = 0; - v->iov_base = (void __user *)zeros; - ++v; - } - - /* ... payload iovecs are already filled in ... */ - - /* compute overall size and fill in padding after payload */ - size = KDBUS_ALIGN8(msg_size); - - if (staging->n_payload > 0) { - size += staging->n_payload; - - v = &staging->parts[staging->n_parts - 1]; - v->iov_len = KDBUS_ALIGN8(size) - size; - v->iov_base = (void __user *)zeros; - - size = KDBUS_ALIGN8(size); - } - - /* - * Step 3: - * The PAYLOAD_OFF items in the message contain a relative 'offset' - * field that tells the receiver where to find the actual payload. This - * offset is relative to the start of the message, and as such depends - * on the size of the metadata items we inserted. This size is variable - * and changes for each peer we send the message to. Hence, we remember - * the last relative offset that was used to calculate the 'offset' - * fields. For each message, we re-calculate it and patch all items, in - * case it changed. - */ - - off = KDBUS_ALIGN8(msg_size); - - if (off != staging->i_payload) { - KDBUS_ITEMS_FOREACH(item, staging->msg->items, - KDBUS_ITEMS_SIZE(staging->msg, items)) { - if (item->type != KDBUS_ITEM_PAYLOAD_OFF) - continue; - - item->vec.offset -= staging->i_payload; - item->vec.offset += off; - } - - staging->i_payload = off; - } - - /* - * Step 4: - * Allocate pool slice and copy over all data. Make sure to properly - * account on user quota. - */ - - ret = kdbus_conn_quota_inc(dst, src ? src->user : NULL, size, - staging->gaps ? staging->gaps->n_fds : 0); - if (ret < 0) - goto error; - - slice = kdbus_pool_slice_alloc(dst->pool, size, true); - if (IS_ERR(slice)) { - ret = PTR_ERR(slice); - slice = NULL; - goto error; - } - - WARN_ON(kdbus_pool_slice_size(slice) != size); - - ret = kdbus_pool_slice_copy_iovec(slice, 0, staging->parts, - staging->n_parts, size); - if (ret < 0) - goto error; - - /* all done, return slice to caller */ - goto exit; - -error: - if (slice) - kdbus_conn_quota_dec(dst, src ? src->user : NULL, size, - staging->gaps ? staging->gaps->n_fds : 0); - kdbus_pool_slice_release(slice); - slice = ERR_PTR(ret); -exit: - kfree(meta_items); - return slice; -} diff --git a/ipc/kdbus/message.h b/ipc/kdbus/message.h deleted file mode 100644 index 298f9c99d..000000000 --- a/ipc/kdbus/message.h +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_MESSAGE_H -#define __KDBUS_MESSAGE_H - -#include <linux/fs.h> -#include <linux/kref.h> -#include <uapi/linux/kdbus.h> - -struct kdbus_bus; -struct kdbus_conn; -struct kdbus_meta_conn; -struct kdbus_meta_proc; -struct kdbus_pool_slice; - -/** - * struct kdbus_gaps - gaps in message to be filled later - * @kref: Reference counter - * @n_memfd_offs: Number of memfds - * @memfd_offs: Offsets of kdbus_memfd items in target slice - * @n_fds: Number of fds - * @fds: Array of sent fds - * @fds_offset: Offset of fd-array in target slice - * - * The 'gaps' object is used to track data that is needed to fill gaps in a - * message at RECV time. Usually, we try to compile the whole message at SEND - * time. This has the advantage, that we don't have to cache any information and - * can keep the memory consumption small. Furthermore, all copy operations can - * be combined into a single function call, which speeds up transactions - * considerably. - * However, things like file-descriptors can only be fully installed at RECV - * time. The gaps object tracks this data and pins it until a message is - * received. The gaps object is shared between all receivers of the same - * message. - */ -struct kdbus_gaps { - struct kref kref; - - /* state tracking for KDBUS_ITEM_PAYLOAD_MEMFD entries */ - size_t n_memfds; - u64 *memfd_offsets; - struct file **memfd_files; - - /* state tracking for KDBUS_ITEM_FDS */ - size_t n_fds; - struct file **fd_files; - u64 fd_offset; -}; - -struct kdbus_gaps *kdbus_gaps_ref(struct kdbus_gaps *gaps); -struct kdbus_gaps *kdbus_gaps_unref(struct kdbus_gaps *gaps); -int kdbus_gaps_install(struct kdbus_gaps *gaps, struct kdbus_pool_slice *slice, - bool *out_incomplete); - -/** - * struct kdbus_staging - staging area to import messages - * @msg: User-supplied message - * @gaps: Gaps-object created during import (or NULL if empty) - * @msg_seqnum: Message sequence number - * @notify_entry: Entry into list of kernel-generated notifications - * @i_payload: Current relative index of start of payload - * @n_payload: Total number of bytes needed for payload - * @n_parts: Number of parts - * @parts: Array of iovecs that make up the whole message - * @meta_proc: Process metadata of the sender (or NULL if empty) - * @meta_conn: Connection metadata of the sender (or NULL if empty) - * @bloom_filter: Pointer to the bloom-item in @msg, or NULL - * @dst_name: Pointer to the dst-name-item in @msg, or NULL - * @notify: Pointer to the notification item in @msg, or NULL - * - * The kdbus_staging object is a temporary staging area to import user-supplied - * messages into the kernel. It is only used during SEND and dropped once the - * message is queued. Any data that cannot be collected during SEND, is - * collected in a kdbus_gaps object and attached to the message queue. - */ -struct kdbus_staging { - struct kdbus_msg *msg; - struct kdbus_gaps *gaps; - u64 msg_seqnum; - struct list_head notify_entry; - - /* crafted iovecs to copy the message */ - size_t i_payload; - size_t n_payload; - size_t n_parts; - struct iovec *parts; - - /* metadata state */ - struct kdbus_meta_proc *meta_proc; - struct kdbus_meta_conn *meta_conn; - - /* cached pointers into @msg */ - const struct kdbus_bloom_filter *bloom_filter; - const char *dst_name; - struct kdbus_item *notify; -}; - -struct kdbus_staging *kdbus_staging_new_kernel(struct kdbus_bus *bus, - u64 dst, u64 cookie_timeout, - size_t it_size, size_t it_type); -struct kdbus_staging *kdbus_staging_new_user(struct kdbus_bus *bus, - struct kdbus_cmd_send *cmd, - struct kdbus_msg *msg); -struct kdbus_staging *kdbus_staging_free(struct kdbus_staging *staging); -struct kdbus_pool_slice *kdbus_staging_emit(struct kdbus_staging *staging, - struct kdbus_conn *src, - struct kdbus_conn *dst); - -#endif diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c deleted file mode 100644 index 71ca475a8..000000000 --- a/ipc/kdbus/metadata.c +++ /dev/null @@ -1,1347 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/audit.h> -#include <linux/capability.h> -#include <linux/cgroup.h> -#include <linux/cred.h> -#include <linux/file.h> -#include <linux/fs_struct.h> -#include <linux/init.h> -#include <linux/kref.h> -#include <linux/mutex.h> -#include <linux/sched.h> -#include <linux/security.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/uidgid.h> -#include <linux/uio.h> -#include <linux/user_namespace.h> - -#include "bus.h" -#include "connection.h" -#include "endpoint.h" -#include "item.h" -#include "message.h" -#include "metadata.h" -#include "names.h" - -/** - * struct kdbus_meta_proc - Process metadata - * @kref: Reference counting - * @lock: Object lock - * @collected: Bitmask of collected items - * @valid: Bitmask of collected and valid items - * @cred: Credentials - * @pid: PID of process - * @tgid: TGID of process - * @ppid: PPID of process - * @tid_comm: TID comm line - * @pid_comm: PID comm line - * @exe_path: Executable path - * @root_path: Root-FS path - * @cmdline: Command-line - * @cgroup: Full cgroup path - * @seclabel: Seclabel - * @audit_loginuid: Audit login-UID - * @audit_sessionid: Audit session-ID - */ -struct kdbus_meta_proc { - struct kref kref; - struct mutex lock; - u64 collected; - u64 valid; - - /* KDBUS_ITEM_CREDS */ - /* KDBUS_ITEM_AUXGROUPS */ - /* KDBUS_ITEM_CAPS */ - const struct cred *cred; - - /* KDBUS_ITEM_PIDS */ - struct pid *pid; - struct pid *tgid; - struct pid *ppid; - - /* KDBUS_ITEM_TID_COMM */ - char tid_comm[TASK_COMM_LEN]; - /* KDBUS_ITEM_PID_COMM */ - char pid_comm[TASK_COMM_LEN]; - - /* KDBUS_ITEM_EXE */ - struct path exe_path; - struct path root_path; - - /* KDBUS_ITEM_CMDLINE */ - char *cmdline; - - /* KDBUS_ITEM_CGROUP */ - char *cgroup; - - /* KDBUS_ITEM_SECLABEL */ - char *seclabel; - - /* KDBUS_ITEM_AUDIT */ - kuid_t audit_loginuid; - unsigned int audit_sessionid; -}; - -/** - * struct kdbus_meta_conn - * @kref: Reference counting - * @lock: Object lock - * @collected: Bitmask of collected items - * @valid: Bitmask of collected and valid items - * @ts: Timestamp values - * @owned_names_items: Serialized items for owned names - * @owned_names_size: Size of @owned_names_items - * @conn_description: Connection description - */ -struct kdbus_meta_conn { - struct kref kref; - struct mutex lock; - u64 collected; - u64 valid; - - /* KDBUS_ITEM_TIMESTAMP */ - struct kdbus_timestamp ts; - - /* KDBUS_ITEM_OWNED_NAME */ - struct kdbus_item *owned_names_items; - size_t owned_names_size; - - /* KDBUS_ITEM_CONN_DESCRIPTION */ - char *conn_description; -}; - -/* fixed size equivalent of "kdbus_caps" */ -struct kdbus_meta_caps { - u32 last_cap; - struct { - u32 caps[_KERNEL_CAPABILITY_U32S]; - } set[4]; -}; - -/** - * kdbus_meta_proc_new() - Create process metadata object - * - * Return: Pointer to new object on success, ERR_PTR on failure. - */ -struct kdbus_meta_proc *kdbus_meta_proc_new(void) -{ - struct kdbus_meta_proc *mp; - - mp = kzalloc(sizeof(*mp), GFP_KERNEL); - if (!mp) - return ERR_PTR(-ENOMEM); - - kref_init(&mp->kref); - mutex_init(&mp->lock); - - return mp; -} - -static void kdbus_meta_proc_free(struct kref *kref) -{ - struct kdbus_meta_proc *mp = container_of(kref, struct kdbus_meta_proc, - kref); - - path_put(&mp->exe_path); - path_put(&mp->root_path); - if (mp->cred) - put_cred(mp->cred); - put_pid(mp->ppid); - put_pid(mp->tgid); - put_pid(mp->pid); - - kfree(mp->seclabel); - kfree(mp->cmdline); - kfree(mp->cgroup); - kfree(mp); -} - -/** - * kdbus_meta_proc_ref() - Gain reference - * @mp: Process metadata object - * - * Return: @mp is returned - */ -struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp) -{ - if (mp) - kref_get(&mp->kref); - return mp; -} - -/** - * kdbus_meta_proc_unref() - Drop reference - * @mp: Process metadata object - * - * Return: NULL - */ -struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp) -{ - if (mp) - kref_put(&mp->kref, kdbus_meta_proc_free); - return NULL; -} - -static void kdbus_meta_proc_collect_pids(struct kdbus_meta_proc *mp) -{ - struct task_struct *parent; - - mp->pid = get_pid(task_pid(current)); - mp->tgid = get_pid(task_tgid(current)); - - rcu_read_lock(); - parent = rcu_dereference(current->real_parent); - mp->ppid = get_pid(task_tgid(parent)); - rcu_read_unlock(); - - mp->valid |= KDBUS_ATTACH_PIDS; -} - -static void kdbus_meta_proc_collect_tid_comm(struct kdbus_meta_proc *mp) -{ - get_task_comm(mp->tid_comm, current); - mp->valid |= KDBUS_ATTACH_TID_COMM; -} - -static void kdbus_meta_proc_collect_pid_comm(struct kdbus_meta_proc *mp) -{ - get_task_comm(mp->pid_comm, current->group_leader); - mp->valid |= KDBUS_ATTACH_PID_COMM; -} - -static void kdbus_meta_proc_collect_exe(struct kdbus_meta_proc *mp) -{ - struct file *exe_file; - - rcu_read_lock(); - exe_file = rcu_dereference(current->mm->exe_file); - if (exe_file) { - mp->exe_path = exe_file->f_path; - path_get(&mp->exe_path); - get_fs_root(current->fs, &mp->root_path); - mp->valid |= KDBUS_ATTACH_EXE; - } - rcu_read_unlock(); -} - -static int kdbus_meta_proc_collect_cmdline(struct kdbus_meta_proc *mp) -{ - struct mm_struct *mm = current->mm; - char *cmdline; - - if (!mm->arg_end) - return 0; - - cmdline = strndup_user((const char __user *)mm->arg_start, - mm->arg_end - mm->arg_start); - if (IS_ERR(cmdline)) - return PTR_ERR(cmdline); - - mp->cmdline = cmdline; - mp->valid |= KDBUS_ATTACH_CMDLINE; - - return 0; -} - -static int kdbus_meta_proc_collect_cgroup(struct kdbus_meta_proc *mp) -{ -#ifdef CONFIG_CGROUPS - void *page; - char *s; - - page = (void *)__get_free_page(GFP_TEMPORARY); - if (!page) - return -ENOMEM; - - s = task_cgroup_path(current, page, PAGE_SIZE); - if (s) { - mp->cgroup = kstrdup(s, GFP_KERNEL); - if (!mp->cgroup) { - free_page((unsigned long)page); - return -ENOMEM; - } - } - - free_page((unsigned long)page); - mp->valid |= KDBUS_ATTACH_CGROUP; -#endif - - return 0; -} - -static int kdbus_meta_proc_collect_seclabel(struct kdbus_meta_proc *mp) -{ -#ifdef CONFIG_SECURITY - char *ctx = NULL; - u32 sid, len; - int ret; - - security_task_getsecid(current, &sid); - ret = security_secid_to_secctx(sid, &ctx, &len); - if (ret < 0) { - /* - * EOPNOTSUPP means no security module is active, - * lets skip adding the seclabel then. This effectively - * drops the SECLABEL item. - */ - return (ret == -EOPNOTSUPP) ? 0 : ret; - } - - mp->seclabel = kstrdup(ctx, GFP_KERNEL); - security_release_secctx(ctx, len); - if (!mp->seclabel) - return -ENOMEM; - - mp->valid |= KDBUS_ATTACH_SECLABEL; -#endif - - return 0; -} - -static void kdbus_meta_proc_collect_audit(struct kdbus_meta_proc *mp) -{ -#ifdef CONFIG_AUDITSYSCALL - mp->audit_loginuid = audit_get_loginuid(current); - mp->audit_sessionid = audit_get_sessionid(current); - mp->valid |= KDBUS_ATTACH_AUDIT; -#endif -} - -/** - * kdbus_meta_proc_collect() - Collect process metadata - * @mp: Process metadata object - * @what: Attach flags to collect - * - * This collects process metadata from current and saves it in @mp. - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what) -{ - int ret; - - if (!mp || !(what & (KDBUS_ATTACH_CREDS | - KDBUS_ATTACH_PIDS | - KDBUS_ATTACH_AUXGROUPS | - KDBUS_ATTACH_TID_COMM | - KDBUS_ATTACH_PID_COMM | - KDBUS_ATTACH_EXE | - KDBUS_ATTACH_CMDLINE | - KDBUS_ATTACH_CGROUP | - KDBUS_ATTACH_CAPS | - KDBUS_ATTACH_SECLABEL | - KDBUS_ATTACH_AUDIT))) - return 0; - - mutex_lock(&mp->lock); - - /* creds, auxgrps and caps share "struct cred" as context */ - { - const u64 m_cred = KDBUS_ATTACH_CREDS | - KDBUS_ATTACH_AUXGROUPS | - KDBUS_ATTACH_CAPS; - - if ((what & m_cred) && !(mp->collected & m_cred)) { - mp->cred = get_current_cred(); - mp->valid |= m_cred; - mp->collected |= m_cred; - } - } - - if ((what & KDBUS_ATTACH_PIDS) && - !(mp->collected & KDBUS_ATTACH_PIDS)) { - kdbus_meta_proc_collect_pids(mp); - mp->collected |= KDBUS_ATTACH_PIDS; - } - - if ((what & KDBUS_ATTACH_TID_COMM) && - !(mp->collected & KDBUS_ATTACH_TID_COMM)) { - kdbus_meta_proc_collect_tid_comm(mp); - mp->collected |= KDBUS_ATTACH_TID_COMM; - } - - if ((what & KDBUS_ATTACH_PID_COMM) && - !(mp->collected & KDBUS_ATTACH_PID_COMM)) { - kdbus_meta_proc_collect_pid_comm(mp); - mp->collected |= KDBUS_ATTACH_PID_COMM; - } - - if ((what & KDBUS_ATTACH_EXE) && - !(mp->collected & KDBUS_ATTACH_EXE)) { - kdbus_meta_proc_collect_exe(mp); - mp->collected |= KDBUS_ATTACH_EXE; - } - - if ((what & KDBUS_ATTACH_CMDLINE) && - !(mp->collected & KDBUS_ATTACH_CMDLINE)) { - ret = kdbus_meta_proc_collect_cmdline(mp); - if (ret < 0) - goto exit_unlock; - mp->collected |= KDBUS_ATTACH_CMDLINE; - } - - if ((what & KDBUS_ATTACH_CGROUP) && - !(mp->collected & KDBUS_ATTACH_CGROUP)) { - ret = kdbus_meta_proc_collect_cgroup(mp); - if (ret < 0) - goto exit_unlock; - mp->collected |= KDBUS_ATTACH_CGROUP; - } - - if ((what & KDBUS_ATTACH_SECLABEL) && - !(mp->collected & KDBUS_ATTACH_SECLABEL)) { - ret = kdbus_meta_proc_collect_seclabel(mp); - if (ret < 0) - goto exit_unlock; - mp->collected |= KDBUS_ATTACH_SECLABEL; - } - - if ((what & KDBUS_ATTACH_AUDIT) && - !(mp->collected & KDBUS_ATTACH_AUDIT)) { - kdbus_meta_proc_collect_audit(mp); - mp->collected |= KDBUS_ATTACH_AUDIT; - } - - ret = 0; - -exit_unlock: - mutex_unlock(&mp->lock); - return ret; -} - -/** - * kdbus_meta_fake_new() - Create fake metadata object - * - * Return: Pointer to new object on success, ERR_PTR on failure. - */ -struct kdbus_meta_fake *kdbus_meta_fake_new(void) -{ - struct kdbus_meta_fake *mf; - - mf = kzalloc(sizeof(*mf), GFP_KERNEL); - if (!mf) - return ERR_PTR(-ENOMEM); - - return mf; -} - -/** - * kdbus_meta_fake_free() - Free fake metadata object - * @mf: Fake metadata object - * - * Return: NULL - */ -struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf) -{ - if (mf) { - put_pid(mf->ppid); - put_pid(mf->tgid); - put_pid(mf->pid); - kfree(mf->seclabel); - kfree(mf); - } - - return NULL; -} - -/** - * kdbus_meta_fake_collect() - Fill fake metadata from faked credentials - * @mf: Fake metadata object - * @creds: Creds to set, may be %NULL - * @pids: PIDs to set, may be %NULL - * @seclabel: Seclabel to set, may be %NULL - * - * This function takes information stored in @creds, @pids and @seclabel and - * resolves them to kernel-representations, if possible. This call uses the - * current task's namespaces to resolve the given information. - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf, - const struct kdbus_creds *creds, - const struct kdbus_pids *pids, - const char *seclabel) -{ - if (mf->valid) - return -EALREADY; - - if (creds) { - struct user_namespace *ns = current_user_ns(); - - mf->uid = make_kuid(ns, creds->uid); - mf->euid = make_kuid(ns, creds->euid); - mf->suid = make_kuid(ns, creds->suid); - mf->fsuid = make_kuid(ns, creds->fsuid); - - mf->gid = make_kgid(ns, creds->gid); - mf->egid = make_kgid(ns, creds->egid); - mf->sgid = make_kgid(ns, creds->sgid); - mf->fsgid = make_kgid(ns, creds->fsgid); - - if ((creds->uid != (uid_t)-1 && !uid_valid(mf->uid)) || - (creds->euid != (uid_t)-1 && !uid_valid(mf->euid)) || - (creds->suid != (uid_t)-1 && !uid_valid(mf->suid)) || - (creds->fsuid != (uid_t)-1 && !uid_valid(mf->fsuid)) || - (creds->gid != (gid_t)-1 && !gid_valid(mf->gid)) || - (creds->egid != (gid_t)-1 && !gid_valid(mf->egid)) || - (creds->sgid != (gid_t)-1 && !gid_valid(mf->sgid)) || - (creds->fsgid != (gid_t)-1 && !gid_valid(mf->fsgid))) - return -EINVAL; - - mf->valid |= KDBUS_ATTACH_CREDS; - } - - if (pids) { - mf->pid = get_pid(find_vpid(pids->tid)); - mf->tgid = get_pid(find_vpid(pids->pid)); - mf->ppid = get_pid(find_vpid(pids->ppid)); - - if ((pids->tid != 0 && !mf->pid) || - (pids->pid != 0 && !mf->tgid) || - (pids->ppid != 0 && !mf->ppid)) { - put_pid(mf->pid); - put_pid(mf->tgid); - put_pid(mf->ppid); - mf->pid = NULL; - mf->tgid = NULL; - mf->ppid = NULL; - return -EINVAL; - } - - mf->valid |= KDBUS_ATTACH_PIDS; - } - - if (seclabel) { - mf->seclabel = kstrdup(seclabel, GFP_KERNEL); - if (!mf->seclabel) - return -ENOMEM; - - mf->valid |= KDBUS_ATTACH_SECLABEL; - } - - return 0; -} - -/** - * kdbus_meta_conn_new() - Create connection metadata object - * - * Return: Pointer to new object on success, ERR_PTR on failure. - */ -struct kdbus_meta_conn *kdbus_meta_conn_new(void) -{ - struct kdbus_meta_conn *mc; - - mc = kzalloc(sizeof(*mc), GFP_KERNEL); - if (!mc) - return ERR_PTR(-ENOMEM); - - kref_init(&mc->kref); - mutex_init(&mc->lock); - - return mc; -} - -static void kdbus_meta_conn_free(struct kref *kref) -{ - struct kdbus_meta_conn *mc = - container_of(kref, struct kdbus_meta_conn, kref); - - kfree(mc->conn_description); - kfree(mc->owned_names_items); - kfree(mc); -} - -/** - * kdbus_meta_conn_ref() - Gain reference - * @mc: Connection metadata object - */ -struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc) -{ - if (mc) - kref_get(&mc->kref); - return mc; -} - -/** - * kdbus_meta_conn_unref() - Drop reference - * @mc: Connection metadata object - */ -struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc) -{ - if (mc) - kref_put(&mc->kref, kdbus_meta_conn_free); - return NULL; -} - -static void kdbus_meta_conn_collect_timestamp(struct kdbus_meta_conn *mc, - u64 msg_seqnum) -{ - mc->ts.monotonic_ns = ktime_get_ns(); - mc->ts.realtime_ns = ktime_get_real_ns(); - - if (msg_seqnum) - mc->ts.seqnum = msg_seqnum; - - mc->valid |= KDBUS_ATTACH_TIMESTAMP; -} - -static int kdbus_meta_conn_collect_names(struct kdbus_meta_conn *mc, - struct kdbus_conn *conn) -{ - const struct kdbus_name_owner *owner; - struct kdbus_item *item; - size_t slen, size; - - lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); - - size = 0; - /* open-code length calculation to avoid final padding */ - list_for_each_entry(owner, &conn->names_list, conn_entry) - if (!(owner->flags & KDBUS_NAME_IN_QUEUE)) - size = KDBUS_ALIGN8(size) + KDBUS_ITEM_HEADER_SIZE + - sizeof(struct kdbus_name) + - strlen(owner->name->name) + 1; - - if (!size) - return 0; - - /* make sure we include zeroed padding for convenience helpers */ - item = kmalloc(KDBUS_ALIGN8(size), GFP_KERNEL); - if (!item) - return -ENOMEM; - - mc->owned_names_items = item; - mc->owned_names_size = size; - - list_for_each_entry(owner, &conn->names_list, conn_entry) { - if (owner->flags & KDBUS_NAME_IN_QUEUE) - continue; - - slen = strlen(owner->name->name) + 1; - kdbus_item_set(item, KDBUS_ITEM_OWNED_NAME, NULL, - sizeof(struct kdbus_name) + slen); - item->name.flags = owner->flags; - memcpy(item->name.name, owner->name->name, slen); - item = KDBUS_ITEM_NEXT(item); - } - - /* sanity check: the buffer should be completely written now */ - WARN_ON((u8 *)item != - (u8 *)mc->owned_names_items + KDBUS_ALIGN8(size)); - - mc->valid |= KDBUS_ATTACH_NAMES; - return 0; -} - -static int kdbus_meta_conn_collect_description(struct kdbus_meta_conn *mc, - struct kdbus_conn *conn) -{ - if (!conn->description) - return 0; - - mc->conn_description = kstrdup(conn->description, GFP_KERNEL); - if (!mc->conn_description) - return -ENOMEM; - - mc->valid |= KDBUS_ATTACH_CONN_DESCRIPTION; - return 0; -} - -/** - * kdbus_meta_conn_collect() - Collect connection metadata - * @mc: Message metadata object - * @conn: Connection to collect data from - * @msg_seqnum: Sequence number of the message to send - * @what: Attach flags to collect - * - * This collects connection metadata from @msg_seqnum and @conn and saves it - * in @mc. - * - * If KDBUS_ATTACH_NAMES is set in @what and @conn is non-NULL, the caller must - * hold the name-registry read-lock of conn->ep->bus->registry. - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, - struct kdbus_conn *conn, - u64 msg_seqnum, u64 what) -{ - int ret; - - if (!mc || !(what & (KDBUS_ATTACH_TIMESTAMP | - KDBUS_ATTACH_NAMES | - KDBUS_ATTACH_CONN_DESCRIPTION))) - return 0; - - mutex_lock(&mc->lock); - - if (msg_seqnum && (what & KDBUS_ATTACH_TIMESTAMP) && - !(mc->collected & KDBUS_ATTACH_TIMESTAMP)) { - kdbus_meta_conn_collect_timestamp(mc, msg_seqnum); - mc->collected |= KDBUS_ATTACH_TIMESTAMP; - } - - if (conn && (what & KDBUS_ATTACH_NAMES) && - !(mc->collected & KDBUS_ATTACH_NAMES)) { - ret = kdbus_meta_conn_collect_names(mc, conn); - if (ret < 0) - goto exit_unlock; - mc->collected |= KDBUS_ATTACH_NAMES; - } - - if (conn && (what & KDBUS_ATTACH_CONN_DESCRIPTION) && - !(mc->collected & KDBUS_ATTACH_CONN_DESCRIPTION)) { - ret = kdbus_meta_conn_collect_description(mc, conn); - if (ret < 0) - goto exit_unlock; - mc->collected |= KDBUS_ATTACH_CONN_DESCRIPTION; - } - - ret = 0; - -exit_unlock: - mutex_unlock(&mc->lock); - return ret; -} - -static void kdbus_meta_export_caps(struct kdbus_meta_caps *out, - const struct kdbus_meta_proc *mp, - struct user_namespace *user_ns) -{ - struct user_namespace *iter; - const struct cred *cred = mp->cred; - bool parent = false, owner = false; - int i; - - /* - * This translates the effective capabilities of 'cred' into the given - * user-namespace. If the given user-namespace is a child-namespace of - * the user-namespace of 'cred', the mask can be copied verbatim. If - * not, the mask is cleared. - * There's one exception: If 'cred' is the owner of any user-namespace - * in the path between the given user-namespace and the user-namespace - * of 'cred', then it has all effective capabilities set. This means, - * the user who created a user-namespace always has all effective - * capabilities in any child namespaces. Note that this is based on the - * uid of the namespace creator, not the task hierarchy. - */ - for (iter = user_ns; iter; iter = iter->parent) { - if (iter == cred->user_ns) { - parent = true; - break; - } - - if (iter == &init_user_ns) - break; - - if ((iter->parent == cred->user_ns) && - uid_eq(iter->owner, cred->euid)) { - owner = true; - break; - } - } - - out->last_cap = CAP_LAST_CAP; - - CAP_FOR_EACH_U32(i) { - if (parent) { - out->set[0].caps[i] = cred->cap_inheritable.cap[i]; - out->set[1].caps[i] = cred->cap_permitted.cap[i]; - out->set[2].caps[i] = cred->cap_effective.cap[i]; - out->set[3].caps[i] = cred->cap_bset.cap[i]; - } else if (owner) { - out->set[0].caps[i] = 0U; - out->set[1].caps[i] = ~0U; - out->set[2].caps[i] = ~0U; - out->set[3].caps[i] = ~0U; - } else { - out->set[0].caps[i] = 0U; - out->set[1].caps[i] = 0U; - out->set[2].caps[i] = 0U; - out->set[3].caps[i] = 0U; - } - } - - /* clear unused bits */ - for (i = 0; i < 4; i++) - out->set[i].caps[CAP_TO_INDEX(CAP_LAST_CAP)] &= - CAP_LAST_U32_VALID_MASK; -} - -/* This is equivalent to from_kuid_munged(), but maps INVALID_UID to itself */ -static uid_t kdbus_from_kuid_keep(struct user_namespace *ns, kuid_t uid) -{ - return uid_valid(uid) ? from_kuid_munged(ns, uid) : ((uid_t)-1); -} - -/* This is equivalent to from_kgid_munged(), but maps INVALID_GID to itself */ -static gid_t kdbus_from_kgid_keep(struct user_namespace *ns, kgid_t gid) -{ - return gid_valid(gid) ? from_kgid_munged(ns, gid) : ((gid_t)-1); -} - -struct kdbus_meta_staging { - const struct kdbus_meta_proc *mp; - const struct kdbus_meta_fake *mf; - const struct kdbus_meta_conn *mc; - const struct kdbus_conn *conn; - u64 mask; - - void *exe; - const char *exe_path; -}; - -static size_t kdbus_meta_measure(struct kdbus_meta_staging *staging) -{ - const struct kdbus_meta_proc *mp = staging->mp; - const struct kdbus_meta_fake *mf = staging->mf; - const struct kdbus_meta_conn *mc = staging->mc; - const u64 mask = staging->mask; - size_t size = 0; - - /* process metadata */ - - if (mf && (mask & KDBUS_ATTACH_CREDS)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); - else if (mp && (mask & KDBUS_ATTACH_CREDS)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); - - if (mf && (mask & KDBUS_ATTACH_PIDS)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); - else if (mp && (mask & KDBUS_ATTACH_PIDS)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_pids)); - - if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) - size += KDBUS_ITEM_SIZE(mp->cred->group_info->ngroups * - sizeof(u64)); - - if (mp && (mask & KDBUS_ATTACH_TID_COMM)) - size += KDBUS_ITEM_SIZE(strlen(mp->tid_comm) + 1); - - if (mp && (mask & KDBUS_ATTACH_PID_COMM)) - size += KDBUS_ITEM_SIZE(strlen(mp->pid_comm) + 1); - - if (staging->exe_path && (mask & KDBUS_ATTACH_EXE)) - size += KDBUS_ITEM_SIZE(strlen(staging->exe_path) + 1); - - if (mp && (mask & KDBUS_ATTACH_CMDLINE)) - size += KDBUS_ITEM_SIZE(strlen(mp->cmdline) + 1); - - if (mp && (mask & KDBUS_ATTACH_CGROUP)) - size += KDBUS_ITEM_SIZE(strlen(mp->cgroup) + 1); - - if (mp && (mask & KDBUS_ATTACH_CAPS)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_meta_caps)); - - if (mf && (mask & KDBUS_ATTACH_SECLABEL)) - size += KDBUS_ITEM_SIZE(strlen(mf->seclabel) + 1); - else if (mp && (mask & KDBUS_ATTACH_SECLABEL)) - size += KDBUS_ITEM_SIZE(strlen(mp->seclabel) + 1); - - if (mp && (mask & KDBUS_ATTACH_AUDIT)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_audit)); - - /* connection metadata */ - - if (mc && (mask & KDBUS_ATTACH_NAMES)) - size += KDBUS_ALIGN8(mc->owned_names_size); - - if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION)) - size += KDBUS_ITEM_SIZE(strlen(mc->conn_description) + 1); - - if (mc && (mask & KDBUS_ATTACH_TIMESTAMP)) - size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_timestamp)); - - return size; -} - -static struct kdbus_item *kdbus_write_head(struct kdbus_item **iter, - u64 type, u64 size) -{ - struct kdbus_item *item = *iter; - size_t padding; - - item->type = type; - item->size = KDBUS_ITEM_HEADER_SIZE + size; - - /* clear padding */ - padding = KDBUS_ALIGN8(item->size) - item->size; - if (padding) - memset(item->data + size, 0, padding); - - *iter = KDBUS_ITEM_NEXT(item); - return item; -} - -static struct kdbus_item *kdbus_write_full(struct kdbus_item **iter, - u64 type, u64 size, const void *data) -{ - struct kdbus_item *item; - - item = kdbus_write_head(iter, type, size); - memcpy(item->data, data, size); - return item; -} - -static size_t kdbus_meta_write(struct kdbus_meta_staging *staging, void *mem, - size_t size) -{ - struct user_namespace *user_ns = staging->conn->cred->user_ns; - struct pid_namespace *pid_ns = ns_of_pid(staging->conn->pid); - struct kdbus_item *item = NULL, *items = mem; - u8 *end, *owned_names_end = NULL; - - /* process metadata */ - - if (staging->mf && (staging->mask & KDBUS_ATTACH_CREDS)) { - const struct kdbus_meta_fake *mf = staging->mf; - - item = kdbus_write_head(&items, KDBUS_ITEM_CREDS, - sizeof(struct kdbus_creds)); - item->creds = (struct kdbus_creds){ - .uid = kdbus_from_kuid_keep(user_ns, mf->uid), - .euid = kdbus_from_kuid_keep(user_ns, mf->euid), - .suid = kdbus_from_kuid_keep(user_ns, mf->suid), - .fsuid = kdbus_from_kuid_keep(user_ns, mf->fsuid), - .gid = kdbus_from_kgid_keep(user_ns, mf->gid), - .egid = kdbus_from_kgid_keep(user_ns, mf->egid), - .sgid = kdbus_from_kgid_keep(user_ns, mf->sgid), - .fsgid = kdbus_from_kgid_keep(user_ns, mf->fsgid), - }; - } else if (staging->mp && (staging->mask & KDBUS_ATTACH_CREDS)) { - const struct cred *c = staging->mp->cred; - - item = kdbus_write_head(&items, KDBUS_ITEM_CREDS, - sizeof(struct kdbus_creds)); - item->creds = (struct kdbus_creds){ - .uid = kdbus_from_kuid_keep(user_ns, c->uid), - .euid = kdbus_from_kuid_keep(user_ns, c->euid), - .suid = kdbus_from_kuid_keep(user_ns, c->suid), - .fsuid = kdbus_from_kuid_keep(user_ns, c->fsuid), - .gid = kdbus_from_kgid_keep(user_ns, c->gid), - .egid = kdbus_from_kgid_keep(user_ns, c->egid), - .sgid = kdbus_from_kgid_keep(user_ns, c->sgid), - .fsgid = kdbus_from_kgid_keep(user_ns, c->fsgid), - }; - } - - if (staging->mf && (staging->mask & KDBUS_ATTACH_PIDS)) { - item = kdbus_write_head(&items, KDBUS_ITEM_PIDS, - sizeof(struct kdbus_pids)); - item->pids = (struct kdbus_pids){ - .pid = pid_nr_ns(staging->mf->tgid, pid_ns), - .tid = pid_nr_ns(staging->mf->pid, pid_ns), - .ppid = pid_nr_ns(staging->mf->ppid, pid_ns), - }; - } else if (staging->mp && (staging->mask & KDBUS_ATTACH_PIDS)) { - item = kdbus_write_head(&items, KDBUS_ITEM_PIDS, - sizeof(struct kdbus_pids)); - item->pids = (struct kdbus_pids){ - .pid = pid_nr_ns(staging->mp->tgid, pid_ns), - .tid = pid_nr_ns(staging->mp->pid, pid_ns), - .ppid = pid_nr_ns(staging->mp->ppid, pid_ns), - }; - } - - if (staging->mp && (staging->mask & KDBUS_ATTACH_AUXGROUPS)) { - const struct group_info *info = staging->mp->cred->group_info; - size_t i; - - item = kdbus_write_head(&items, KDBUS_ITEM_AUXGROUPS, - info->ngroups * sizeof(u64)); - for (i = 0; i < info->ngroups; ++i) - item->data64[i] = from_kgid_munged(user_ns, - GROUP_AT(info, i)); - } - - if (staging->mp && (staging->mask & KDBUS_ATTACH_TID_COMM)) - item = kdbus_write_full(&items, KDBUS_ITEM_TID_COMM, - strlen(staging->mp->tid_comm) + 1, - staging->mp->tid_comm); - - if (staging->mp && (staging->mask & KDBUS_ATTACH_PID_COMM)) - item = kdbus_write_full(&items, KDBUS_ITEM_PID_COMM, - strlen(staging->mp->pid_comm) + 1, - staging->mp->pid_comm); - - if (staging->exe_path && (staging->mask & KDBUS_ATTACH_EXE)) - item = kdbus_write_full(&items, KDBUS_ITEM_EXE, - strlen(staging->exe_path) + 1, - staging->exe_path); - - if (staging->mp && (staging->mask & KDBUS_ATTACH_CMDLINE)) - item = kdbus_write_full(&items, KDBUS_ITEM_CMDLINE, - strlen(staging->mp->cmdline) + 1, - staging->mp->cmdline); - - if (staging->mp && (staging->mask & KDBUS_ATTACH_CGROUP)) - item = kdbus_write_full(&items, KDBUS_ITEM_CGROUP, - strlen(staging->mp->cgroup) + 1, - staging->mp->cgroup); - - if (staging->mp && (staging->mask & KDBUS_ATTACH_CAPS)) { - item = kdbus_write_head(&items, KDBUS_ITEM_CAPS, - sizeof(struct kdbus_meta_caps)); - kdbus_meta_export_caps((void*)&item->caps, staging->mp, - user_ns); - } - - if (staging->mf && (staging->mask & KDBUS_ATTACH_SECLABEL)) - item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL, - strlen(staging->mf->seclabel) + 1, - staging->mf->seclabel); - else if (staging->mp && (staging->mask & KDBUS_ATTACH_SECLABEL)) - item = kdbus_write_full(&items, KDBUS_ITEM_SECLABEL, - strlen(staging->mp->seclabel) + 1, - staging->mp->seclabel); - - if (staging->mp && (staging->mask & KDBUS_ATTACH_AUDIT)) { - item = kdbus_write_head(&items, KDBUS_ITEM_AUDIT, - sizeof(struct kdbus_audit)); - item->audit = (struct kdbus_audit){ - .loginuid = from_kuid(user_ns, - staging->mp->audit_loginuid), - .sessionid = staging->mp->audit_sessionid, - }; - } - - /* connection metadata */ - - if (staging->mc && (staging->mask & KDBUS_ATTACH_NAMES)) { - memcpy(items, staging->mc->owned_names_items, - KDBUS_ALIGN8(staging->mc->owned_names_size)); - owned_names_end = (u8 *)items + staging->mc->owned_names_size; - items = (void *)KDBUS_ALIGN8((unsigned long)owned_names_end); - } - - if (staging->mc && (staging->mask & KDBUS_ATTACH_CONN_DESCRIPTION)) - item = kdbus_write_full(&items, KDBUS_ITEM_CONN_DESCRIPTION, - strlen(staging->mc->conn_description) + 1, - staging->mc->conn_description); - - if (staging->mc && (staging->mask & KDBUS_ATTACH_TIMESTAMP)) - item = kdbus_write_full(&items, KDBUS_ITEM_TIMESTAMP, - sizeof(staging->mc->ts), - &staging->mc->ts); - - /* - * Return real size (minus trailing padding). In case of 'owned_names' - * we cannot deduce it from item->size, so treat it special. - */ - - if (items == (void *)KDBUS_ALIGN8((unsigned long)owned_names_end)) - end = owned_names_end; - else if (item) - end = (u8 *)item + item->size; - else - end = mem; - - WARN_ON((u8 *)items - (u8 *)mem != size); - WARN_ON((void *)KDBUS_ALIGN8((unsigned long)end) != (void *)items); - - return end - (u8 *)mem; -} - -int kdbus_meta_emit(struct kdbus_meta_proc *mp, - struct kdbus_meta_fake *mf, - struct kdbus_meta_conn *mc, - struct kdbus_conn *conn, - u64 mask, - struct kdbus_item **out_items, - size_t *out_size) -{ - struct kdbus_meta_staging staging = {}; - struct kdbus_item *items = NULL; - size_t size = 0; - int ret; - - if (WARN_ON(mf && mp)) - mp = NULL; - - staging.mp = mp; - staging.mf = mf; - staging.mc = mc; - staging.conn = conn; - - /* get mask of valid items */ - if (mf) - staging.mask |= mf->valid; - if (mp) { - mutex_lock(&mp->lock); - staging.mask |= mp->valid; - mutex_unlock(&mp->lock); - } - if (mc) { - mutex_lock(&mc->lock); - staging.mask |= mc->valid; - mutex_unlock(&mc->lock); - } - - staging.mask &= mask; - - if (!staging.mask) { /* bail out if nothing to do */ - ret = 0; - goto exit; - } - - /* EXE is special as it needs a temporary page to assemble */ - if (mp && (staging.mask & KDBUS_ATTACH_EXE)) { - struct path p; - - /* - * XXX: We need access to __d_path() so we can write the path - * relative to conn->root_path. Once upstream, we need - * EXPORT_SYMBOL(__d_path) or an equivalent of d_path() that - * takes the root path directly. Until then, we drop this item - * if the root-paths differ. - */ - - get_fs_root(current->fs, &p); - if (path_equal(&p, &conn->root_path)) { - staging.exe = (void *)__get_free_page(GFP_TEMPORARY); - if (!staging.exe) { - path_put(&p); - ret = -ENOMEM; - goto exit; - } - - staging.exe_path = d_path(&mp->exe_path, staging.exe, - PAGE_SIZE); - if (IS_ERR(staging.exe_path)) { - path_put(&p); - ret = PTR_ERR(staging.exe_path); - goto exit; - } - } - path_put(&p); - } - - size = kdbus_meta_measure(&staging); - if (!size) { /* bail out if nothing to do */ - ret = 0; - goto exit; - } - - items = kmalloc(size, GFP_KERNEL); - if (!items) { - ret = -ENOMEM; - goto exit; - } - - size = kdbus_meta_write(&staging, items, size); - if (!size) { - kfree(items); - items = NULL; - } - - ret = 0; - -exit: - if (staging.exe) - free_page((unsigned long)staging.exe); - if (ret >= 0) { - *out_items = items; - *out_size = size; - } - return ret; -} - -enum { - KDBUS_META_PROC_NONE, - KDBUS_META_PROC_NORMAL, -}; - -/** - * kdbus_proc_permission() - check /proc permissions on target pid - * @pid_ns: namespace we operate in - * @cred: credentials of requestor - * @target: target process - * - * This checks whether a process with credentials @cred can access information - * of @target in the namespace @pid_ns. This tries to follow /proc permissions, - * but is slightly more restrictive. - * - * Return: The /proc access level (KDBUS_META_PROC_*) is returned. - */ -static unsigned int kdbus_proc_permission(const struct pid_namespace *pid_ns, - const struct cred *cred, - struct pid *target) -{ - if (pid_ns->hide_pid < 1) - return KDBUS_META_PROC_NORMAL; - - /* XXX: we need groups_search() exported for aux-groups */ - if (gid_eq(cred->egid, pid_ns->pid_gid)) - return KDBUS_META_PROC_NORMAL; - - /* - * XXX: If ptrace_may_access(PTRACE_MODE_READ) is granted, you can - * overwrite hide_pid. However, ptrace_may_access() only supports - * checking 'current', hence, we cannot use this here. But we - * simply decide to not support this override, so no need to worry. - */ - - return KDBUS_META_PROC_NONE; -} - -/** - * kdbus_meta_proc_mask() - calculate which metadata would be visible to - * a connection via /proc - * @prv_pid: pid of metadata provider - * @req_pid: pid of metadata requestor - * @req_cred: credentials of metadata reqeuestor - * @wanted: metadata that is requested - * - * This checks which metadata items of @prv_pid can be read via /proc by the - * requestor @req_pid. - * - * Return: Set of metadata flags the requestor can see (limited by @wanted). - */ -static u64 kdbus_meta_proc_mask(struct pid *prv_pid, - struct pid *req_pid, - const struct cred *req_cred, - u64 wanted) -{ - struct pid_namespace *prv_ns, *req_ns; - unsigned int proc; - - prv_ns = ns_of_pid(prv_pid); - req_ns = ns_of_pid(req_pid); - - /* - * If the sender is not visible in the receiver namespace, then the - * receiver cannot access the sender via its own procfs. Hence, we do - * not attach any additional metadata. - */ - if (!pid_nr_ns(prv_pid, req_ns)) - return 0; - - /* - * If the pid-namespace of the receiver has hide_pid set, it cannot see - * any process but its own. We shortcut this /proc permission check if - * provider and requestor are the same. If not, we perform rather - * expensive /proc permission checks. - */ - if (prv_pid == req_pid) - proc = KDBUS_META_PROC_NORMAL; - else - proc = kdbus_proc_permission(req_ns, req_cred, prv_pid); - - /* you need /proc access to read standard process attributes */ - if (proc < KDBUS_META_PROC_NORMAL) - wanted &= ~(KDBUS_ATTACH_TID_COMM | - KDBUS_ATTACH_PID_COMM | - KDBUS_ATTACH_SECLABEL | - KDBUS_ATTACH_CMDLINE | - KDBUS_ATTACH_CGROUP | - KDBUS_ATTACH_AUDIT | - KDBUS_ATTACH_CAPS | - KDBUS_ATTACH_EXE); - - /* clear all non-/proc flags */ - return wanted & (KDBUS_ATTACH_TID_COMM | - KDBUS_ATTACH_PID_COMM | - KDBUS_ATTACH_SECLABEL | - KDBUS_ATTACH_CMDLINE | - KDBUS_ATTACH_CGROUP | - KDBUS_ATTACH_AUDIT | - KDBUS_ATTACH_CAPS | - KDBUS_ATTACH_EXE); -} - -/** - * kdbus_meta_get_mask() - calculate attach flags mask for metadata request - * @prv_pid: pid of metadata provider - * @prv_mask: mask of metadata the provide grants unchecked - * @req_pid: pid of metadata requestor - * @req_cred: credentials of metadata requestor - * @req_mask: mask of metadata that is requested - * - * This calculates the metadata items that the requestor @req_pid can access - * from the metadata provider @prv_pid. This permission check consists of - * several different parts: - * - Providers can grant metadata items unchecked. Regardless of their type, - * they're always granted to the requestor. This mask is passed as @prv_mask. - * - Basic items (credentials and connection metadata) are granted implicitly - * to everyone. They're publicly available to any bus-user that can see the - * provider. - * - Process credentials that are not granted implicitly follow the same - * permission checks as /proc. This means, we always assume a requestor - * process has access to their *own* /proc mount, if they have access to - * kdbusfs. - * - * Return: Mask of metadata that is granted. - */ -static u64 kdbus_meta_get_mask(struct pid *prv_pid, u64 prv_mask, - struct pid *req_pid, - const struct cred *req_cred, u64 req_mask) -{ - u64 missing, impl_mask, proc_mask = 0; - - /* - * Connection metadata and basic unix process credentials are - * transmitted implicitly, and cannot be suppressed. Both are required - * to perform user-space policies on the receiver-side. Furthermore, - * connection metadata is public state, anyway, and unix credentials - * are needed for UDS-compatibility. We extend them slightly by - * auxiliary groups and additional uids/gids/pids. - */ - impl_mask = /* connection metadata */ - KDBUS_ATTACH_CONN_DESCRIPTION | - KDBUS_ATTACH_TIMESTAMP | - KDBUS_ATTACH_NAMES | - /* credentials and pids */ - KDBUS_ATTACH_AUXGROUPS | - KDBUS_ATTACH_CREDS | - KDBUS_ATTACH_PIDS; - - /* - * Calculate the set of metadata that is not granted implicitly nor by - * the sender, but still requested by the receiver. If any are left, - * perform rather expensive /proc access checks for them. - */ - missing = req_mask & ~((prv_mask | impl_mask) & req_mask); - if (missing) - proc_mask = kdbus_meta_proc_mask(prv_pid, req_pid, req_cred, - missing); - - return (prv_mask | impl_mask | proc_mask) & req_mask; -} - -/** - */ -u64 kdbus_meta_info_mask(const struct kdbus_conn *conn, u64 mask) -{ - return kdbus_meta_get_mask(conn->pid, - atomic64_read(&conn->attach_flags_send), - task_pid(current), - current_cred(), - mask); -} - -/** - */ -u64 kdbus_meta_msg_mask(const struct kdbus_conn *snd, - const struct kdbus_conn *rcv) -{ - return kdbus_meta_get_mask(task_pid(current), - atomic64_read(&snd->attach_flags_send), - rcv->pid, - rcv->cred, - atomic64_read(&rcv->attach_flags_recv)); -} diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h deleted file mode 100644 index dba7cc7fd..000000000 --- a/ipc/kdbus/metadata.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_METADATA_H -#define __KDBUS_METADATA_H - -#include <linux/kernel.h> - -struct kdbus_conn; -struct kdbus_pool_slice; - -struct kdbus_meta_proc; -struct kdbus_meta_conn; - -/** - * struct kdbus_meta_fake - Fake metadata - * @valid: Bitmask of collected and valid items - * @uid: UID of process - * @euid: EUID of process - * @suid: SUID of process - * @fsuid: FSUID of process - * @gid: GID of process - * @egid: EGID of process - * @sgid: SGID of process - * @fsgid: FSGID of process - * @pid: PID of process - * @tgid: TGID of process - * @ppid: PPID of process - * @seclabel: Seclabel - */ -struct kdbus_meta_fake { - u64 valid; - - /* KDBUS_ITEM_CREDS */ - kuid_t uid, euid, suid, fsuid; - kgid_t gid, egid, sgid, fsgid; - - /* KDBUS_ITEM_PIDS */ - struct pid *pid, *tgid, *ppid; - - /* KDBUS_ITEM_SECLABEL */ - char *seclabel; -}; - -struct kdbus_meta_proc *kdbus_meta_proc_new(void); -struct kdbus_meta_proc *kdbus_meta_proc_ref(struct kdbus_meta_proc *mp); -struct kdbus_meta_proc *kdbus_meta_proc_unref(struct kdbus_meta_proc *mp); -int kdbus_meta_proc_collect(struct kdbus_meta_proc *mp, u64 what); - -struct kdbus_meta_fake *kdbus_meta_fake_new(void); -struct kdbus_meta_fake *kdbus_meta_fake_free(struct kdbus_meta_fake *mf); -int kdbus_meta_fake_collect(struct kdbus_meta_fake *mf, - const struct kdbus_creds *creds, - const struct kdbus_pids *pids, - const char *seclabel); - -struct kdbus_meta_conn *kdbus_meta_conn_new(void); -struct kdbus_meta_conn *kdbus_meta_conn_ref(struct kdbus_meta_conn *mc); -struct kdbus_meta_conn *kdbus_meta_conn_unref(struct kdbus_meta_conn *mc); -int kdbus_meta_conn_collect(struct kdbus_meta_conn *mc, - struct kdbus_conn *conn, - u64 msg_seqnum, u64 what); - -int kdbus_meta_emit(struct kdbus_meta_proc *mp, - struct kdbus_meta_fake *mf, - struct kdbus_meta_conn *mc, - struct kdbus_conn *conn, - u64 mask, - struct kdbus_item **out_items, - size_t *out_size); -u64 kdbus_meta_info_mask(const struct kdbus_conn *conn, u64 mask); -u64 kdbus_meta_msg_mask(const struct kdbus_conn *snd, - const struct kdbus_conn *rcv); - -#endif diff --git a/ipc/kdbus/names.c b/ipc/kdbus/names.c deleted file mode 100644 index bf44ca3f1..000000000 --- a/ipc/kdbus/names.c +++ /dev/null @@ -1,854 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/ctype.h> -#include <linux/fs.h> -#include <linux/hash.h> -#include <linux/idr.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/rwsem.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/uio.h> - -#include "bus.h" -#include "connection.h" -#include "endpoint.h" -#include "handle.h" -#include "item.h" -#include "names.h" -#include "notify.h" -#include "policy.h" - -#define KDBUS_NAME_SAVED_MASK (KDBUS_NAME_ALLOW_REPLACEMENT | \ - KDBUS_NAME_QUEUE) - -static bool kdbus_name_owner_is_used(struct kdbus_name_owner *owner) -{ - return !list_empty(&owner->name_entry) || - owner == owner->name->activator; -} - -static struct kdbus_name_owner * -kdbus_name_owner_new(struct kdbus_conn *conn, struct kdbus_name_entry *name, - u64 flags) -{ - struct kdbus_name_owner *owner; - - kdbus_conn_assert_active(conn); - - if (conn->name_count >= KDBUS_CONN_MAX_NAMES) - return ERR_PTR(-E2BIG); - - owner = kmalloc(sizeof(*owner), GFP_KERNEL); - if (!owner) - return ERR_PTR(-ENOMEM); - - owner->flags = flags & KDBUS_NAME_SAVED_MASK; - owner->conn = conn; - owner->name = name; - list_add_tail(&owner->conn_entry, &conn->names_list); - INIT_LIST_HEAD(&owner->name_entry); - - ++conn->name_count; - return owner; -} - -static void kdbus_name_owner_free(struct kdbus_name_owner *owner) -{ - if (!owner) - return; - - WARN_ON(kdbus_name_owner_is_used(owner)); - --owner->conn->name_count; - list_del(&owner->conn_entry); - kfree(owner); -} - -static struct kdbus_name_owner * -kdbus_name_owner_find(struct kdbus_name_entry *name, struct kdbus_conn *conn) -{ - struct kdbus_name_owner *owner; - - /* - * Use conn->names_list over name->queue to make sure boundaries of - * this linear search are controlled by the connection itself. - * Furthermore, this will find normal owners as well as activators - * without any additional code. - */ - list_for_each_entry(owner, &conn->names_list, conn_entry) - if (owner->name == name) - return owner; - - return NULL; -} - -static bool kdbus_name_entry_is_used(struct kdbus_name_entry *name) -{ - return !list_empty(&name->queue) || name->activator; -} - -static struct kdbus_name_owner * -kdbus_name_entry_first(struct kdbus_name_entry *name) -{ - return list_first_entry_or_null(&name->queue, struct kdbus_name_owner, - name_entry); -} - -static struct kdbus_name_entry * -kdbus_name_entry_new(struct kdbus_name_registry *r, u32 hash, - const char *name_str) -{ - struct kdbus_name_entry *name; - size_t namelen; - - lockdep_assert_held(&r->rwlock); - - namelen = strlen(name_str); - - name = kmalloc(sizeof(*name) + namelen + 1, GFP_KERNEL); - if (!name) - return ERR_PTR(-ENOMEM); - - name->name_id = ++r->name_seq_last; - name->activator = NULL; - INIT_LIST_HEAD(&name->queue); - hash_add(r->entries_hash, &name->hentry, hash); - memcpy(name->name, name_str, namelen + 1); - - return name; -} - -static void kdbus_name_entry_free(struct kdbus_name_entry *name) -{ - if (!name) - return; - - WARN_ON(kdbus_name_entry_is_used(name)); - hash_del(&name->hentry); - kfree(name); -} - -static struct kdbus_name_entry * -kdbus_name_entry_find(struct kdbus_name_registry *r, u32 hash, - const char *name_str) -{ - struct kdbus_name_entry *name; - - lockdep_assert_held(&r->rwlock); - - hash_for_each_possible(r->entries_hash, name, hentry, hash) - if (!strcmp(name->name, name_str)) - return name; - - return NULL; -} - -/** - * kdbus_name_registry_new() - create a new name registry - * - * Return: a new kdbus_name_registry on success, ERR_PTR on failure. - */ -struct kdbus_name_registry *kdbus_name_registry_new(void) -{ - struct kdbus_name_registry *r; - - r = kmalloc(sizeof(*r), GFP_KERNEL); - if (!r) - return ERR_PTR(-ENOMEM); - - hash_init(r->entries_hash); - init_rwsem(&r->rwlock); - r->name_seq_last = 0; - - return r; -} - -/** - * kdbus_name_registry_free() - free name registry - * @r: name registry to free, or NULL - * - * Free a name registry and cleanup all internal objects. This is a no-op if - * you pass NULL as registry. - */ -void kdbus_name_registry_free(struct kdbus_name_registry *r) -{ - if (!r) - return; - - WARN_ON(!hash_empty(r->entries_hash)); - kfree(r); -} - -/** - * kdbus_name_lookup_unlocked() - lookup name in registry - * @reg: name registry - * @name: name to lookup - * - * This looks up @name in the given name-registry and returns the - * kdbus_name_entry object. The caller must hold the registry-lock and must not - * access the returned object after releasing the lock. - * - * Return: Pointer to name-entry, or NULL if not found. - */ -struct kdbus_name_entry * -kdbus_name_lookup_unlocked(struct kdbus_name_registry *reg, const char *name) -{ - return kdbus_name_entry_find(reg, kdbus_strhash(name), name); -} - -static int kdbus_name_become_activator(struct kdbus_name_owner *owner, - u64 *return_flags) -{ - if (kdbus_name_owner_is_used(owner)) - return -EALREADY; - if (owner->name->activator) - return -EEXIST; - - owner->name->activator = owner; - owner->flags |= KDBUS_NAME_ACTIVATOR; - - if (kdbus_name_entry_first(owner->name)) { - owner->flags |= KDBUS_NAME_IN_QUEUE; - } else { - owner->flags |= KDBUS_NAME_PRIMARY; - kdbus_notify_name_change(owner->conn->ep->bus, - KDBUS_ITEM_NAME_ADD, - 0, owner->conn->id, - 0, owner->flags, - owner->name->name); - } - - if (return_flags) - *return_flags = owner->flags | KDBUS_NAME_ACQUIRED; - - return 0; -} - -static int kdbus_name_update(struct kdbus_name_owner *owner, u64 flags, - u64 *return_flags) -{ - struct kdbus_name_owner *primary, *activator; - struct kdbus_name_entry *name; - struct kdbus_bus *bus; - u64 nflags = 0; - int ret = 0; - - name = owner->name; - bus = owner->conn->ep->bus; - primary = kdbus_name_entry_first(name); - activator = name->activator; - - /* cannot be activator and acquire a name */ - if (owner == activator) - return -EUCLEAN; - - /* update saved flags */ - owner->flags = flags & KDBUS_NAME_SAVED_MASK; - - if (!primary) { - /* - * No primary owner (but maybe an activator). Take over the - * name. - */ - - list_add(&owner->name_entry, &name->queue); - owner->flags |= KDBUS_NAME_PRIMARY; - nflags |= KDBUS_NAME_ACQUIRED; - - /* move messages to new owner on activation */ - if (activator) { - kdbus_conn_move_messages(owner->conn, activator->conn, - name->name_id); - kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_CHANGE, - activator->conn->id, owner->conn->id, - activator->flags, owner->flags, - name->name); - activator->flags &= ~KDBUS_NAME_PRIMARY; - activator->flags |= KDBUS_NAME_IN_QUEUE; - } else { - kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_ADD, - 0, owner->conn->id, - 0, owner->flags, - name->name); - } - - } else if (owner == primary) { - /* - * Already the primary owner of the name, flags were already - * updated. Nothing to do. - */ - - owner->flags |= KDBUS_NAME_PRIMARY; - - } else if ((primary->flags & KDBUS_NAME_ALLOW_REPLACEMENT) && - (flags & KDBUS_NAME_REPLACE_EXISTING)) { - /* - * We're not the primary owner but can replace it. Move us - * ahead of the primary owner and acquire the name (possibly - * skipping queued owners ahead of us). - */ - - list_del_init(&owner->name_entry); - list_add(&owner->name_entry, &name->queue); - owner->flags |= KDBUS_NAME_PRIMARY; - nflags |= KDBUS_NAME_ACQUIRED; - - kdbus_notify_name_change(bus, KDBUS_ITEM_NAME_CHANGE, - primary->conn->id, owner->conn->id, - primary->flags, owner->flags, - name->name); - - /* requeue old primary, or drop if queueing not wanted */ - if (primary->flags & KDBUS_NAME_QUEUE) { - primary->flags &= ~KDBUS_NAME_PRIMARY; - primary->flags |= KDBUS_NAME_IN_QUEUE; - } else { - list_del_init(&primary->name_entry); - kdbus_name_owner_free(primary); - } - - } else if (flags & KDBUS_NAME_QUEUE) { - /* - * Name is already occupied and we cannot take it over, but - * queuing is allowed. Put us silently on the queue, if not - * already there. - */ - - owner->flags |= KDBUS_NAME_IN_QUEUE; - if (!kdbus_name_owner_is_used(owner)) { - list_add_tail(&owner->name_entry, &name->queue); - nflags |= KDBUS_NAME_ACQUIRED; - } - } else if (kdbus_name_owner_is_used(owner)) { - /* - * Already queued on name, but re-queueing was not requested. - * Make sure to unlink it from the name, the caller is - * responsible for releasing it. - */ - - list_del_init(&owner->name_entry); - } else { - /* - * Name is already claimed and queueing is not requested. - * Return error to the caller. - */ - - ret = -EEXIST; - } - - if (return_flags) - *return_flags = owner->flags | nflags; - - return ret; -} - -int kdbus_name_acquire(struct kdbus_name_registry *reg, - struct kdbus_conn *conn, const char *name_str, - u64 flags, u64 *return_flags) -{ - struct kdbus_name_entry *name = NULL; - struct kdbus_name_owner *owner = NULL; - u32 hash; - int ret; - - kdbus_conn_assert_active(conn); - - down_write(®->rwlock); - - /* - * Verify the connection has access to the name. Do this before testing - * for double-acquisitions and other errors to make sure we do not leak - * information about this name through possible custom endpoints. - */ - if (!kdbus_conn_policy_own_name(conn, current_cred(), name_str)) { - ret = -EPERM; - goto exit; - } - - /* - * Lookup the name entry. If it already exists, search for an owner - * entry as we might already own that name. If either does not exist, - * we will allocate a fresh one. - */ - hash = kdbus_strhash(name_str); - name = kdbus_name_entry_find(reg, hash, name_str); - if (name) { - owner = kdbus_name_owner_find(name, conn); - } else { - name = kdbus_name_entry_new(reg, hash, name_str); - if (IS_ERR(name)) { - ret = PTR_ERR(name); - name = NULL; - goto exit; - } - } - - /* create name owner object if not already queued */ - if (!owner) { - owner = kdbus_name_owner_new(conn, name, flags); - if (IS_ERR(owner)) { - ret = PTR_ERR(owner); - owner = NULL; - goto exit; - } - } - - if (flags & KDBUS_NAME_ACTIVATOR) - ret = kdbus_name_become_activator(owner, return_flags); - else - ret = kdbus_name_update(owner, flags, return_flags); - if (ret < 0) - goto exit; - -exit: - if (owner && !kdbus_name_owner_is_used(owner)) - kdbus_name_owner_free(owner); - if (name && !kdbus_name_entry_is_used(name)) - kdbus_name_entry_free(name); - up_write(®->rwlock); - kdbus_notify_flush(conn->ep->bus); - return ret; -} - -static void kdbus_name_release_unlocked(struct kdbus_name_owner *owner) -{ - struct kdbus_name_owner *primary, *next; - struct kdbus_name_entry *name; - - name = owner->name; - primary = kdbus_name_entry_first(name); - - list_del_init(&owner->name_entry); - if (owner == name->activator) - name->activator = NULL; - - if (!primary || owner == primary) { - next = kdbus_name_entry_first(name); - if (!next) - next = name->activator; - - if (next) { - /* hand to next in queue */ - next->flags &= ~KDBUS_NAME_IN_QUEUE; - next->flags |= KDBUS_NAME_PRIMARY; - if (next == name->activator) - kdbus_conn_move_messages(next->conn, - owner->conn, - name->name_id); - - kdbus_notify_name_change(owner->conn->ep->bus, - KDBUS_ITEM_NAME_CHANGE, - owner->conn->id, next->conn->id, - owner->flags, next->flags, - name->name); - } else { - kdbus_notify_name_change(owner->conn->ep->bus, - KDBUS_ITEM_NAME_REMOVE, - owner->conn->id, 0, - owner->flags, 0, - name->name); - } - } - - kdbus_name_owner_free(owner); - if (!kdbus_name_entry_is_used(name)) - kdbus_name_entry_free(name); -} - -static int kdbus_name_release(struct kdbus_name_registry *reg, - struct kdbus_conn *conn, - const char *name_str) -{ - struct kdbus_name_owner *owner; - struct kdbus_name_entry *name; - int ret = 0; - - down_write(®->rwlock); - name = kdbus_name_entry_find(reg, kdbus_strhash(name_str), name_str); - if (name) { - owner = kdbus_name_owner_find(name, conn); - if (owner) - kdbus_name_release_unlocked(owner); - else - ret = -EADDRINUSE; - } else { - ret = -ESRCH; - } - up_write(®->rwlock); - - kdbus_notify_flush(conn->ep->bus); - return ret; -} - -/** - * kdbus_name_release_all() - remove all name entries of a given connection - * @reg: name registry - * @conn: connection - */ -void kdbus_name_release_all(struct kdbus_name_registry *reg, - struct kdbus_conn *conn) -{ - struct kdbus_name_owner *owner; - - down_write(®->rwlock); - - while ((owner = list_first_entry_or_null(&conn->names_list, - struct kdbus_name_owner, - conn_entry))) - kdbus_name_release_unlocked(owner); - - up_write(®->rwlock); - - kdbus_notify_flush(conn->ep->bus); -} - -/** - * kdbus_name_is_valid() - check if a name is valid - * @p: The name to check - * @allow_wildcard: Whether or not to allow a wildcard name - * - * A name is valid if all of the following criterias are met: - * - * - The name has two or more elements separated by a period ('.') character. - * - All elements must contain at least one character. - * - Each element must only contain the ASCII characters "[A-Z][a-z][0-9]_-" - * and must not begin with a digit. - * - The name must not exceed KDBUS_NAME_MAX_LEN. - * - If @allow_wildcard is true, the name may end on '.*' - */ -bool kdbus_name_is_valid(const char *p, bool allow_wildcard) -{ - bool dot, found_dot = false; - const char *q; - - for (dot = true, q = p; *q; q++) { - if (*q == '.') { - if (dot) - return false; - - found_dot = true; - dot = true; - } else { - bool good; - - good = isalpha(*q) || (!dot && isdigit(*q)) || - *q == '_' || *q == '-' || - (allow_wildcard && dot && - *q == '*' && *(q + 1) == '\0'); - - if (!good) - return false; - - dot = false; - } - } - - if (q - p > KDBUS_NAME_MAX_LEN) - return false; - - if (dot) - return false; - - if (!found_dot) - return false; - - return true; -} - -/** - * kdbus_cmd_name_acquire() - handle KDBUS_CMD_NAME_ACQUIRE - * @conn: connection to operate on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp) -{ - const char *item_name; - struct kdbus_cmd *cmd; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_NAME, .mandatory = true }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE | - KDBUS_NAME_REPLACE_EXISTING | - KDBUS_NAME_ALLOW_REPLACEMENT | - KDBUS_NAME_QUEUE, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - if (!kdbus_conn_is_ordinary(conn)) - return -EOPNOTSUPP; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - item_name = argv[1].item->str; - if (!kdbus_name_is_valid(item_name, false)) { - ret = -EINVAL; - goto exit; - } - - ret = kdbus_name_acquire(conn->ep->bus->name_registry, conn, item_name, - cmd->flags, &cmd->return_flags); - -exit: - return kdbus_args_clear(&args, ret); -} - -/** - * kdbus_cmd_name_release() - handle KDBUS_CMD_NAME_RELEASE - * @conn: connection to operate on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_name_release(struct kdbus_conn *conn, void __user *argp) -{ - struct kdbus_cmd *cmd; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - { .type = KDBUS_ITEM_NAME, .mandatory = true }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - if (!kdbus_conn_is_ordinary(conn)) - return -EOPNOTSUPP; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - ret = kdbus_name_release(conn->ep->bus->name_registry, conn, - argv[1].item->str); - return kdbus_args_clear(&args, ret); -} - -static int kdbus_list_write(struct kdbus_conn *conn, - struct kdbus_conn *c, - struct kdbus_pool_slice *slice, - size_t *pos, - struct kdbus_name_owner *o, - bool write) -{ - struct kvec kvec[4]; - size_t cnt = 0; - int ret; - - /* info header */ - struct kdbus_info info = { - .size = 0, - .id = c->id, - .flags = c->flags, - }; - - /* fake the header of a kdbus_name item */ - struct { - u64 size; - u64 type; - u64 flags; - } h = {}; - - if (o && !kdbus_conn_policy_see_name_unlocked(conn, current_cred(), - o->name->name)) - return 0; - - kdbus_kvec_set(&kvec[cnt++], &info, sizeof(info), &info.size); - - /* append name */ - if (o) { - size_t slen = strlen(o->name->name) + 1; - - h.size = offsetof(struct kdbus_item, name.name) + slen; - h.type = KDBUS_ITEM_OWNED_NAME; - h.flags = o->flags; - - kdbus_kvec_set(&kvec[cnt++], &h, sizeof(h), &info.size); - kdbus_kvec_set(&kvec[cnt++], o->name->name, slen, &info.size); - cnt += !!kdbus_kvec_pad(&kvec[cnt], &info.size); - } - - if (write) { - ret = kdbus_pool_slice_copy_kvec(slice, *pos, kvec, - cnt, info.size); - if (ret < 0) - return ret; - } - - *pos += info.size; - return 0; -} - -static int kdbus_list_all(struct kdbus_conn *conn, u64 flags, - struct kdbus_pool_slice *slice, - size_t *pos, bool write) -{ - struct kdbus_conn *c; - size_t p = *pos; - int ret, i; - - hash_for_each(conn->ep->bus->conn_hash, i, c, hentry) { - bool added = false; - - /* skip monitors */ - if (kdbus_conn_is_monitor(c)) - continue; - - /* all names the connection owns */ - if (flags & (KDBUS_LIST_NAMES | - KDBUS_LIST_ACTIVATORS | - KDBUS_LIST_QUEUED)) { - struct kdbus_name_owner *o; - - list_for_each_entry(o, &c->names_list, conn_entry) { - if (o->flags & KDBUS_NAME_ACTIVATOR) { - if (!(flags & KDBUS_LIST_ACTIVATORS)) - continue; - - ret = kdbus_list_write(conn, c, slice, - &p, o, write); - if (ret < 0) { - mutex_unlock(&c->lock); - return ret; - } - - added = true; - } else if (o->flags & KDBUS_NAME_IN_QUEUE) { - if (!(flags & KDBUS_LIST_QUEUED)) - continue; - - ret = kdbus_list_write(conn, c, slice, - &p, o, write); - if (ret < 0) { - mutex_unlock(&c->lock); - return ret; - } - - added = true; - } else if (flags & KDBUS_LIST_NAMES) { - ret = kdbus_list_write(conn, c, slice, - &p, o, write); - if (ret < 0) { - mutex_unlock(&c->lock); - return ret; - } - - added = true; - } - } - } - - /* nothing added so far, just add the unique ID */ - if (!added && (flags & KDBUS_LIST_UNIQUE)) { - ret = kdbus_list_write(conn, c, slice, &p, NULL, write); - if (ret < 0) - return ret; - } - } - - *pos = p; - return 0; -} - -/** - * kdbus_cmd_list() - handle KDBUS_CMD_LIST - * @conn: connection to operate on - * @argp: command payload - * - * Return: >=0 on success, negative error code on failure. - */ -int kdbus_cmd_list(struct kdbus_conn *conn, void __user *argp) -{ - struct kdbus_name_registry *reg = conn->ep->bus->name_registry; - struct kdbus_pool_slice *slice = NULL; - struct kdbus_cmd_list *cmd; - size_t pos, size; - int ret; - - struct kdbus_arg argv[] = { - { .type = KDBUS_ITEM_NEGOTIATE }, - }; - struct kdbus_args args = { - .allowed_flags = KDBUS_FLAG_NEGOTIATE | - KDBUS_LIST_UNIQUE | - KDBUS_LIST_NAMES | - KDBUS_LIST_ACTIVATORS | - KDBUS_LIST_QUEUED, - .argv = argv, - .argc = ARRAY_SIZE(argv), - }; - - ret = kdbus_args_parse(&args, argp, &cmd); - if (ret != 0) - return ret; - - /* lock order: domain -> bus -> ep -> names -> conn */ - down_read(®->rwlock); - down_read(&conn->ep->bus->conn_rwlock); - down_read(&conn->ep->policy_db.entries_rwlock); - - /* size of records */ - size = 0; - ret = kdbus_list_all(conn, cmd->flags, NULL, &size, false); - if (ret < 0) - goto exit_unlock; - - if (size == 0) { - kdbus_pool_publish_empty(conn->pool, &cmd->offset, - &cmd->list_size); - } else { - slice = kdbus_pool_slice_alloc(conn->pool, size, false); - if (IS_ERR(slice)) { - ret = PTR_ERR(slice); - slice = NULL; - goto exit_unlock; - } - - /* copy the records */ - pos = 0; - ret = kdbus_list_all(conn, cmd->flags, slice, &pos, true); - if (ret < 0) - goto exit_unlock; - - WARN_ON(pos != size); - kdbus_pool_slice_publish(slice, &cmd->offset, &cmd->list_size); - } - - if (kdbus_member_set_user(&cmd->offset, argp, typeof(*cmd), offset) || - kdbus_member_set_user(&cmd->list_size, argp, - typeof(*cmd), list_size)) - ret = -EFAULT; - -exit_unlock: - up_read(&conn->ep->policy_db.entries_rwlock); - up_read(&conn->ep->bus->conn_rwlock); - up_read(®->rwlock); - kdbus_pool_slice_release(slice); - return kdbus_args_clear(&args, ret); -} diff --git a/ipc/kdbus/names.h b/ipc/kdbus/names.h deleted file mode 100644 index edac59ddd..000000000 --- a/ipc/kdbus/names.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_NAMES_H -#define __KDBUS_NAMES_H - -#include <linux/hashtable.h> -#include <linux/rwsem.h> - -struct kdbus_name_entry; -struct kdbus_name_owner; -struct kdbus_name_registry; - -/** - * struct kdbus_name_registry - names registered for a bus - * @entries_hash: Map of entries - * @lock: Registry data lock - * @name_seq_last: Last used sequence number to assign to a name entry - */ -struct kdbus_name_registry { - DECLARE_HASHTABLE(entries_hash, 8); - struct rw_semaphore rwlock; - u64 name_seq_last; -}; - -/** - * struct kdbus_name_entry - well-know name entry - * @name_id: sequence number of name entry to be able to uniquely - * identify a name over its registration lifetime - * @activator: activator of this name, or NULL - * @queue: list of queued owners - * @hentry: entry in registry map - * @name: well-known name - */ -struct kdbus_name_entry { - u64 name_id; - struct kdbus_name_owner *activator; - struct list_head queue; - struct hlist_node hentry; - char name[]; -}; - -/** - * struct kdbus_name_owner - owner of a well-known name - * @flags: KDBUS_NAME_* flags of this owner - * @conn: connection owning the name - * @name: name that is owned - * @conn_entry: link into @conn - * @name_entry: link into @name - */ -struct kdbus_name_owner { - u64 flags; - struct kdbus_conn *conn; - struct kdbus_name_entry *name; - struct list_head conn_entry; - struct list_head name_entry; -}; - -bool kdbus_name_is_valid(const char *p, bool allow_wildcard); - -struct kdbus_name_registry *kdbus_name_registry_new(void); -void kdbus_name_registry_free(struct kdbus_name_registry *reg); - -struct kdbus_name_entry * -kdbus_name_lookup_unlocked(struct kdbus_name_registry *reg, const char *name); - -int kdbus_name_acquire(struct kdbus_name_registry *reg, - struct kdbus_conn *conn, const char *name, - u64 flags, u64 *return_flags); -void kdbus_name_release_all(struct kdbus_name_registry *reg, - struct kdbus_conn *conn); - -int kdbus_cmd_name_acquire(struct kdbus_conn *conn, void __user *argp); -int kdbus_cmd_name_release(struct kdbus_conn *conn, void __user *argp); -int kdbus_cmd_list(struct kdbus_conn *conn, void __user *argp); - -/** - * kdbus_name_get_owner() - get current owner of a name - * @name: name to get current owner of - * - * This returns a pointer to the current owner of a name (or its activator if - * there is no owner). The caller must make sure @name is valid and does not - * vanish. - * - * Return: Pointer to current owner or NULL if there is none. - */ -static inline struct kdbus_name_owner * -kdbus_name_get_owner(struct kdbus_name_entry *name) -{ - return list_first_entry_or_null(&name->queue, struct kdbus_name_owner, - name_entry) ? : name->activator; -} - -#endif diff --git a/ipc/kdbus/node.c b/ipc/kdbus/node.c deleted file mode 100644 index 986aca39c..000000000 --- a/ipc/kdbus/node.c +++ /dev/null @@ -1,948 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/atomic.h> -#include <linux/fs.h> -#include <linux/idr.h> -#include <linux/kdev_t.h> -#include <linux/rbtree.h> -#include <linux/rwsem.h> -#include <linux/sched.h> -#include <linux/slab.h> -#include <linux/wait.h> - -#include "bus.h" -#include "domain.h" -#include "endpoint.h" -#include "fs.h" -#include "handle.h" -#include "node.h" -#include "util.h" - -/** - * DOC: kdbus nodes - * - * Nodes unify lifetime management across exposed kdbus objects and provide a - * hierarchy. Each kdbus object, that might be exposed to user-space, has a - * kdbus_node object embedded and is linked into the hierarchy. Each node can - * have any number (0-n) of child nodes linked. Each child retains a reference - * to its parent node. For root-nodes, the parent is NULL. - * - * Each node object goes through a bunch of states during it's lifetime: - * * NEW - * * LINKED (can be skipped by NEW->FREED transition) - * * ACTIVE (can be skipped by LINKED->INACTIVE transition) - * * INACTIVE - * * DRAINED - * * FREED - * - * Each node is allocated by the caller and initialized via kdbus_node_init(). - * This never fails and sets the object into state NEW. From now on, ref-counts - * on the node manage its lifetime. During init, the ref-count is set to 1. Once - * it drops to 0, the node goes to state FREED and the node->free_cb() callback - * is called to deallocate any memory. - * - * After initializing a node, you usually link it into the hierarchy. You need - * to provide a parent node and a name. The node will be linked as child to the - * parent and a globally unique ID is assigned to the child. The name of the - * child must be unique for all children of this parent. Otherwise, linking the - * child will fail with -EEXIST. - * Note that the child is not marked active, yet. Admittedly, it prevents any - * other node from being linked with the same name (thus, it reserves that - * name), but any child-lookup (via name or unique ID) will never return this - * child unless it has been marked active. - * - * Once successfully linked, you can use kdbus_node_activate() to activate a - * child. This will mark the child active. This state can be skipped by directly - * deactivating the child via kdbus_node_deactivate() (see below). - * By activating a child, you enable any lookups on this child to succeed from - * now on. Furthermore, any code that got its hands on a reference to the node, - * can from now on "acquire" the node. - * - * Active References (or: 'acquiring' and 'releasing' a node) - * Additionally to normal object references, nodes support something we call - * "active references". An active reference can be acquired via - * kdbus_node_acquire() and released via kdbus_node_release(). A caller - * _must_ own a normal object reference whenever calling those functions. - * Unlike object references, acquiring an active reference can fail (by - * returning 'false' from kdbus_node_acquire()). An active reference can - * only be acquired if the node is marked active. If it is not marked - * active, yet, or if it was already deactivated, no more active references - * can be acquired, ever! - * Active references are used to track tasks working on a node. Whenever a - * task enters kernel-space to perform an action on a node, it acquires an - * active reference, performs the action and releases the reference again. - * While holding an active reference, the node is guaranteed to stay active. - * If the node is deactivated in parallel, the node is marked as - * deactivated, then we wait for all active references to be dropped, before - * we finally proceed with any cleanups. That is, if you hold an active - * reference to a node, any resources that are bound to the "active" state - * are guaranteed to stay accessible until you release your reference. - * - * Active-references are very similar to rw-locks, where acquiring a node is - * equal to try-read-lock and releasing to read-unlock. Deactivating a node - * means write-lock and never releasing it again. - * Unlike rw-locks, the 'active reference' concept is more versatile and - * avoids unusual rw-lock usage (never releasing a write-lock..). - * - * It is safe to acquire multiple active-references recursively. But you - * need to check the return value of kdbus_node_acquire() on _each_ call. It - * may stop granting references at _any_ time. - * - * You're free to perform any operations you want while holding an active - * reference, except sleeping for an indefinite period. Sleeping for a fixed - * amount of time is fine, but you usually should not wait on wait-queues - * without a timeout. - * For example, if you wait for I/O to happen, you should gather all data - * and schedule the I/O operation, then release your active reference and - * wait for it to complete. Then try to acquire a new reference. If it - * fails, perform any cleanup (the node is now dead). Otherwise, you can - * finish your operation. - * - * All nodes can be deactivated via kdbus_node_deactivate() at any time. You can - * call this multiple times, even in parallel or on nodes that were never - * linked, and it will just work. Furthermore, all children will be deactivated - * recursively as well. If a node is deactivated, there might still be active - * references that were acquired before calling kdbus_node_deactivate(). The - * owner of an object must call kdbus_node_drain() (which is a superset of - * kdbus_node_deactivate()) before dropping their reference. This will - * deactivate the node and also synchronously wait for all active references to - * be dropped. Hence, once kdbus_node_drain() returns, the node is fully - * released and no active references exist, anymore. - * kdbus_node_drain() can be called at any times, multiple times, and in - * parallel on multiple threads. All calls are synchronized internally and will - * return only once the node is fully drained. The only restriction is, you - * must not hold an active reference when calling kdbus_node_drain() (unlike - * deactivation, which allows the caller to hold an active reference). - * - * When a node is activated, we acquire a normal object reference to the node. - * This reference is dropped after deactivation is fully done (and only if the - * node really was activated). This allows callers to link+activate a child node - * and then drop all refs. This has the effect that nobody owns a reference to - * the node, except for the parent node. Hence, if the parent is deactivated - * (and thus all children are deactivated, too), this will automatically - * release the child node. - * - * Currently, nodes provide a bunch of resources that external code can use - * directly. This includes: - * - * * node->waitq: Each node has its own wait-queue that is used to manage - * the 'active' state. When a node is deactivated, we wait on - * this queue until all active refs are dropped. Analogously, - * when you release an active reference on a deactivated - * node, and the active ref-count drops to 0, we wake up a - * single thread on this queue. Furthermore, once the - * ->release_cb() callback finished, we wake up all waiters. - * The node-owner is free to re-use this wait-queue for other - * purposes. As node-management uses this queue only during - * deactivation, it is usually totally fine to re-use the - * queue for other, preferably low-overhead, use-cases. - * - * * node->type: This field defines the type of the owner of this node. It - * must be set during node initialization and must remain - * constant. The node management never looks at this value, - * but external users might use to gain access to the owner - * object of a node. - * It is totally up to the owner of the node to define what - * their type means. Usually it means you can access the - * parent structure via container_of(), as long as you hold an - * active reference to the node. - * - * * node->free_cb: callback after all references are dropped - * node->release_cb: callback during node deactivation - * These fields must be set by the node owner during - * node initialization. They must remain constant. If - * NULL, they're skipped. - * - * * node->mode: filesystem access modes - * node->uid: filesystem owner uid - * node->gid: filesystem owner gid - * These fields must be set by the node owner during node - * initialization. They must remain constant and may be - * accessed by other callers to properly initialize - * filesystem nodes. - * - * * node->id: This is an unsigned 32bit integer allocated by an IDA. It is - * always kept as small as possible during allocation and is - * globally unique across all nodes allocated by this module. 0 - * is reserved as "not assigned" and is the default. - * The ID is assigned during kdbus_node_link() and is kept until - * the object is freed. Thus, the ID surpasses the active - * lifetime of a node. As long as you hold an object reference - * to a node (and the node was linked once), the ID is valid and - * unique. - * - * * node->name: name of this node - * node->hash: 31bit hash-value of @name (range [2..INT_MAX-1]) - * These values follow the same lifetime rules as node->id. - * They're initialized when the node is linked and then remain - * constant until the last object reference is dropped. - * Unlike the id, the name is only unique across all siblings - * and only until the node is deactivated. Currently, the name - * is even unique if linked but not activated, yet. This might - * change in the future, though. Code should not rely on this. - * - * * node->lock: lock to protect node->children, node->rb, node->parent - * * node->parent: Reference to parent node. This is set during LINK time - * and is dropped during destruction. You can freely access - * this field, but it may be NULL (root node). - * * node->children: rb-tree of all linked children of this node. You must - * not access this directly, but use one of the iterator - * or lookup helpers. - */ - -/* - * Bias values track states of "active references". They're all negative. If a - * node is active, its active-ref-counter is >=0 and tracks all active - * references. Once a node is deactivaed, we subtract NODE_BIAS. This means, the - * counter is now negative but still counts the active references. Once it drops - * to exactly NODE_BIAS, we know all active references were dropped. Exactly one - * thread will change it to NODE_RELEASE now, perform cleanup and then put it - * into NODE_DRAINED. Once drained, all other threads that tried deactivating - * the node will now be woken up (thus, they wait until the node is fully done). - * The initial state during node-setup is NODE_NEW. If a node is directly - * deactivated without having ever been active, it is put into - * NODE_RELEASE_DIRECT instead of NODE_BIAS. This tracks this one-bit state - * across node-deactivation. The task putting it into NODE_RELEASE now knows - * whether the node was active before or not. - * - * Some archs implement atomic_sub(v) with atomic_add(-v), so reserve INT_MIN - * to avoid overflows if multiplied by -1. - */ -#define KDBUS_NODE_BIAS (INT_MIN + 5) -#define KDBUS_NODE_RELEASE_DIRECT (KDBUS_NODE_BIAS - 1) -#define KDBUS_NODE_RELEASE (KDBUS_NODE_BIAS - 2) -#define KDBUS_NODE_DRAINED (KDBUS_NODE_BIAS - 3) -#define KDBUS_NODE_NEW (KDBUS_NODE_BIAS - 4) - -/* global unique ID mapping for kdbus nodes */ -DEFINE_IDA(kdbus_node_ida); - -/** - * kdbus_node_name_hash() - hash a name - * @name: The string to hash - * - * This computes the hash of @name. It is guaranteed to be in the range - * [2..INT_MAX-1]. The values 1, 2 and INT_MAX are unused as they are reserved - * for the filesystem code. - * - * Return: hash value of the passed string - */ -static unsigned int kdbus_node_name_hash(const char *name) -{ - unsigned int hash; - - /* reserve hash numbers 0, 1 and >=INT_MAX for magic directories */ - hash = kdbus_strhash(name) & INT_MAX; - if (hash < 2) - hash += 2; - if (hash >= INT_MAX) - hash = INT_MAX - 1; - - return hash; -} - -/** - * kdbus_node_name_compare() - compare a name with a node's name - * @hash: hash of the string to compare the node with - * @name: name to compare the node with - * @node: node to compare the name with - * - * This compares a query string against a kdbus node. If the kdbus node has the - * given name, this returns 0. Otherwise, this returns >0 / <0 depending - * whether the query string is greater / less than the node. - * - * Note: If @node is drained but has the name @name, this returns 1. The - * reason for this is that we treat drained nodes as "renamed". The - * slot of such nodes is no longer occupied and new nodes can claim it. - * Obviously, this has the side-effect that you cannot match drained - * nodes, as they will never return 0 on name-matches. But this is - * intentional, as there is no reason why anyone would ever want to match - * on drained nodes. - * - * Return: 0 if @name and @hash exactly match the information in @node, or - * an integer less than or greater than zero if @name is found, respectively, - * to be less than or be greater than the string stored in @node. - */ -static int kdbus_node_name_compare(unsigned int hash, const char *name, - const struct kdbus_node *node) -{ - int ret; - - if (hash != node->hash) - return hash - node->hash; - - ret = strcmp(name, node->name); - if (ret != 0) - return ret; - - return atomic_read(&node->active) == KDBUS_NODE_DRAINED; -} - -/** - * kdbus_node_init() - initialize a kdbus_node - * @node: Pointer to the node to initialize - * @type: The type the node will have (KDBUS_NODE_*) - * - * The caller is responsible of allocating @node and initializating it to zero. - * Once this call returns, you must use the node_ref() and node_unref() - * functions to manage this node. - */ -void kdbus_node_init(struct kdbus_node *node, unsigned int type) -{ - atomic_set(&node->refcnt, 1); - mutex_init(&node->lock); - node->id = 0; - node->type = type; - RB_CLEAR_NODE(&node->rb); - node->children = RB_ROOT; - init_waitqueue_head(&node->waitq); - atomic_set(&node->active, KDBUS_NODE_NEW); -} - -/** - * kdbus_node_link() - link a node into the nodes system - * @node: Pointer to the node to initialize - * @parent: Pointer to a parent node, may be %NULL - * @name: The name of the node (or NULL if root node) - * - * This links a node into the hierarchy. This must not be called multiple times. - * If @parent is NULL, the node becomes a new root node. - * - * This call will fail if @name is not unique across all its siblings or if no - * ID could be allocated. You must not activate a node if linking failed! It is - * safe to deactivate it, though. - * - * Once you linked a node, you must call kdbus_node_drain() before you drop - * the last reference (even if you never activate the node). - * - * Return: 0 on success. negative error otherwise. - */ -int kdbus_node_link(struct kdbus_node *node, struct kdbus_node *parent, - const char *name) -{ - int ret; - - if (WARN_ON(node->type != KDBUS_NODE_DOMAIN && !parent)) - return -EINVAL; - - if (WARN_ON(parent && !name)) - return -EINVAL; - - if (name) { - node->name = kstrdup(name, GFP_KERNEL); - if (!node->name) - return -ENOMEM; - - node->hash = kdbus_node_name_hash(name); - } - - ret = ida_simple_get(&kdbus_node_ida, 1, 0, GFP_KERNEL); - if (ret < 0) - return ret; - - node->id = ret; - ret = 0; - - if (parent) { - struct rb_node **n, *prev; - - if (!kdbus_node_acquire(parent)) - return -ESHUTDOWN; - - mutex_lock(&parent->lock); - - n = &parent->children.rb_node; - prev = NULL; - - while (*n) { - struct kdbus_node *pos; - int result; - - pos = kdbus_node_from_rb(*n); - prev = *n; - result = kdbus_node_name_compare(node->hash, - node->name, - pos); - if (result == 0) { - ret = -EEXIST; - goto exit_unlock; - } - - if (result < 0) - n = &pos->rb.rb_left; - else - n = &pos->rb.rb_right; - } - - /* add new node and rebalance the tree */ - rb_link_node(&node->rb, prev, n); - rb_insert_color(&node->rb, &parent->children); - node->parent = kdbus_node_ref(parent); - -exit_unlock: - mutex_unlock(&parent->lock); - kdbus_node_release(parent); - } - - return ret; -} - -/** - * kdbus_node_ref() - Acquire object reference - * @node: node to acquire reference to (or NULL) - * - * This acquires a new reference to @node. You must already own a reference when - * calling this! - * If @node is NULL, this is a no-op. - * - * Return: @node is returned - */ -struct kdbus_node *kdbus_node_ref(struct kdbus_node *node) -{ - if (node) - atomic_inc(&node->refcnt); - return node; -} - -/** - * kdbus_node_unref() - Drop object reference - * @node: node to drop reference to (or NULL) - * - * This drops an object reference to @node. You must not access the node if you - * no longer own a reference. - * If the ref-count drops to 0, the object will be destroyed (->free_cb will be - * called). - * - * If you linked or activated the node, you must deactivate the node before you - * drop your last reference! If you didn't link or activate the node, you can - * drop any reference you want. - * - * Note that this calls into ->free_cb() and thus _might_ sleep. The ->free_cb() - * callbacks must not acquire any outer locks, though. So you can safely drop - * references while holding locks (apart from node->parent->lock). - * - * If @node is NULL, this is a no-op. - * - * Return: This always returns NULL - */ -struct kdbus_node *kdbus_node_unref(struct kdbus_node *node) -{ - if (node && atomic_dec_and_test(&node->refcnt)) { - struct kdbus_node safe = *node; - - WARN_ON(atomic_read(&node->active) != KDBUS_NODE_DRAINED); - - if (node->parent) { - mutex_lock(&node->parent->lock); - if (!RB_EMPTY_NODE(&node->rb)) { - rb_erase(&node->rb, - &node->parent->children); - RB_CLEAR_NODE(&node->rb); - } - mutex_unlock(&node->parent->lock); - } - - if (node->free_cb) - node->free_cb(node); - if (safe.id > 0) - ida_simple_remove(&kdbus_node_ida, safe.id); - - kfree(safe.name); - kdbus_node_unref(safe.parent); - } - - return NULL; -} - -/** - * kdbus_node_is_active() - test whether a node is active - * @node: node to test - * - * This checks whether @node is active. That means, @node was linked and - * activated by the node owner and hasn't been deactivated, yet. If, and only - * if, a node is active, kdbus_node_acquire() will be able to acquire active - * references. - * - * Note that this function does not give any lifetime guarantees. After this - * call returns, the node might be deactivated immediately. Normally, what you - * want is to acquire a real active reference via kdbus_node_acquire(). - * - * Return: true if @node is active, false otherwise - */ -bool kdbus_node_is_active(struct kdbus_node *node) -{ - return atomic_read(&node->active) >= 0; -} - -/** - * kdbus_node_is_deactivated() - test whether a node was already deactivated - * @node: node to test - * - * This checks whether kdbus_node_deactivate() was called on @node. Note that - * this might be true even if you never deactivated the node directly, but only - * one of its ancestors. - * - * Note that even if this returns 'false', the node might get deactivated - * immediately after the call returns. - * - * Return: true if @node was already deactivated, false if not - */ -bool kdbus_node_is_deactivated(struct kdbus_node *node) -{ - int v; - - v = atomic_read(&node->active); - return v != KDBUS_NODE_NEW && v < 0; -} - -/** - * kdbus_node_activate() - activate a node - * @node: node to activate - * - * This marks @node as active if, and only if, the node wasn't activated nor - * deactivated, yet, and the parent is still active. Any but the first call to - * kdbus_node_activate() is a no-op. - * If you called kdbus_node_deactivate() before, then even the first call to - * kdbus_node_activate() will be a no-op. - * - * This call doesn't give any lifetime guarantees. The node might get - * deactivated immediately after this call returns. Or the parent might already - * be deactivated, which will make this call a no-op. - * - * If this call successfully activated a node, it will take an object reference - * to it. This reference is dropped after the node is deactivated. Therefore, - * the object owner can safely drop their reference to @node iff they know that - * its parent node will get deactivated at some point. Once the parent node is - * deactivated, it will deactivate all its child and thus drop this reference - * again. - * - * Return: True if this call successfully activated the node, otherwise false. - * Note that this might return false, even if the node is still active - * (eg., if you called this a second time). - */ -bool kdbus_node_activate(struct kdbus_node *node) -{ - bool res = false; - - mutex_lock(&node->lock); - if (atomic_read(&node->active) == KDBUS_NODE_NEW) { - atomic_sub(KDBUS_NODE_NEW, &node->active); - /* activated nodes have ref +1 */ - kdbus_node_ref(node); - res = true; - } - mutex_unlock(&node->lock); - - return res; -} - -/** - * kdbus_node_recurse_unlock() - advance iterator on a tree - * @start: node at which the iteration started - * @node: previously visited node - * - * This helper advances an iterator by one, when traversing a node tree. It is - * supposed to be used like this: - * - * struct kdbus_node *n; - * - * n = start; - * while (n) { - * mutex_lock(&n->lock); - * ... visit @n ... - * n = kdbus_node_recurse_unlock(start, n); - * } - * - * This helpers takes as input the start-node of the iteration and the current - * position. It returns a pointer to the next node to visit. The caller must - * hold a reference to @start during the whole iteration. Furthermore, @node - * must be locked when entering this helper. On return, the lock is released. - * - * The order of visit is pre-order traversal. - * - * If @node is deactivated before recursing its children, then it is guaranteed - * that all children will be visited. If @node is still active, new nodes might - * be inserted during traversal, and thus might be missed. - * - * Also note that the node-locks are released while traversing children. You - * must not rely on the locks to be held during the whole traversal. Each node - * that is visited is pinned by this helper, so the caller can rely on owning a - * reference. It is dropped, once all of the children of the node have been - * visited (recursively). - * - * You *must not* bail out of a traversal early, otherwise you'll leak - * ref-counts to all nodes in the current depth-path. - * - * Return: Reference to next node, or NULL. - */ -static struct kdbus_node *kdbus_node_recurse_unlock(struct kdbus_node *start, - struct kdbus_node *node) -{ - struct kdbus_node *t, *prev = NULL; - struct rb_node *rb; - - lockdep_assert_held(&node->lock); - - rb = rb_first(&node->children); - if (!rb) { - do { - mutex_unlock(&node->lock); - kdbus_node_unref(prev); - - if (node == start) - return NULL; - - prev = node; - node = node->parent; - - mutex_lock(&node->lock); - rb = rb_next(&prev->rb); - } while (!rb); - } - - t = kdbus_node_ref(kdbus_node_from_rb(rb)); - mutex_unlock(&node->lock); - kdbus_node_unref(prev); - return t; -} - -/** - * kdbus_node_deactivate() - deactivate a node - * @node: node to deactivate - * - * This recursively deactivates the passed node and all its children. The nodes - * are marked as deactivated, but they're not drained. Hence, even after this - * call returns, there might still be someone holding an active reference to - * any of the nodes. However, no new active references can be acquired after - * this returns. - * - * It is safe to call this multiple times (even in parallel). Each call is - * guaranteed to only return after _all_ nodes have been deactivated. - */ -void kdbus_node_deactivate(struct kdbus_node *node) -{ - struct kdbus_node *pos; - int v; - - pos = node; - while (pos) { - mutex_lock(&pos->lock); - - /* - * Add BIAS to pos->active to mark it as inactive. If it was - * never active before, immediately mark it as RELEASE_INACTIVE - * so that this case can be detected later on. - * If the node was already deactivated, make sure to still - * recurse into the children. Otherwise, we might return before - * a racing thread finished deactivating all children. But we - * want to guarantee that the whole tree is deactivated once - * this returns. - */ - v = atomic_read(&pos->active); - if (v >= 0) - atomic_add_return(KDBUS_NODE_BIAS, &pos->active); - else if (v == KDBUS_NODE_NEW) - atomic_set(&pos->active, KDBUS_NODE_RELEASE_DIRECT); - - pos = kdbus_node_recurse_unlock(node, pos); - } -} - -/** - * kdbus_node_drain() - drain a node - * @node: node to drain - * - * This function recursively deactivates this node and all its children and - * then waits for all active references to be dropped. This function is a - * superset of kdbus_node_deactivate(), as it additionally drains all nodes. It - * returns only once all children and the node itself were recursively drained - * (even if you call this function multiple times in parallel). - * - * It is safe to call this function on _any_ node that was initialized _any_ - * number of times. - * - * This call may sleep, as it waits for all active references to be dropped. - */ -void kdbus_node_drain(struct kdbus_node *node) -{ - struct kdbus_node *pos; - int v; - - kdbus_node_deactivate(node); - - pos = node; - while (pos) { - /* wait until all active references were dropped */ - wait_event(pos->waitq, - atomic_read(&pos->active) <= KDBUS_NODE_BIAS); - - /* mark object as RELEASE */ - mutex_lock(&pos->lock); - v = atomic_read(&pos->active); - if (v == KDBUS_NODE_BIAS || v == KDBUS_NODE_RELEASE_DIRECT) - atomic_set(&pos->active, KDBUS_NODE_RELEASE); - mutex_unlock(&pos->lock); - - /* - * If this is the thread that marked the object as RELEASE, we - * perform the actual release. Otherwise, we wait until the - * release is done and the node is marked as DRAINED. - */ - if (v == KDBUS_NODE_BIAS || v == KDBUS_NODE_RELEASE_DIRECT) { - if (pos->release_cb) - pos->release_cb(pos, v == KDBUS_NODE_BIAS); - - /* mark as DRAINED */ - atomic_set(&pos->active, KDBUS_NODE_DRAINED); - wake_up_all(&pos->waitq); - - /* drop VFS cache */ - kdbus_fs_flush(pos); - - /* - * If the node was activated and someone subtracted BIAS - * from it to deactivate it, we, and only us, are - * responsible to release the extra ref-count that was - * taken once in kdbus_node_activate(). - * If the node was never activated, no-one ever - * subtracted BIAS, but instead skipped that state and - * immediately went to NODE_RELEASE_DIRECT. In that case - * we must not drop the reference. - */ - if (v == KDBUS_NODE_BIAS) - kdbus_node_unref(pos); - } else { - /* wait until object is DRAINED */ - wait_event(pos->waitq, - atomic_read(&pos->active) == KDBUS_NODE_DRAINED); - } - - mutex_lock(&pos->lock); - pos = kdbus_node_recurse_unlock(node, pos); - } -} - -/** - * kdbus_node_acquire() - Acquire an active ref on a node - * @node: The node - * - * This acquires an active-reference to @node. This will only succeed if the - * node is active. You must release this active reference via - * kdbus_node_release() again. - * - * See the introduction to "active references" for more details. - * - * Return: %true if @node was non-NULL and active - */ -bool kdbus_node_acquire(struct kdbus_node *node) -{ - return node && atomic_inc_unless_negative(&node->active); -} - -/** - * kdbus_node_release() - Release an active ref on a node - * @node: The node - * - * This releases an active reference that was previously acquired via - * kdbus_node_acquire(). See kdbus_node_acquire() for details. - */ -void kdbus_node_release(struct kdbus_node *node) -{ - if (node && atomic_dec_return(&node->active) == KDBUS_NODE_BIAS) - wake_up(&node->waitq); -} - -/** - * kdbus_node_find_child() - Find child by name - * @node: parent node to search through - * @name: name of child node - * - * This searches through all children of @node for a child-node with name @name. - * If not found, or if the child is deactivated, NULL is returned. Otherwise, - * the child is acquired and a new reference is returned. - * - * If you're done with the child, you need to release it and drop your - * reference. - * - * This function does not acquire the parent node. However, if the parent was - * already deactivated, then kdbus_node_deactivate() will, at some point, also - * deactivate the child. Therefore, we can rely on the explicit ordering during - * deactivation. - * - * Return: Reference to acquired child node, or NULL if not found / not active. - */ -struct kdbus_node *kdbus_node_find_child(struct kdbus_node *node, - const char *name) -{ - struct kdbus_node *child; - struct rb_node *rb; - unsigned int hash; - int ret; - - hash = kdbus_node_name_hash(name); - - mutex_lock(&node->lock); - rb = node->children.rb_node; - while (rb) { - child = kdbus_node_from_rb(rb); - ret = kdbus_node_name_compare(hash, name, child); - if (ret < 0) - rb = rb->rb_left; - else if (ret > 0) - rb = rb->rb_right; - else - break; - } - if (rb && kdbus_node_acquire(child)) - kdbus_node_ref(child); - else - child = NULL; - mutex_unlock(&node->lock); - - return child; -} - -static struct kdbus_node *node_find_closest_unlocked(struct kdbus_node *node, - unsigned int hash, - const char *name) -{ - struct kdbus_node *n, *pos = NULL; - struct rb_node *rb; - int res; - - /* - * Find the closest child with ``node->hash >= hash'', or, if @name is - * valid, ``node->name >= name'' (where '>=' is the lex. order). - */ - - rb = node->children.rb_node; - while (rb) { - n = kdbus_node_from_rb(rb); - - if (name) - res = kdbus_node_name_compare(hash, name, n); - else - res = hash - n->hash; - - if (res <= 0) { - rb = rb->rb_left; - pos = n; - } else { /* ``hash > n->hash'', ``name > n->name'' */ - rb = rb->rb_right; - } - } - - return pos; -} - -/** - * kdbus_node_find_closest() - Find closest child-match - * @node: parent node to search through - * @hash: hash value to find closest match for - * - * Find the closest child of @node with a hash greater than or equal to @hash. - * The closest match is the left-most child of @node with this property. Which - * means, it is the first child with that hash returned by - * kdbus_node_next_child(), if you'd iterate the whole parent node. - * - * Return: Reference to acquired child, or NULL if none found. - */ -struct kdbus_node *kdbus_node_find_closest(struct kdbus_node *node, - unsigned int hash) -{ - struct kdbus_node *child; - struct rb_node *rb; - - mutex_lock(&node->lock); - - child = node_find_closest_unlocked(node, hash, NULL); - while (child && !kdbus_node_acquire(child)) { - rb = rb_next(&child->rb); - if (rb) - child = kdbus_node_from_rb(rb); - else - child = NULL; - } - kdbus_node_ref(child); - - mutex_unlock(&node->lock); - - return child; -} - -/** - * kdbus_node_next_child() - Acquire next child - * @node: parent node - * @prev: previous child-node position or NULL - * - * This function returns a reference to the next active child of @node, after - * the passed position @prev. If @prev is NULL, a reference to the first active - * child is returned. If no more active children are found, NULL is returned. - * - * This function acquires the next child it returns. If you're done with the - * returned pointer, you need to release _and_ unref it. - * - * The passed in pointer @prev is not modified by this function, and it does - * *not* have to be active. If @prev was acquired via different means, or if it - * was unlinked from its parent before you pass it in, then this iterator will - * still return the next active child (it will have to search through the - * rb-tree based on the node-name, though). - * However, @prev must not be linked to a different parent than @node! - * - * Return: Reference to next acquired child, or NULL if at the end. - */ -struct kdbus_node *kdbus_node_next_child(struct kdbus_node *node, - struct kdbus_node *prev) -{ - struct kdbus_node *pos = NULL; - struct rb_node *rb; - - mutex_lock(&node->lock); - - if (!prev) { - /* - * New iteration; find first node in rb-tree and try to acquire - * it. If we got it, directly return it as first element. - * Otherwise, the loop below will find the next active node. - */ - rb = rb_first(&node->children); - if (!rb) - goto exit; - pos = kdbus_node_from_rb(rb); - if (kdbus_node_acquire(pos)) - goto exit; - } else { - /* - * The current iterator is still linked to the parent. Set it - * as current position and use the loop below to find the next - * active element. - */ - pos = prev; - } - - /* @pos was already returned or is inactive; find next active node */ - do { - rb = rb_next(&pos->rb); - if (rb) - pos = kdbus_node_from_rb(rb); - else - pos = NULL; - } while (pos && !kdbus_node_acquire(pos)); - -exit: - /* @pos is NULL or acquired. Take ref if non-NULL and return it */ - kdbus_node_ref(pos); - mutex_unlock(&node->lock); - return pos; -} diff --git a/ipc/kdbus/node.h b/ipc/kdbus/node.h deleted file mode 100644 index 16c6fd574..000000000 --- a/ipc/kdbus/node.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_NODE_H -#define __KDBUS_NODE_H - -#include <linux/atomic.h> -#include <linux/kernel.h> -#include <linux/mutex.h> -#include <linux/wait.h> - -struct kdbus_node; - -enum kdbus_node_type { - KDBUS_NODE_DOMAIN, - KDBUS_NODE_CONTROL, - KDBUS_NODE_BUS, - KDBUS_NODE_ENDPOINT, -}; - -typedef void (*kdbus_node_free_t) (struct kdbus_node *node); -typedef void (*kdbus_node_release_t) (struct kdbus_node *node, bool was_active); - -struct kdbus_node { - struct mutex lock; - atomic_t refcnt; - atomic_t active; - wait_queue_head_t waitq; - - /* static members */ - unsigned int type; - kdbus_node_free_t free_cb; - kdbus_node_release_t release_cb; - umode_t mode; - kuid_t uid; - kgid_t gid; - - /* valid once linked */ - char *name; - unsigned int hash; - unsigned int id; - struct kdbus_node *parent; /* may be NULL */ - struct rb_node rb; - - /* dynamic list of children */ - struct rb_root children; -}; - -#define kdbus_node_from_rb(_node) rb_entry((_node), struct kdbus_node, rb) - -extern struct ida kdbus_node_ida; - -void kdbus_node_init(struct kdbus_node *node, unsigned int type); - -int kdbus_node_link(struct kdbus_node *node, struct kdbus_node *parent, - const char *name); - -struct kdbus_node *kdbus_node_ref(struct kdbus_node *node); -struct kdbus_node *kdbus_node_unref(struct kdbus_node *node); - -bool kdbus_node_is_active(struct kdbus_node *node); -bool kdbus_node_is_deactivated(struct kdbus_node *node); -bool kdbus_node_activate(struct kdbus_node *node); -void kdbus_node_deactivate(struct kdbus_node *node); -void kdbus_node_drain(struct kdbus_node *node); - -bool kdbus_node_acquire(struct kdbus_node *node); -void kdbus_node_release(struct kdbus_node *node); - -struct kdbus_node *kdbus_node_find_child(struct kdbus_node *node, - const char *name); -struct kdbus_node *kdbus_node_find_closest(struct kdbus_node *node, - unsigned int hash); -struct kdbus_node *kdbus_node_next_child(struct kdbus_node *node, - struct kdbus_node *prev); - -#endif diff --git a/ipc/kdbus/notify.c b/ipc/kdbus/notify.c deleted file mode 100644 index 375758c48..000000000 --- a/ipc/kdbus/notify.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/fs.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/spinlock.h> -#include <linux/sched.h> -#include <linux/slab.h> - -#include "bus.h" -#include "connection.h" -#include "domain.h" -#include "endpoint.h" -#include "item.h" -#include "message.h" -#include "notify.h" - -static inline void kdbus_notify_add_tail(struct kdbus_staging *staging, - struct kdbus_bus *bus) -{ - spin_lock(&bus->notify_lock); - list_add_tail(&staging->notify_entry, &bus->notify_list); - spin_unlock(&bus->notify_lock); -} - -static int kdbus_notify_reply(struct kdbus_bus *bus, u64 id, - u64 cookie, u64 msg_type) -{ - struct kdbus_staging *s; - - s = kdbus_staging_new_kernel(bus, id, cookie, 0, msg_type); - if (IS_ERR(s)) - return PTR_ERR(s); - - kdbus_notify_add_tail(s, bus); - return 0; -} - -/** - * kdbus_notify_reply_timeout() - queue a timeout reply - * @bus: Bus which queues the messages - * @id: The destination's connection ID - * @cookie: The cookie to set in the reply. - * - * Queues a message that has a KDBUS_ITEM_REPLY_TIMEOUT item attached. - * - * Return: 0 on success, negative errno on failure. - */ -int kdbus_notify_reply_timeout(struct kdbus_bus *bus, u64 id, u64 cookie) -{ - return kdbus_notify_reply(bus, id, cookie, KDBUS_ITEM_REPLY_TIMEOUT); -} - -/** - * kdbus_notify_reply_dead() - queue a 'dead' reply - * @bus: Bus which queues the messages - * @id: The destination's connection ID - * @cookie: The cookie to set in the reply. - * - * Queues a message that has a KDBUS_ITEM_REPLY_DEAD item attached. - * - * Return: 0 on success, negative errno on failure. - */ -int kdbus_notify_reply_dead(struct kdbus_bus *bus, u64 id, u64 cookie) -{ - return kdbus_notify_reply(bus, id, cookie, KDBUS_ITEM_REPLY_DEAD); -} - -/** - * kdbus_notify_name_change() - queue a notification about a name owner change - * @bus: Bus which queues the messages - * @type: The type if the notification; KDBUS_ITEM_NAME_ADD, - * KDBUS_ITEM_NAME_CHANGE or KDBUS_ITEM_NAME_REMOVE - * @old_id: The id of the connection that used to own the name - * @new_id: The id of the new owner connection - * @old_flags: The flags to pass in the KDBUS_ITEM flags field for - * the old owner - * @new_flags: The flags to pass in the KDBUS_ITEM flags field for - * the new owner - * @name: The name that was removed or assigned to a new owner - * - * Return: 0 on success, negative errno on failure. - */ -int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type, - u64 old_id, u64 new_id, - u64 old_flags, u64 new_flags, - const char *name) -{ - size_t name_len, extra_size; - struct kdbus_staging *s; - - name_len = strlen(name) + 1; - extra_size = sizeof(struct kdbus_notify_name_change) + name_len; - - s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, - extra_size, type); - if (IS_ERR(s)) - return PTR_ERR(s); - - s->notify->name_change.old_id.id = old_id; - s->notify->name_change.old_id.flags = old_flags; - s->notify->name_change.new_id.id = new_id; - s->notify->name_change.new_id.flags = new_flags; - memcpy(s->notify->name_change.name, name, name_len); - - kdbus_notify_add_tail(s, bus); - return 0; -} - -/** - * kdbus_notify_id_change() - queue a notification about a unique ID change - * @bus: Bus which queues the messages - * @type: The type if the notification; KDBUS_ITEM_ID_ADD or - * KDBUS_ITEM_ID_REMOVE - * @id: The id of the connection that was added or removed - * @flags: The flags to pass in the KDBUS_ITEM flags field - * - * Return: 0 on success, negative errno on failure. - */ -int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags) -{ - struct kdbus_staging *s; - size_t extra_size; - - extra_size = sizeof(struct kdbus_notify_id_change); - s = kdbus_staging_new_kernel(bus, KDBUS_DST_ID_BROADCAST, 0, - extra_size, type); - if (IS_ERR(s)) - return PTR_ERR(s); - - s->notify->id_change.id = id; - s->notify->id_change.flags = flags; - - kdbus_notify_add_tail(s, bus); - return 0; -} - -/** - * kdbus_notify_flush() - send a list of collected messages - * @bus: Bus which queues the messages - * - * The list is empty after sending the messages. - */ -void kdbus_notify_flush(struct kdbus_bus *bus) -{ - LIST_HEAD(notify_list); - struct kdbus_staging *s, *tmp; - - mutex_lock(&bus->notify_flush_lock); - down_read(&bus->name_registry->rwlock); - - spin_lock(&bus->notify_lock); - list_splice_init(&bus->notify_list, ¬ify_list); - spin_unlock(&bus->notify_lock); - - list_for_each_entry_safe(s, tmp, ¬ify_list, notify_entry) { - if (s->msg->dst_id != KDBUS_DST_ID_BROADCAST) { - struct kdbus_conn *conn; - - conn = kdbus_bus_find_conn_by_id(bus, s->msg->dst_id); - if (conn) { - kdbus_bus_eavesdrop(bus, NULL, s); - kdbus_conn_entry_insert(NULL, conn, s, NULL, - NULL); - kdbus_conn_unref(conn); - } - } else { - kdbus_bus_broadcast(bus, NULL, s); - } - - list_del(&s->notify_entry); - kdbus_staging_free(s); - } - - up_read(&bus->name_registry->rwlock); - mutex_unlock(&bus->notify_flush_lock); -} - -/** - * kdbus_notify_free() - free a list of collected messages - * @bus: Bus which queues the messages - */ -void kdbus_notify_free(struct kdbus_bus *bus) -{ - struct kdbus_staging *s, *tmp; - - list_for_each_entry_safe(s, tmp, &bus->notify_list, notify_entry) { - list_del(&s->notify_entry); - kdbus_staging_free(s); - } -} diff --git a/ipc/kdbus/notify.h b/ipc/kdbus/notify.h deleted file mode 100644 index 03df464cb..000000000 --- a/ipc/kdbus/notify.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_NOTIFY_H -#define __KDBUS_NOTIFY_H - -struct kdbus_bus; - -int kdbus_notify_id_change(struct kdbus_bus *bus, u64 type, u64 id, u64 flags); -int kdbus_notify_reply_timeout(struct kdbus_bus *bus, u64 id, u64 cookie); -int kdbus_notify_reply_dead(struct kdbus_bus *bus, u64 id, u64 cookie); -int kdbus_notify_name_change(struct kdbus_bus *bus, u64 type, - u64 old_id, u64 new_id, - u64 old_flags, u64 new_flags, - const char *name); -void kdbus_notify_flush(struct kdbus_bus *bus); -void kdbus_notify_free(struct kdbus_bus *bus); - -#endif diff --git a/ipc/kdbus/policy.c b/ipc/kdbus/policy.c deleted file mode 100644 index f2618e15e..000000000 --- a/ipc/kdbus/policy.c +++ /dev/null @@ -1,489 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/dcache.h> -#include <linux/fs.h> -#include <linux/init.h> -#include <linux/mutex.h> -#include <linux/sched.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/uaccess.h> - -#include "bus.h" -#include "connection.h" -#include "domain.h" -#include "item.h" -#include "names.h" -#include "policy.h" - -#define KDBUS_POLICY_HASH_SIZE 64 - -/** - * struct kdbus_policy_db_entry_access - a database entry access item - * @type: One of KDBUS_POLICY_ACCESS_* types - * @access: Access to grant. One of KDBUS_POLICY_* - * @uid: For KDBUS_POLICY_ACCESS_USER, the global uid - * @gid: For KDBUS_POLICY_ACCESS_GROUP, the global gid - * @list: List entry item for the entry's list - * - * This is the internal version of struct kdbus_policy_db_access. - */ -struct kdbus_policy_db_entry_access { - u8 type; /* USER, GROUP, WORLD */ - u8 access; /* OWN, TALK, SEE */ - union { - kuid_t uid; /* global uid */ - kgid_t gid; /* global gid */ - }; - struct list_head list; -}; - -/** - * struct kdbus_policy_db_entry - a policy database entry - * @name: The name to match the policy entry against - * @hentry: The hash entry for the database's entries_hash - * @access_list: List head for keeping tracks of the entry's - * access items. - * @owner: The owner of this entry. Can be a kdbus_conn or - * a kdbus_ep object. - * @wildcard: The name is a wildcard, such as ending on '.*' - */ -struct kdbus_policy_db_entry { - char *name; - struct hlist_node hentry; - struct list_head access_list; - const void *owner; - bool wildcard:1; -}; - -static void kdbus_policy_entry_free(struct kdbus_policy_db_entry *e) -{ - struct kdbus_policy_db_entry_access *a, *tmp; - - list_for_each_entry_safe(a, tmp, &e->access_list, list) { - list_del(&a->list); - kfree(a); - } - - kfree(e->name); - kfree(e); -} - -static unsigned int kdbus_strnhash(const char *str, size_t len) -{ - unsigned long hash = init_name_hash(); - - while (len--) - hash = partial_name_hash(*str++, hash); - - return end_name_hash(hash); -} - -static const struct kdbus_policy_db_entry * -kdbus_policy_lookup(struct kdbus_policy_db *db, const char *name, u32 hash) -{ - struct kdbus_policy_db_entry *e; - const char *dot; - size_t len; - - /* find exact match */ - hash_for_each_possible(db->entries_hash, e, hentry, hash) - if (strcmp(e->name, name) == 0 && !e->wildcard) - return e; - - /* find wildcard match */ - - dot = strrchr(name, '.'); - if (!dot) - return NULL; - - len = dot - name; - hash = kdbus_strnhash(name, len); - - hash_for_each_possible(db->entries_hash, e, hentry, hash) - if (e->wildcard && !strncmp(e->name, name, len) && - !e->name[len]) - return e; - - return NULL; -} - -/** - * kdbus_policy_db_clear - release all memory from a policy db - * @db: The policy database - */ -void kdbus_policy_db_clear(struct kdbus_policy_db *db) -{ - struct kdbus_policy_db_entry *e; - struct hlist_node *tmp; - unsigned int i; - - /* purge entries */ - down_write(&db->entries_rwlock); - hash_for_each_safe(db->entries_hash, i, tmp, e, hentry) { - hash_del(&e->hentry); - kdbus_policy_entry_free(e); - } - up_write(&db->entries_rwlock); -} - -/** - * kdbus_policy_db_init() - initialize a new policy database - * @db: The location of the database - * - * This initializes a new policy-db. The underlying memory must have been - * cleared to zero by the caller. - */ -void kdbus_policy_db_init(struct kdbus_policy_db *db) -{ - hash_init(db->entries_hash); - init_rwsem(&db->entries_rwlock); -} - -/** - * kdbus_policy_query_unlocked() - Query the policy database - * @db: Policy database - * @cred: Credentials to test against - * @name: Name to query - * @hash: Hash value of @name - * - * Same as kdbus_policy_query() but requires the caller to lock the policy - * database against concurrent writes. - * - * Return: The highest KDBUS_POLICY_* access type found, or -EPERM if none. - */ -int kdbus_policy_query_unlocked(struct kdbus_policy_db *db, - const struct cred *cred, const char *name, - unsigned int hash) -{ - struct kdbus_policy_db_entry_access *a; - const struct kdbus_policy_db_entry *e; - int i, highest = -EPERM; - - e = kdbus_policy_lookup(db, name, hash); - if (!e) - return -EPERM; - - list_for_each_entry(a, &e->access_list, list) { - if ((int)a->access <= highest) - continue; - - switch (a->type) { - case KDBUS_POLICY_ACCESS_USER: - if (uid_eq(cred->euid, a->uid)) - highest = a->access; - break; - case KDBUS_POLICY_ACCESS_GROUP: - if (gid_eq(cred->egid, a->gid)) { - highest = a->access; - break; - } - - for (i = 0; i < cred->group_info->ngroups; i++) { - kgid_t gid = GROUP_AT(cred->group_info, i); - - if (gid_eq(gid, a->gid)) { - highest = a->access; - break; - } - } - - break; - case KDBUS_POLICY_ACCESS_WORLD: - highest = a->access; - break; - } - - /* OWN is the highest possible policy */ - if (highest >= KDBUS_POLICY_OWN) - break; - } - - return highest; -} - -/** - * kdbus_policy_query() - Query the policy database - * @db: Policy database - * @cred: Credentials to test against - * @name: Name to query - * @hash: Hash value of @name - * - * Query the policy database @db for the access rights of @cred to the name - * @name. The access rights of @cred are returned, or -EPERM if no access is - * granted. - * - * This call effectively searches for the highest access-right granted to - * @cred. The caller should really cache those as policy lookups are rather - * expensive. - * - * Return: The highest KDBUS_POLICY_* access type found, or -EPERM if none. - */ -int kdbus_policy_query(struct kdbus_policy_db *db, const struct cred *cred, - const char *name, unsigned int hash) -{ - int ret; - - down_read(&db->entries_rwlock); - ret = kdbus_policy_query_unlocked(db, cred, name, hash); - up_read(&db->entries_rwlock); - - return ret; -} - -static void __kdbus_policy_remove_owner(struct kdbus_policy_db *db, - const void *owner) -{ - struct kdbus_policy_db_entry *e; - struct hlist_node *tmp; - int i; - - hash_for_each_safe(db->entries_hash, i, tmp, e, hentry) - if (e->owner == owner) { - hash_del(&e->hentry); - kdbus_policy_entry_free(e); - } -} - -/** - * kdbus_policy_remove_owner() - remove all entries related to a connection - * @db: The policy database - * @owner: The connection which items to remove - */ -void kdbus_policy_remove_owner(struct kdbus_policy_db *db, - const void *owner) -{ - down_write(&db->entries_rwlock); - __kdbus_policy_remove_owner(db, owner); - up_write(&db->entries_rwlock); -} - -/* - * Convert user provided policy access to internal kdbus policy - * access - */ -static struct kdbus_policy_db_entry_access * -kdbus_policy_make_access(const struct kdbus_policy_access *uaccess) -{ - int ret; - struct kdbus_policy_db_entry_access *a; - - a = kzalloc(sizeof(*a), GFP_KERNEL); - if (!a) - return ERR_PTR(-ENOMEM); - - ret = -EINVAL; - switch (uaccess->access) { - case KDBUS_POLICY_SEE: - case KDBUS_POLICY_TALK: - case KDBUS_POLICY_OWN: - a->access = uaccess->access; - break; - default: - goto err; - } - - switch (uaccess->type) { - case KDBUS_POLICY_ACCESS_USER: - a->uid = make_kuid(current_user_ns(), uaccess->id); - if (!uid_valid(a->uid)) - goto err; - - break; - case KDBUS_POLICY_ACCESS_GROUP: - a->gid = make_kgid(current_user_ns(), uaccess->id); - if (!gid_valid(a->gid)) - goto err; - - break; - case KDBUS_POLICY_ACCESS_WORLD: - break; - default: - goto err; - } - - a->type = uaccess->type; - - return a; - -err: - kfree(a); - return ERR_PTR(ret); -} - -/** - * kdbus_policy_set() - set a connection's policy rules - * @db: The policy database - * @items: A list of kdbus_item elements that contain both - * names and access rules to set. - * @items_size: The total size of the items. - * @max_policies: The maximum number of policy entries to allow. - * Pass 0 for no limit. - * @allow_wildcards: Boolean value whether wildcard entries (such - * ending on '.*') should be allowed. - * @owner: The owner of the new policy items. - * - * This function sets a new set of policies for a given owner. The names and - * access rules are gathered by walking the list of items passed in as - * argument. An item of type KDBUS_ITEM_NAME is expected before any number of - * KDBUS_ITEM_POLICY_ACCESS items. If there are more repetitions of this - * pattern than denoted in @max_policies, -EINVAL is returned. - * - * In order to allow atomic replacement of rules, the function first removes - * all entries that have been created for the given owner previously. - * - * Callers to this function must make sure that the owner is a custom - * endpoint, or if the endpoint is a default endpoint, then it must be - * either a policy holder or an activator. - * - * Return: 0 on success, negative errno on failure. - */ -int kdbus_policy_set(struct kdbus_policy_db *db, - const struct kdbus_item *items, - size_t items_size, - size_t max_policies, - bool allow_wildcards, - const void *owner) -{ - struct kdbus_policy_db_entry_access *a; - struct kdbus_policy_db_entry *e, *p; - const struct kdbus_item *item; - struct hlist_node *tmp; - HLIST_HEAD(entries); - HLIST_HEAD(restore); - size_t count = 0; - int i, ret = 0; - u32 hash; - - /* Walk the list of items and look for new policies */ - e = NULL; - KDBUS_ITEMS_FOREACH(item, items, items_size) { - switch (item->type) { - case KDBUS_ITEM_NAME: { - size_t len; - - if (max_policies && ++count > max_policies) { - ret = -E2BIG; - goto exit; - } - - if (!kdbus_name_is_valid(item->str, true)) { - ret = -EINVAL; - goto exit; - } - - e = kzalloc(sizeof(*e), GFP_KERNEL); - if (!e) { - ret = -ENOMEM; - goto exit; - } - - INIT_LIST_HEAD(&e->access_list); - e->owner = owner; - hlist_add_head(&e->hentry, &entries); - - e->name = kstrdup(item->str, GFP_KERNEL); - if (!e->name) { - ret = -ENOMEM; - goto exit; - } - - /* - * If a supplied name ends with an '.*', cut off that - * part, only store anything before it, and mark the - * entry as wildcard. - */ - len = strlen(e->name); - if (len > 2 && - e->name[len - 3] == '.' && - e->name[len - 2] == '*') { - if (!allow_wildcards) { - ret = -EINVAL; - goto exit; - } - - e->name[len - 3] = '\0'; - e->wildcard = true; - } - - break; - } - - case KDBUS_ITEM_POLICY_ACCESS: - if (!e) { - ret = -EINVAL; - goto exit; - } - - a = kdbus_policy_make_access(&item->policy_access); - if (IS_ERR(a)) { - ret = PTR_ERR(a); - goto exit; - } - - list_add_tail(&a->list, &e->access_list); - break; - } - } - - down_write(&db->entries_rwlock); - - /* remember previous entries to restore in case of failure */ - hash_for_each_safe(db->entries_hash, i, tmp, e, hentry) - if (e->owner == owner) { - hash_del(&e->hentry); - hlist_add_head(&e->hentry, &restore); - } - - hlist_for_each_entry_safe(e, tmp, &entries, hentry) { - /* prevent duplicates */ - hash = kdbus_strhash(e->name); - hash_for_each_possible(db->entries_hash, p, hentry, hash) - if (strcmp(e->name, p->name) == 0 && - e->wildcard == p->wildcard) { - ret = -EEXIST; - goto restore; - } - - hlist_del(&e->hentry); - hash_add(db->entries_hash, &e->hentry, hash); - } - -restore: - /* if we failed, flush all entries we added so far */ - if (ret < 0) - __kdbus_policy_remove_owner(db, owner); - - /* if we failed, restore entries, otherwise release them */ - hlist_for_each_entry_safe(e, tmp, &restore, hentry) { - hlist_del(&e->hentry); - if (ret < 0) { - hash = kdbus_strhash(e->name); - hash_add(db->entries_hash, &e->hentry, hash); - } else { - kdbus_policy_entry_free(e); - } - } - - up_write(&db->entries_rwlock); - -exit: - hlist_for_each_entry_safe(e, tmp, &entries, hentry) { - hlist_del(&e->hentry); - kdbus_policy_entry_free(e); - } - - return ret; -} diff --git a/ipc/kdbus/policy.h b/ipc/kdbus/policy.h deleted file mode 100644 index 15dd7bc12..000000000 --- a/ipc/kdbus/policy.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_POLICY_H -#define __KDBUS_POLICY_H - -#include <linux/hashtable.h> -#include <linux/rwsem.h> - -struct kdbus_conn; -struct kdbus_item; - -/** - * struct kdbus_policy_db - policy database - * @entries_hash: Hashtable of entries - * @entries_rwlock: Mutex to protect the database's access entries - */ -struct kdbus_policy_db { - DECLARE_HASHTABLE(entries_hash, 6); - struct rw_semaphore entries_rwlock; -}; - -void kdbus_policy_db_init(struct kdbus_policy_db *db); -void kdbus_policy_db_clear(struct kdbus_policy_db *db); - -int kdbus_policy_query_unlocked(struct kdbus_policy_db *db, - const struct cred *cred, const char *name, - unsigned int hash); -int kdbus_policy_query(struct kdbus_policy_db *db, const struct cred *cred, - const char *name, unsigned int hash); - -void kdbus_policy_remove_owner(struct kdbus_policy_db *db, - const void *owner); -int kdbus_policy_set(struct kdbus_policy_db *db, - const struct kdbus_item *items, - size_t items_size, - size_t max_policies, - bool allow_wildcards, - const void *owner); - -#endif diff --git a/ipc/kdbus/pool.c b/ipc/kdbus/pool.c deleted file mode 100644 index c65043e8c..000000000 --- a/ipc/kdbus/pool.c +++ /dev/null @@ -1,728 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/aio.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/highmem.h> -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/pagemap.h> -#include <linux/rbtree.h> -#include <linux/sched.h> -#include <linux/shmem_fs.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/uaccess.h> -#include <linux/uio.h> - -#include "pool.h" -#include "util.h" - -/** - * struct kdbus_pool - the receiver's buffer - * @f: The backing shmem file - * @size: The size of the file - * @accounted_size: Currently accounted memory in bytes - * @lock: Pool data lock - * @slices: All slices sorted by address - * @slices_busy: Tree of allocated slices - * @slices_free: Tree of free slices - * - * The receiver's buffer, managed as a pool of allocated and free - * slices containing the queued messages. - * - * Messages sent with KDBUS_CMD_SEND are copied directly by the - * sending process into the receiver's pool. - * - * Messages received with KDBUS_CMD_RECV just return the offset - * to the data placed in the pool. - * - * The internally allocated memory needs to be returned by the receiver - * with KDBUS_CMD_FREE. - */ -struct kdbus_pool { - struct file *f; - size_t size; - size_t accounted_size; - struct mutex lock; - - struct list_head slices; - struct rb_root slices_busy; - struct rb_root slices_free; -}; - -/** - * struct kdbus_pool_slice - allocated element in kdbus_pool - * @pool: Pool this slice belongs to - * @off: Offset of slice in the shmem file - * @size: Size of slice - * @entry: Entry in "all slices" list - * @rb_node: Entry in free or busy list - * @free: Unused slice - * @accounted: Accounted as queue slice - * @ref_kernel: Kernel holds a reference - * @ref_user: Userspace holds a reference - * - * The pool has one or more slices, always spanning the entire size of the - * pool. - * - * Every slice is an element in a list sorted by the buffer address, to - * provide access to the next neighbor slice. - * - * Every slice is member in either the busy or the free tree. The free - * tree is organized by slice size, the busy tree organized by buffer - * offset. - */ -struct kdbus_pool_slice { - struct kdbus_pool *pool; - size_t off; - size_t size; - - struct list_head entry; - struct rb_node rb_node; - - bool free:1; - bool accounted:1; - bool ref_kernel:1; - bool ref_user:1; -}; - -static struct kdbus_pool_slice *kdbus_pool_slice_new(struct kdbus_pool *pool, - size_t off, size_t size) -{ - struct kdbus_pool_slice *slice; - - slice = kzalloc(sizeof(*slice), GFP_KERNEL); - if (!slice) - return NULL; - - slice->pool = pool; - slice->off = off; - slice->size = size; - slice->free = true; - return slice; -} - -/* insert a slice into the free tree */ -static void kdbus_pool_add_free_slice(struct kdbus_pool *pool, - struct kdbus_pool_slice *slice) -{ - struct rb_node **n; - struct rb_node *pn = NULL; - - n = &pool->slices_free.rb_node; - while (*n) { - struct kdbus_pool_slice *pslice; - - pn = *n; - pslice = rb_entry(pn, struct kdbus_pool_slice, rb_node); - if (slice->size < pslice->size) - n = &pn->rb_left; - else - n = &pn->rb_right; - } - - rb_link_node(&slice->rb_node, pn, n); - rb_insert_color(&slice->rb_node, &pool->slices_free); -} - -/* insert a slice into the busy tree */ -static void kdbus_pool_add_busy_slice(struct kdbus_pool *pool, - struct kdbus_pool_slice *slice) -{ - struct rb_node **n; - struct rb_node *pn = NULL; - - n = &pool->slices_busy.rb_node; - while (*n) { - struct kdbus_pool_slice *pslice; - - pn = *n; - pslice = rb_entry(pn, struct kdbus_pool_slice, rb_node); - if (slice->off < pslice->off) - n = &pn->rb_left; - else if (slice->off > pslice->off) - n = &pn->rb_right; - else - BUG(); - } - - rb_link_node(&slice->rb_node, pn, n); - rb_insert_color(&slice->rb_node, &pool->slices_busy); -} - -static struct kdbus_pool_slice *kdbus_pool_find_slice(struct kdbus_pool *pool, - size_t off) -{ - struct rb_node *n; - - n = pool->slices_busy.rb_node; - while (n) { - struct kdbus_pool_slice *s; - - s = rb_entry(n, struct kdbus_pool_slice, rb_node); - if (off < s->off) - n = n->rb_left; - else if (off > s->off) - n = n->rb_right; - else - return s; - } - - return NULL; -} - -/** - * kdbus_pool_slice_alloc() - allocate memory from a pool - * @pool: The receiver's pool - * @size: The number of bytes to allocate - * @accounted: Whether this slice should be accounted for - * - * The returned slice is used for kdbus_pool_slice_release() to - * free the allocated memory. If either @kvec or @iovec is non-NULL, the data - * will be copied from kernel or userspace memory into the new slice at - * offset 0. - * - * Return: the allocated slice on success, ERR_PTR on failure. - */ -struct kdbus_pool_slice *kdbus_pool_slice_alloc(struct kdbus_pool *pool, - size_t size, bool accounted) -{ - size_t slice_size = KDBUS_ALIGN8(size); - struct rb_node *n, *found = NULL; - struct kdbus_pool_slice *s; - int ret = 0; - - if (WARN_ON(!size)) - return ERR_PTR(-EINVAL); - - /* search a free slice with the closest matching size */ - mutex_lock(&pool->lock); - n = pool->slices_free.rb_node; - while (n) { - s = rb_entry(n, struct kdbus_pool_slice, rb_node); - if (slice_size < s->size) { - found = n; - n = n->rb_left; - } else if (slice_size > s->size) { - n = n->rb_right; - } else { - found = n; - break; - } - } - - /* no slice with the minimum size found in the pool */ - if (!found) { - ret = -EXFULL; - goto exit_unlock; - } - - /* no exact match, use the closest one */ - if (!n) { - struct kdbus_pool_slice *s_new; - - s = rb_entry(found, struct kdbus_pool_slice, rb_node); - - /* split-off the remainder of the size to its own slice */ - s_new = kdbus_pool_slice_new(pool, s->off + slice_size, - s->size - slice_size); - if (!s_new) { - ret = -ENOMEM; - goto exit_unlock; - } - - list_add(&s_new->entry, &s->entry); - kdbus_pool_add_free_slice(pool, s_new); - - /* adjust our size now that we split-off another slice */ - s->size = slice_size; - } - - /* move slice from free to the busy tree */ - rb_erase(found, &pool->slices_free); - kdbus_pool_add_busy_slice(pool, s); - - WARN_ON(s->ref_kernel || s->ref_user); - - s->ref_kernel = true; - s->free = false; - s->accounted = accounted; - if (accounted) - pool->accounted_size += s->size; - mutex_unlock(&pool->lock); - - return s; - -exit_unlock: - mutex_unlock(&pool->lock); - return ERR_PTR(ret); -} - -static void __kdbus_pool_slice_release(struct kdbus_pool_slice *slice) -{ - struct kdbus_pool *pool = slice->pool; - - /* don't free the slice if either has a reference */ - if (slice->ref_kernel || slice->ref_user) - return; - - if (WARN_ON(slice->free)) - return; - - rb_erase(&slice->rb_node, &pool->slices_busy); - - /* merge with the next free slice */ - if (!list_is_last(&slice->entry, &pool->slices)) { - struct kdbus_pool_slice *s; - - s = list_entry(slice->entry.next, - struct kdbus_pool_slice, entry); - if (s->free) { - rb_erase(&s->rb_node, &pool->slices_free); - list_del(&s->entry); - slice->size += s->size; - kfree(s); - } - } - - /* merge with previous free slice */ - if (pool->slices.next != &slice->entry) { - struct kdbus_pool_slice *s; - - s = list_entry(slice->entry.prev, - struct kdbus_pool_slice, entry); - if (s->free) { - rb_erase(&s->rb_node, &pool->slices_free); - list_del(&slice->entry); - s->size += slice->size; - kfree(slice); - slice = s; - } - } - - slice->free = true; - kdbus_pool_add_free_slice(pool, slice); -} - -/** - * kdbus_pool_slice_release() - drop kernel-reference on allocated slice - * @slice: Slice allocated from the pool - * - * This releases the kernel-reference on the given slice. If the - * kernel-reference and the user-reference on a slice are dropped, the slice is - * returned to the pool. - * - * So far, we do not implement full ref-counting on slices. Each, kernel and - * user-space can have exactly one reference to a slice. If both are dropped at - * the same time, the slice is released. - */ -void kdbus_pool_slice_release(struct kdbus_pool_slice *slice) -{ - struct kdbus_pool *pool; - - if (!slice) - return; - - /* @slice may be freed, so keep local ptr to @pool */ - pool = slice->pool; - - mutex_lock(&pool->lock); - /* kernel must own a ref to @slice to drop it */ - WARN_ON(!slice->ref_kernel); - slice->ref_kernel = false; - /* no longer kernel-owned, de-account slice */ - if (slice->accounted && !WARN_ON(pool->accounted_size < slice->size)) - pool->accounted_size -= slice->size; - __kdbus_pool_slice_release(slice); - mutex_unlock(&pool->lock); -} - -/** - * kdbus_pool_release_offset() - release a public offset - * @pool: pool to operate on - * @off: offset to release - * - * This should be called whenever user-space frees a slice given to them. It - * verifies the slice is available and public, and then drops it. It ensures - * correct locking and barriers against queues. - * - * Return: 0 on success, ENXIO if the offset is invalid or not public. - */ -int kdbus_pool_release_offset(struct kdbus_pool *pool, size_t off) -{ - struct kdbus_pool_slice *slice; - int ret = 0; - - /* 'pool->size' is used as dummy offset for empty slices */ - if (off == pool->size) - return 0; - - mutex_lock(&pool->lock); - slice = kdbus_pool_find_slice(pool, off); - if (slice && slice->ref_user) { - slice->ref_user = false; - __kdbus_pool_slice_release(slice); - } else { - ret = -ENXIO; - } - mutex_unlock(&pool->lock); - - return ret; -} - -/** - * kdbus_pool_publish_empty() - publish empty slice to user-space - * @pool: pool to operate on - * @off: output storage for offset, or NULL - * @size: output storage for size, or NULL - * - * This is the same as kdbus_pool_slice_publish(), but uses a dummy slice with - * size 0. The returned offset points to the end of the pool and is never - * returned on real slices. - */ -void kdbus_pool_publish_empty(struct kdbus_pool *pool, u64 *off, u64 *size) -{ - if (off) - *off = pool->size; - if (size) - *size = 0; -} - -/** - * kdbus_pool_slice_publish() - publish slice to user-space - * @slice: The slice - * @out_offset: Output storage for offset, or NULL - * @out_size: Output storage for size, or NULL - * - * This prepares a slice to be published to user-space. - * - * This call combines the following operations: - * * the memory region is flushed so the user's memory view is consistent - * * the slice is marked as referenced by user-space, so user-space has to - * call KDBUS_CMD_FREE to release it - * * the offset and size of the slice are written to the given output - * arguments, if non-NULL - */ -void kdbus_pool_slice_publish(struct kdbus_pool_slice *slice, - u64 *out_offset, u64 *out_size) -{ - mutex_lock(&slice->pool->lock); - /* kernel must own a ref to @slice to gain a user-space ref */ - WARN_ON(!slice->ref_kernel); - slice->ref_user = true; - mutex_unlock(&slice->pool->lock); - - if (out_offset) - *out_offset = slice->off; - if (out_size) - *out_size = slice->size; -} - -/** - * kdbus_pool_slice_offset() - Get a slice's offset inside the pool - * @slice: Slice to return the offset of - * - * Return: The internal offset @slice inside the pool. - */ -off_t kdbus_pool_slice_offset(const struct kdbus_pool_slice *slice) -{ - return slice->off; -} - -/** - * kdbus_pool_slice_size() - get size of a pool slice - * @slice: slice to query - * - * Return: size of the given slice - */ -size_t kdbus_pool_slice_size(const struct kdbus_pool_slice *slice) -{ - return slice->size; -} - -/** - * kdbus_pool_new() - create a new pool - * @name: Name of the (deleted) file which shows up in - * /proc, used for debugging - * @size: Maximum size of the pool - * - * Return: a new kdbus_pool on success, ERR_PTR on failure. - */ -struct kdbus_pool *kdbus_pool_new(const char *name, size_t size) -{ - struct kdbus_pool_slice *s; - struct kdbus_pool *p; - struct file *f; - char *n = NULL; - int ret; - - p = kzalloc(sizeof(*p), GFP_KERNEL); - if (!p) - return ERR_PTR(-ENOMEM); - - if (name) { - n = kasprintf(GFP_KERNEL, KBUILD_MODNAME "-conn:%s", name); - if (!n) { - ret = -ENOMEM; - goto exit_free; - } - } - - f = shmem_file_setup(n ?: KBUILD_MODNAME "-conn", size, 0, 0); - kfree(n); - - if (IS_ERR(f)) { - ret = PTR_ERR(f); - goto exit_free; - } - - ret = get_write_access(file_inode(f)); - if (ret < 0) - goto exit_put_shmem; - - /* allocate first slice spanning the entire pool */ - s = kdbus_pool_slice_new(p, 0, size); - if (!s) { - ret = -ENOMEM; - goto exit_put_write; - } - - p->f = f; - p->size = size; - p->slices_free = RB_ROOT; - p->slices_busy = RB_ROOT; - mutex_init(&p->lock); - - INIT_LIST_HEAD(&p->slices); - list_add(&s->entry, &p->slices); - - kdbus_pool_add_free_slice(p, s); - return p; - -exit_put_write: - put_write_access(file_inode(f)); -exit_put_shmem: - fput(f); -exit_free: - kfree(p); - return ERR_PTR(ret); -} - -/** - * kdbus_pool_free() - destroy pool - * @pool: The receiver's pool - */ -void kdbus_pool_free(struct kdbus_pool *pool) -{ - struct kdbus_pool_slice *s, *tmp; - - if (!pool) - return; - - list_for_each_entry_safe(s, tmp, &pool->slices, entry) { - list_del(&s->entry); - kfree(s); - } - - put_write_access(file_inode(pool->f)); - fput(pool->f); - kfree(pool); -} - -/** - * kdbus_pool_accounted() - retrieve accounting information - * @pool: pool to query - * @size: output for overall pool size - * @acc: output for currently accounted size - * - * This returns accounting information of the pool. Note that the data might - * change after the function returns, as the pool lock is dropped. You need to - * protect the data via other means, if you need reliable accounting. - */ -void kdbus_pool_accounted(struct kdbus_pool *pool, size_t *size, size_t *acc) -{ - mutex_lock(&pool->lock); - if (size) - *size = pool->size; - if (acc) - *acc = pool->accounted_size; - mutex_unlock(&pool->lock); -} - -/** - * kdbus_pool_slice_copy_iovec() - copy user memory to a slice - * @slice: The slice to write to - * @off: Offset in the slice to write to - * @iov: iovec array, pointing to data to copy - * @iov_len: Number of elements in @iov - * @total_len: Total number of bytes described in members of @iov - * - * User memory referenced by @iov will be copied into @slice at offset @off. - * - * Return: the numbers of bytes copied, negative errno on failure. - */ -ssize_t -kdbus_pool_slice_copy_iovec(const struct kdbus_pool_slice *slice, loff_t off, - struct iovec *iov, size_t iov_len, size_t total_len) -{ - struct iov_iter iter; - ssize_t len; - - if (WARN_ON(off + total_len > slice->size)) - return -EFAULT; - - off += slice->off; - iov_iter_init(&iter, WRITE, iov, iov_len, total_len); - len = vfs_iter_write(slice->pool->f, &iter, &off); - - return (len >= 0 && len != total_len) ? -EFAULT : len; -} - -/** - * kdbus_pool_slice_copy_kvec() - copy kernel memory to a slice - * @slice: The slice to write to - * @off: Offset in the slice to write to - * @kvec: kvec array, pointing to data to copy - * @kvec_len: Number of elements in @kvec - * @total_len: Total number of bytes described in members of @kvec - * - * Kernel memory referenced by @kvec will be copied into @slice at offset @off. - * - * Return: the numbers of bytes copied, negative errno on failure. - */ -ssize_t kdbus_pool_slice_copy_kvec(const struct kdbus_pool_slice *slice, - loff_t off, struct kvec *kvec, - size_t kvec_len, size_t total_len) -{ - struct iov_iter iter; - mm_segment_t old_fs; - ssize_t len; - - if (WARN_ON(off + total_len > slice->size)) - return -EFAULT; - - off += slice->off; - iov_iter_kvec(&iter, WRITE | ITER_KVEC, kvec, kvec_len, total_len); - - old_fs = get_fs(); - set_fs(get_ds()); - len = vfs_iter_write(slice->pool->f, &iter, &off); - set_fs(old_fs); - - return (len >= 0 && len != total_len) ? -EFAULT : len; -} - -/** - * kdbus_pool_slice_copy() - copy data from one slice into another - * @slice_dst: destination slice - * @slice_src: source slice - * - * Return: 0 on success, negative error number on failure. - */ -int kdbus_pool_slice_copy(const struct kdbus_pool_slice *slice_dst, - const struct kdbus_pool_slice *slice_src) -{ - struct file *f_src = slice_src->pool->f; - struct file *f_dst = slice_dst->pool->f; - struct inode *i_dst = file_inode(f_dst); - struct address_space *mapping_dst = f_dst->f_mapping; - const struct address_space_operations *aops = mapping_dst->a_ops; - unsigned long len = slice_src->size; - loff_t off_src = slice_src->off; - loff_t off_dst = slice_dst->off; - mm_segment_t old_fs; - int ret = 0; - - if (WARN_ON(slice_src->size != slice_dst->size) || - WARN_ON(slice_src->free || slice_dst->free)) - return -EINVAL; - - mutex_lock(&i_dst->i_mutex); - old_fs = get_fs(); - set_fs(get_ds()); - while (len > 0) { - unsigned long page_off; - unsigned long copy_len; - char __user *kaddr; - struct page *page; - ssize_t n_read; - void *fsdata; - long status; - - page_off = off_dst & (PAGE_CACHE_SIZE - 1); - copy_len = min_t(unsigned long, - PAGE_CACHE_SIZE - page_off, len); - - status = aops->write_begin(f_dst, mapping_dst, off_dst, - copy_len, 0, &page, &fsdata); - if (unlikely(status < 0)) { - ret = status; - break; - } - - kaddr = (char __force __user *)kmap(page) + page_off; - n_read = __vfs_read(f_src, kaddr, copy_len, &off_src); - kunmap(page); - mark_page_accessed(page); - flush_dcache_page(page); - - if (unlikely(n_read != copy_len)) { - ret = -EFAULT; - break; - } - - status = aops->write_end(f_dst, mapping_dst, off_dst, - copy_len, copy_len, page, fsdata); - if (unlikely(status != copy_len)) { - ret = -EFAULT; - break; - } - - off_dst += copy_len; - len -= copy_len; - } - set_fs(old_fs); - mutex_unlock(&i_dst->i_mutex); - - return ret; -} - -/** - * kdbus_pool_mmap() - map the pool into the process - * @pool: The receiver's pool - * @vma: passed by mmap() syscall - * - * Return: the result of the mmap() call, negative errno on failure. - */ -int kdbus_pool_mmap(const struct kdbus_pool *pool, struct vm_area_struct *vma) -{ - /* deny write access to the pool */ - if (vma->vm_flags & VM_WRITE) - return -EPERM; - vma->vm_flags &= ~VM_MAYWRITE; - - /* do not allow to map more than the size of the file */ - if ((vma->vm_end - vma->vm_start) > pool->size) - return -EFAULT; - - /* replace the connection file with our shmem file */ - if (vma->vm_file) - fput(vma->vm_file); - vma->vm_file = get_file(pool->f); - - return pool->f->f_op->mmap(pool->f, vma); -} diff --git a/ipc/kdbus/pool.h b/ipc/kdbus/pool.h deleted file mode 100644 index a9038213a..000000000 --- a/ipc/kdbus/pool.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_POOL_H -#define __KDBUS_POOL_H - -#include <linux/uio.h> - -struct kdbus_pool; -struct kdbus_pool_slice; - -struct kdbus_pool *kdbus_pool_new(const char *name, size_t size); -void kdbus_pool_free(struct kdbus_pool *pool); -void kdbus_pool_accounted(struct kdbus_pool *pool, size_t *size, size_t *acc); -int kdbus_pool_mmap(const struct kdbus_pool *pool, struct vm_area_struct *vma); -int kdbus_pool_release_offset(struct kdbus_pool *pool, size_t off); -void kdbus_pool_publish_empty(struct kdbus_pool *pool, u64 *off, u64 *size); - -struct kdbus_pool_slice *kdbus_pool_slice_alloc(struct kdbus_pool *pool, - size_t size, bool accounted); -void kdbus_pool_slice_release(struct kdbus_pool_slice *slice); -void kdbus_pool_slice_publish(struct kdbus_pool_slice *slice, - u64 *out_offset, u64 *out_size); -off_t kdbus_pool_slice_offset(const struct kdbus_pool_slice *slice); -size_t kdbus_pool_slice_size(const struct kdbus_pool_slice *slice); -int kdbus_pool_slice_copy(const struct kdbus_pool_slice *slice_dst, - const struct kdbus_pool_slice *slice_src); -ssize_t kdbus_pool_slice_copy_kvec(const struct kdbus_pool_slice *slice, - loff_t off, struct kvec *kvec, - size_t kvec_count, size_t total_len); -ssize_t kdbus_pool_slice_copy_iovec(const struct kdbus_pool_slice *slice, - loff_t off, struct iovec *iov, - size_t iov_count, size_t total_len); - -#endif diff --git a/ipc/kdbus/queue.c b/ipc/kdbus/queue.c deleted file mode 100644 index f9c44d7ba..000000000 --- a/ipc/kdbus/queue.c +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/audit.h> -#include <linux/file.h> -#include <linux/fs.h> -#include <linux/hashtable.h> -#include <linux/idr.h> -#include <linux/init.h> -#include <linux/math64.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/poll.h> -#include <linux/sched.h> -#include <linux/sizes.h> -#include <linux/slab.h> -#include <linux/syscalls.h> -#include <linux/uio.h> - -#include "util.h" -#include "domain.h" -#include "connection.h" -#include "item.h" -#include "message.h" -#include "metadata.h" -#include "queue.h" -#include "reply.h" - -/** - * kdbus_queue_init() - initialize data structure related to a queue - * @queue: The queue to initialize - */ -void kdbus_queue_init(struct kdbus_queue *queue) -{ - INIT_LIST_HEAD(&queue->msg_list); - queue->msg_prio_queue = RB_ROOT; -} - -/** - * kdbus_queue_peek() - Retrieves an entry from a queue - * @queue: The queue - * @priority: The minimum priority of the entry to peek - * @use_priority: Boolean flag whether or not to peek by priority - * - * Look for a entry in a queue, either by priority, or the oldest one (FIFO). - * The entry is not freed, put off the queue's lists or anything else. - * - * Return: the peeked queue entry on success, NULL if no suitable msg is found - */ -struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue, - s64 priority, bool use_priority) -{ - struct kdbus_queue_entry *e; - - if (list_empty(&queue->msg_list)) - return NULL; - - if (use_priority) { - /* get next entry with highest priority */ - e = rb_entry(queue->msg_prio_highest, - struct kdbus_queue_entry, prio_node); - - /* no entry with the requested priority */ - if (e->priority > priority) - return NULL; - } else { - /* ignore the priority, return the next entry in the entry */ - e = list_first_entry(&queue->msg_list, - struct kdbus_queue_entry, entry); - } - - return e; -} - -static void kdbus_queue_entry_link(struct kdbus_queue_entry *entry) -{ - struct kdbus_queue *queue = &entry->conn->queue; - struct rb_node **n, *pn = NULL; - bool highest = true; - - lockdep_assert_held(&entry->conn->lock); - if (WARN_ON(!list_empty(&entry->entry))) - return; - - /* sort into priority entry tree */ - n = &queue->msg_prio_queue.rb_node; - while (*n) { - struct kdbus_queue_entry *e; - - pn = *n; - e = rb_entry(pn, struct kdbus_queue_entry, prio_node); - - /* existing node for this priority, add to its list */ - if (likely(entry->priority == e->priority)) { - list_add_tail(&entry->prio_entry, &e->prio_entry); - goto prio_done; - } - - if (entry->priority < e->priority) { - n = &pn->rb_left; - } else { - n = &pn->rb_right; - highest = false; - } - } - - /* cache highest-priority entry */ - if (highest) - queue->msg_prio_highest = &entry->prio_node; - - /* new node for this priority */ - rb_link_node(&entry->prio_node, pn, n); - rb_insert_color(&entry->prio_node, &queue->msg_prio_queue); - INIT_LIST_HEAD(&entry->prio_entry); - -prio_done: - /* add to unsorted fifo list */ - list_add_tail(&entry->entry, &queue->msg_list); -} - -static void kdbus_queue_entry_unlink(struct kdbus_queue_entry *entry) -{ - struct kdbus_queue *queue = &entry->conn->queue; - - lockdep_assert_held(&entry->conn->lock); - if (list_empty(&entry->entry)) - return; - - list_del_init(&entry->entry); - - if (list_empty(&entry->prio_entry)) { - /* - * Single entry for this priority, update cached - * highest-priority entry, remove the tree node. - */ - if (queue->msg_prio_highest == &entry->prio_node) - queue->msg_prio_highest = rb_next(&entry->prio_node); - - rb_erase(&entry->prio_node, &queue->msg_prio_queue); - } else { - struct kdbus_queue_entry *q; - - /* - * Multiple entries for this priority entry, get next one in - * the list. Update cached highest-priority entry, store the - * new one as the tree node. - */ - q = list_first_entry(&entry->prio_entry, - struct kdbus_queue_entry, prio_entry); - list_del(&entry->prio_entry); - - if (queue->msg_prio_highest == &entry->prio_node) - queue->msg_prio_highest = &q->prio_node; - - rb_replace_node(&entry->prio_node, &q->prio_node, - &queue->msg_prio_queue); - } -} - -/** - * kdbus_queue_entry_new() - allocate a queue entry - * @src: source connection, or NULL - * @dst: destination connection - * @s: staging object carrying the message - * - * Allocates a queue entry based on a given msg and allocate space for - * the message payload and the requested metadata in the connection's pool. - * The entry is not actually added to the queue's lists at this point. - * - * Return: the allocated entry on success, or an ERR_PTR on failures. - */ -struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src, - struct kdbus_conn *dst, - struct kdbus_staging *s) -{ - struct kdbus_queue_entry *entry; - int ret; - - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return ERR_PTR(-ENOMEM); - - INIT_LIST_HEAD(&entry->entry); - entry->priority = s->msg->priority; - entry->conn = kdbus_conn_ref(dst); - entry->gaps = kdbus_gaps_ref(s->gaps); - - entry->slice = kdbus_staging_emit(s, src, dst); - if (IS_ERR(entry->slice)) { - ret = PTR_ERR(entry->slice); - entry->slice = NULL; - goto error; - } - - entry->user = src ? kdbus_user_ref(src->user) : NULL; - return entry; - -error: - kdbus_queue_entry_free(entry); - return ERR_PTR(ret); -} - -/** - * kdbus_queue_entry_free() - free resources of an entry - * @entry: The entry to free - * - * Removes resources allocated by a queue entry, along with the entry itself. - * Note that the entry's slice is not freed at this point. - */ -void kdbus_queue_entry_free(struct kdbus_queue_entry *entry) -{ - if (!entry) - return; - - lockdep_assert_held(&entry->conn->lock); - - kdbus_queue_entry_unlink(entry); - kdbus_reply_unref(entry->reply); - - if (entry->slice) { - kdbus_conn_quota_dec(entry->conn, entry->user, - kdbus_pool_slice_size(entry->slice), - entry->gaps ? entry->gaps->n_fds : 0); - kdbus_pool_slice_release(entry->slice); - } - - kdbus_user_unref(entry->user); - kdbus_gaps_unref(entry->gaps); - kdbus_conn_unref(entry->conn); - kfree(entry); -} - -/** - * kdbus_queue_entry_install() - install message components into the - * receiver's process - * @entry: The queue entry to install - * @return_flags: Pointer to store the return flags for userspace - * @install_fds: Whether or not to install associated file descriptors - * - * Return: 0 on success. - */ -int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, - u64 *return_flags, bool install_fds) -{ - bool incomplete_fds = false; - int ret; - - lockdep_assert_held(&entry->conn->lock); - - ret = kdbus_gaps_install(entry->gaps, entry->slice, &incomplete_fds); - if (ret < 0) - return ret; - - if (incomplete_fds) - *return_flags |= KDBUS_RECV_RETURN_INCOMPLETE_FDS; - return 0; -} - -/** - * kdbus_queue_entry_enqueue() - enqueue an entry - * @entry: entry to enqueue - * @reply: reply to link to this entry (or NULL if none) - * - * This enqueues an unqueued entry into the message queue of the linked - * connection. It also binds a reply object to the entry so we can remember it - * when the message is moved. - * - * Once this call returns (and the connection lock is released), this entry can - * be dequeued by the target connection. Note that the entry will not be removed - * from the queue until it is destroyed. - */ -void kdbus_queue_entry_enqueue(struct kdbus_queue_entry *entry, - struct kdbus_reply *reply) -{ - lockdep_assert_held(&entry->conn->lock); - - if (WARN_ON(entry->reply) || WARN_ON(!list_empty(&entry->entry))) - return; - - entry->reply = kdbus_reply_ref(reply); - kdbus_queue_entry_link(entry); -} - -/** - * kdbus_queue_entry_move() - move queue entry - * @e: queue entry to move - * @dst: destination connection to queue the entry on - * - * This moves a queue entry onto a different connection. It allocates a new - * slice on the target connection and copies the message over. If the copy - * succeeded, we move the entry from @src to @dst. - * - * On failure, the entry is left untouched. - * - * The queue entry must be queued right now, and after the call succeeds it will - * be queued on the destination, but no longer on the source. - * - * The caller must hold the connection lock of the source *and* destination. - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_queue_entry_move(struct kdbus_queue_entry *e, - struct kdbus_conn *dst) -{ - struct kdbus_pool_slice *slice = NULL; - struct kdbus_conn *src = e->conn; - size_t size, fds; - int ret; - - lockdep_assert_held(&src->lock); - lockdep_assert_held(&dst->lock); - - if (WARN_ON(list_empty(&e->entry))) - return -EINVAL; - if (src == dst) - return 0; - - size = kdbus_pool_slice_size(e->slice); - fds = e->gaps ? e->gaps->n_fds : 0; - - ret = kdbus_conn_quota_inc(dst, e->user, size, fds); - if (ret < 0) - return ret; - - slice = kdbus_pool_slice_alloc(dst->pool, size, true); - if (IS_ERR(slice)) { - ret = PTR_ERR(slice); - slice = NULL; - goto error; - } - - ret = kdbus_pool_slice_copy(slice, e->slice); - if (ret < 0) - goto error; - - kdbus_queue_entry_unlink(e); - kdbus_conn_quota_dec(src, e->user, size, fds); - kdbus_pool_slice_release(e->slice); - kdbus_conn_unref(e->conn); - - e->slice = slice; - e->conn = kdbus_conn_ref(dst); - kdbus_queue_entry_link(e); - - return 0; - -error: - kdbus_pool_slice_release(slice); - kdbus_conn_quota_dec(dst, e->user, size, fds); - return ret; -} diff --git a/ipc/kdbus/queue.h b/ipc/kdbus/queue.h deleted file mode 100644 index bf686d182..000000000 --- a/ipc/kdbus/queue.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_QUEUE_H -#define __KDBUS_QUEUE_H - -#include <linux/list.h> -#include <linux/rbtree.h> - -struct kdbus_conn; -struct kdbus_pool_slice; -struct kdbus_reply; -struct kdbus_staging; -struct kdbus_user; - -/** - * struct kdbus_queue - a connection's message queue - * @msg_list: List head for kdbus_queue_entry objects - * @msg_prio_queue: RB tree root for messages, sorted by priority - * @msg_prio_highest: Link to the RB node referencing the message with the - * highest priority in the tree. - */ -struct kdbus_queue { - struct list_head msg_list; - struct rb_root msg_prio_queue; - struct rb_node *msg_prio_highest; -}; - -/** - * struct kdbus_queue_entry - messages waiting to be read - * @entry: Entry in the connection's list - * @prio_node: Entry in the priority queue tree - * @prio_entry: Queue tree node entry in the list of one priority - * @priority: Message priority - * @dst_name_id: The sequence number of the name this message is - * addressed to, 0 for messages sent to an ID - * @conn: Connection this entry is queued on - * @gaps: Gaps object to fill message gaps at RECV time - * @user: User used for accounting - * @slice: Slice in the receiver's pool for the message - * @reply: The reply block if a reply to this message is expected - */ -struct kdbus_queue_entry { - struct list_head entry; - struct rb_node prio_node; - struct list_head prio_entry; - - s64 priority; - u64 dst_name_id; - - struct kdbus_conn *conn; - struct kdbus_gaps *gaps; - struct kdbus_user *user; - struct kdbus_pool_slice *slice; - struct kdbus_reply *reply; -}; - -void kdbus_queue_init(struct kdbus_queue *queue); -struct kdbus_queue_entry *kdbus_queue_peek(struct kdbus_queue *queue, - s64 priority, bool use_priority); - -struct kdbus_queue_entry *kdbus_queue_entry_new(struct kdbus_conn *src, - struct kdbus_conn *dst, - struct kdbus_staging *s); -void kdbus_queue_entry_free(struct kdbus_queue_entry *entry); -int kdbus_queue_entry_install(struct kdbus_queue_entry *entry, - u64 *return_flags, bool install_fds); -void kdbus_queue_entry_enqueue(struct kdbus_queue_entry *entry, - struct kdbus_reply *reply); -int kdbus_queue_entry_move(struct kdbus_queue_entry *entry, - struct kdbus_conn *dst); - -#endif /* __KDBUS_QUEUE_H */ diff --git a/ipc/kdbus/reply.c b/ipc/kdbus/reply.c deleted file mode 100644 index e6791d86e..000000000 --- a/ipc/kdbus/reply.c +++ /dev/null @@ -1,252 +0,0 @@ -#include <linux/init.h> -#include <linux/mm.h> -#include <linux/module.h> -#include <linux/mutex.h> -#include <linux/slab.h> -#include <linux/uio.h> - -#include "bus.h" -#include "connection.h" -#include "endpoint.h" -#include "message.h" -#include "metadata.h" -#include "names.h" -#include "domain.h" -#include "item.h" -#include "notify.h" -#include "policy.h" -#include "reply.h" -#include "util.h" - -/** - * kdbus_reply_new() - Allocate and set up a new kdbus_reply object - * @reply_src: The connection a reply is expected from - * @reply_dst: The connection this reply object belongs to - * @msg: Message associated with the reply - * @name_entry: Name entry used to send the message - * @sync: Whether or not to make this reply synchronous - * - * Allocate and fill a new kdbus_reply object. - * - * Return: New kdbus_conn object on success, ERR_PTR on error. - */ -struct kdbus_reply *kdbus_reply_new(struct kdbus_conn *reply_src, - struct kdbus_conn *reply_dst, - const struct kdbus_msg *msg, - struct kdbus_name_entry *name_entry, - bool sync) -{ - struct kdbus_reply *r; - int ret; - - if (atomic_inc_return(&reply_dst->request_count) > - KDBUS_CONN_MAX_REQUESTS_PENDING) { - ret = -EMLINK; - goto exit_dec_request_count; - } - - r = kzalloc(sizeof(*r), GFP_KERNEL); - if (!r) { - ret = -ENOMEM; - goto exit_dec_request_count; - } - - kref_init(&r->kref); - INIT_LIST_HEAD(&r->entry); - r->reply_src = kdbus_conn_ref(reply_src); - r->reply_dst = kdbus_conn_ref(reply_dst); - r->cookie = msg->cookie; - r->name_id = name_entry ? name_entry->name_id : 0; - r->deadline_ns = msg->timeout_ns; - - if (sync) { - r->sync = true; - r->waiting = true; - } - - return r; - -exit_dec_request_count: - atomic_dec(&reply_dst->request_count); - return ERR_PTR(ret); -} - -static void __kdbus_reply_free(struct kref *kref) -{ - struct kdbus_reply *reply = - container_of(kref, struct kdbus_reply, kref); - - atomic_dec(&reply->reply_dst->request_count); - kdbus_conn_unref(reply->reply_src); - kdbus_conn_unref(reply->reply_dst); - kfree(reply); -} - -/** - * kdbus_reply_ref() - Increase reference on kdbus_reply - * @r: The reply, may be %NULL - * - * Return: The reply object with an extra reference - */ -struct kdbus_reply *kdbus_reply_ref(struct kdbus_reply *r) -{ - if (r) - kref_get(&r->kref); - return r; -} - -/** - * kdbus_reply_unref() - Decrease reference on kdbus_reply - * @r: The reply, may be %NULL - * - * Return: NULL - */ -struct kdbus_reply *kdbus_reply_unref(struct kdbus_reply *r) -{ - if (r) - kref_put(&r->kref, __kdbus_reply_free); - return NULL; -} - -/** - * kdbus_reply_link() - Link reply object into target connection - * @r: Reply to link - */ -void kdbus_reply_link(struct kdbus_reply *r) -{ - if (WARN_ON(!list_empty(&r->entry))) - return; - - list_add(&r->entry, &r->reply_dst->reply_list); - kdbus_reply_ref(r); -} - -/** - * kdbus_reply_unlink() - Unlink reply object from target connection - * @r: Reply to unlink - */ -void kdbus_reply_unlink(struct kdbus_reply *r) -{ - if (!list_empty(&r->entry)) { - list_del_init(&r->entry); - kdbus_reply_unref(r); - } -} - -/** - * kdbus_sync_reply_wakeup() - Wake a synchronously blocking reply - * @reply: The reply object - * @err: Error code to set on the remote side - * - * Wake up remote peer (method origin) with the appropriate synchronous reply - * code. - */ -void kdbus_sync_reply_wakeup(struct kdbus_reply *reply, int err) -{ - if (WARN_ON(!reply->sync)) - return; - - reply->waiting = false; - reply->err = err; - wake_up_interruptible(&reply->reply_dst->wait); -} - -/** - * kdbus_reply_find() - Find the corresponding reply object - * @replying: The replying connection or NULL - * @reply_dst: The connection the reply will be sent to - * (method origin) - * @cookie: The cookie of the requesting message - * - * Lookup a reply object that should be sent as a reply by - * @replying to @reply_dst with the given cookie. - * - * Callers must take the @reply_dst lock. - * - * Return: the corresponding reply object or NULL if not found - */ -struct kdbus_reply *kdbus_reply_find(struct kdbus_conn *replying, - struct kdbus_conn *reply_dst, - u64 cookie) -{ - struct kdbus_reply *r; - - list_for_each_entry(r, &reply_dst->reply_list, entry) { - if (r->cookie == cookie && - (!replying || r->reply_src == replying)) - return r; - } - - return NULL; -} - -/** - * kdbus_reply_list_scan_work() - Worker callback to scan the replies of a - * connection for exceeded timeouts - * @work: Work struct of the connection to scan - * - * Walk the list of replies stored with a connection and look for entries - * that have exceeded their timeout. If such an entry is found, a timeout - * notification is sent to the waiting peer, and the reply is removed from - * the list. - * - * The work is rescheduled to the nearest timeout found during the list - * iteration. - */ -void kdbus_reply_list_scan_work(struct work_struct *work) -{ - struct kdbus_conn *conn = - container_of(work, struct kdbus_conn, work.work); - struct kdbus_reply *reply, *reply_tmp; - u64 deadline = ~0ULL; - u64 now; - - now = ktime_get_ns(); - - mutex_lock(&conn->lock); - if (!kdbus_conn_active(conn)) { - mutex_unlock(&conn->lock); - return; - } - - list_for_each_entry_safe(reply, reply_tmp, &conn->reply_list, entry) { - /* - * If the reply block is waiting for synchronous I/O, - * the timeout is handled by wait_event_*_timeout(), - * so we don't have to care for it here. - */ - if (reply->sync && !reply->interrupted) - continue; - - WARN_ON(reply->reply_dst != conn); - - if (reply->deadline_ns > now) { - /* remember next timeout */ - if (deadline > reply->deadline_ns) - deadline = reply->deadline_ns; - - continue; - } - - /* - * A zero deadline means the connection died, was - * cleaned up already and the notification was sent. - * Don't send notifications for reply trackers that were - * left in an interrupted syscall state. - */ - if (reply->deadline_ns != 0 && !reply->interrupted) - kdbus_notify_reply_timeout(conn->ep->bus, conn->id, - reply->cookie); - - kdbus_reply_unlink(reply); - } - - /* rearm delayed work with next timeout */ - if (deadline != ~0ULL) - schedule_delayed_work(&conn->work, - nsecs_to_jiffies(deadline - now)); - - mutex_unlock(&conn->lock); - - kdbus_notify_flush(conn->ep->bus); -} diff --git a/ipc/kdbus/reply.h b/ipc/kdbus/reply.h deleted file mode 100644 index 68d52321a..000000000 --- a/ipc/kdbus/reply.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_REPLY_H -#define __KDBUS_REPLY_H - -/** - * struct kdbus_reply - an entry of kdbus_conn's list of replies - * @kref: Ref-count of this object - * @entry: The entry of the connection's reply_list - * @reply_src: The connection the reply will be sent from - * @reply_dst: The connection the reply will be sent to - * @queue_entry: The queue entry item that is prepared by the replying - * connection - * @deadline_ns: The deadline of the reply, in nanoseconds - * @cookie: The cookie of the requesting message - * @name_id: ID of the well-known name the original msg was sent to - * @sync: The reply block is waiting for synchronous I/O - * @waiting: The condition to synchronously wait for - * @interrupted: The sync reply was left in an interrupted state - * @err: The error code for the synchronous reply - */ -struct kdbus_reply { - struct kref kref; - struct list_head entry; - struct kdbus_conn *reply_src; - struct kdbus_conn *reply_dst; - struct kdbus_queue_entry *queue_entry; - u64 deadline_ns; - u64 cookie; - u64 name_id; - bool sync:1; - bool waiting:1; - bool interrupted:1; - int err; -}; - -struct kdbus_reply *kdbus_reply_new(struct kdbus_conn *reply_src, - struct kdbus_conn *reply_dst, - const struct kdbus_msg *msg, - struct kdbus_name_entry *name_entry, - bool sync); - -struct kdbus_reply *kdbus_reply_ref(struct kdbus_reply *r); -struct kdbus_reply *kdbus_reply_unref(struct kdbus_reply *r); - -void kdbus_reply_link(struct kdbus_reply *r); -void kdbus_reply_unlink(struct kdbus_reply *r); - -struct kdbus_reply *kdbus_reply_find(struct kdbus_conn *replying, - struct kdbus_conn *reply_dst, - u64 cookie); - -void kdbus_sync_reply_wakeup(struct kdbus_reply *reply, int err); -void kdbus_reply_list_scan_work(struct work_struct *work); - -#endif /* __KDBUS_REPLY_H */ diff --git a/ipc/kdbus/util.c b/ipc/kdbus/util.c deleted file mode 100644 index 72b188330..000000000 --- a/ipc/kdbus/util.c +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#include <linux/capability.h> -#include <linux/cred.h> -#include <linux/ctype.h> -#include <linux/err.h> -#include <linux/file.h> -#include <linux/slab.h> -#include <linux/string.h> -#include <linux/uaccess.h> -#include <linux/uio.h> -#include <linux/user_namespace.h> - -#include "limits.h" -#include "util.h" - -/** - * kdbus_copy_from_user() - copy aligned data from user-space - * @dest: target buffer in kernel memory - * @user_ptr: user-provided source buffer - * @size: memory size to copy from user - * - * This copies @size bytes from @user_ptr into the kernel, just like - * copy_from_user() does. But we enforce an 8-byte alignment and reject any - * unaligned user-space pointers. - * - * Return: 0 on success, negative error code on failure. - */ -int kdbus_copy_from_user(void *dest, void __user *user_ptr, size_t size) -{ - if (!KDBUS_IS_ALIGNED8((uintptr_t)user_ptr)) - return -EFAULT; - - if (copy_from_user(dest, user_ptr, size)) - return -EFAULT; - - return 0; -} - -/** - * kdbus_verify_uid_prefix() - verify UID prefix of a user-supplied name - * @name: user-supplied name to verify - * @user_ns: user-namespace to act in - * @kuid: Kernel internal uid of user - * - * This verifies that the user-supplied name @name has their UID as prefix. This - * is the default name-spacing policy we enforce on user-supplied names for - * public kdbus entities like buses and endpoints. - * - * The user must supply names prefixed with "<UID>-", whereas the UID is - * interpreted in the user-namespace of the domain. If the user fails to supply - * such a prefixed name, we reject it. - * - * Return: 0 on success, negative error code on failure - */ -int kdbus_verify_uid_prefix(const char *name, struct user_namespace *user_ns, - kuid_t kuid) -{ - uid_t uid; - char prefix[16]; - - /* - * The kuid must have a mapping into the userns of the domain - * otherwise do not allow creation of buses nor endpoints. - */ - uid = from_kuid(user_ns, kuid); - if (uid == (uid_t) -1) - return -EINVAL; - - snprintf(prefix, sizeof(prefix), "%u-", uid); - if (strncmp(name, prefix, strlen(prefix)) != 0) - return -EINVAL; - - return 0; -} - -/** - * kdbus_sanitize_attach_flags() - Sanitize attach flags from user-space - * @flags: Attach flags provided by userspace - * @attach_flags: A pointer where to store the valid attach flags - * - * Convert attach-flags provided by user-space into a valid mask. If the mask - * is invalid, an error is returned. The sanitized attach flags are stored in - * the output parameter. - * - * Return: 0 on success, negative error on failure. - */ -int kdbus_sanitize_attach_flags(u64 flags, u64 *attach_flags) -{ - /* 'any' degrades to 'all' for compatibility */ - if (flags == _KDBUS_ATTACH_ANY) - flags = _KDBUS_ATTACH_ALL; - - /* reject unknown attach flags */ - if (flags & ~_KDBUS_ATTACH_ALL) - return -EINVAL; - - *attach_flags = flags; - return 0; -} - -/** - * kdbus_kvec_set - helper utility to assemble kvec arrays - * @kvec: kvec entry to use - * @src: Source address to set in @kvec - * @len: Number of bytes in @src - * @total_len: Pointer to total length variable - * - * Set @src and @len in @kvec, and increase @total_len by @len. - */ -void kdbus_kvec_set(struct kvec *kvec, void *src, size_t len, u64 *total_len) -{ - kvec->iov_base = src; - kvec->iov_len = len; - *total_len += len; -} - -static const char * const zeros = "\0\0\0\0\0\0\0"; - -/** - * kdbus_kvec_pad - conditionally write a padding kvec - * @kvec: kvec entry to use - * @len: Total length used for kvec array - * - * Check if the current total byte length of the array in @len is aligned to - * 8 bytes. If it isn't, fill @kvec with padding information and increase @len - * by the number of bytes stored in @kvec. - * - * Return: the number of added padding bytes. - */ -size_t kdbus_kvec_pad(struct kvec *kvec, u64 *len) -{ - size_t pad = KDBUS_ALIGN8(*len) - *len; - - if (!pad) - return 0; - - kvec->iov_base = (void *)zeros; - kvec->iov_len = pad; - - *len += pad; - - return pad; -} diff --git a/ipc/kdbus/util.h b/ipc/kdbus/util.h deleted file mode 100644 index 529716669..000000000 --- a/ipc/kdbus/util.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (C) 2013-2015 Kay Sievers - * Copyright (C) 2013-2015 Greg Kroah-Hartman <gregkh@linuxfoundation.org> - * Copyright (C) 2013-2015 Daniel Mack <daniel@zonque.org> - * Copyright (C) 2013-2015 David Herrmann <dh.herrmann@gmail.com> - * Copyright (C) 2013-2015 Linux Foundation - * Copyright (C) 2014-2015 Djalal Harouni <tixxdz@opendz.org> - * - * kdbus is free software; you can redistribute it and/or modify it under - * the terms of the GNU Lesser General Public License as published by the - * Free Software Foundation; either version 2.1 of the License, or (at - * your option) any later version. - */ - -#ifndef __KDBUS_UTIL_H -#define __KDBUS_UTIL_H - -#include <linux/dcache.h> -#include <linux/ioctl.h> - -#include <uapi/linux/kdbus.h> - -/* all exported addresses are 64 bit */ -#define KDBUS_PTR(addr) ((void __user *)(uintptr_t)(addr)) - -/* all exported sizes are 64 bit and data aligned to 64 bit */ -#define KDBUS_ALIGN8(s) ALIGN((s), 8) -#define KDBUS_IS_ALIGNED8(s) (IS_ALIGNED(s, 8)) - -/** - * kdbus_member_set_user - write a structure member to user memory - * @_s: Variable to copy from - * @_b: Buffer to write to - * @_t: Structure type - * @_m: Member name in the passed structure - * - * Return: the result of copy_to_user() - */ -#define kdbus_member_set_user(_s, _b, _t, _m) \ -({ \ - u64 __user *_sz = \ - (void __user *)((u8 __user *)(_b) + offsetof(_t, _m)); \ - copy_to_user(_sz, _s, FIELD_SIZEOF(_t, _m)); \ -}) - -/** - * kdbus_strhash - calculate a hash - * @str: String - * - * Return: hash value - */ -static inline unsigned int kdbus_strhash(const char *str) -{ - unsigned long hash = init_name_hash(); - - while (*str) - hash = partial_name_hash(*str++, hash); - - return end_name_hash(hash); -} - -int kdbus_verify_uid_prefix(const char *name, struct user_namespace *user_ns, - kuid_t kuid); -int kdbus_sanitize_attach_flags(u64 flags, u64 *attach_flags); - -int kdbus_copy_from_user(void *dest, void __user *user_ptr, size_t size); - -struct kvec; - -void kdbus_kvec_set(struct kvec *kvec, void *src, size_t len, u64 *total_len); -size_t kdbus_kvec_pad(struct kvec *kvec, u64 *len); - -#endif |