diff options
Diffstat (limited to 'kdbus-add-code-to-gather-metadata.patch')
-rw-r--r-- | kdbus-add-code-to-gather-metadata.patch | 1320 |
1 files changed, 1320 insertions, 0 deletions
diff --git a/kdbus-add-code-to-gather-metadata.patch b/kdbus-add-code-to-gather-metadata.patch new file mode 100644 index 000000000..bd0bd9451 --- /dev/null +++ b/kdbus-add-code-to-gather-metadata.patch @@ -0,0 +1,1320 @@ +From: Daniel Mack <daniel@zonque.org> +Date: Thu, 11 Sep 2014 18:58:45 +0200 +Subject: [PATCH] kdbus: add code to gather metadata + +A connection chooses which metadata it wants to have attached to each +message it receives with kdbus_cmd_hello.attach_flags. The metadata +will be attached as items to the messages. All metadata refers to +information about the sending task at sending time, unless otherwise +stated. Also, the metadata is copied, not referenced, so even if the +sending task doesn't exist anymore at the time the message is received, +the information is still preserved. + +In traditional D-Bus, userspace tasks like polkit or journald make a +live lookup in procfs and sysfs to gain information about a sending +task. This is racy, of course, as in a a connection-less system like +D-Bus, the originating peer can go away immediately after sending the +message. As we're moving D-Bus prmitives into the kernel, we have to +provide the same semantics here, and inform the receiving peer on the +live credentials of the sending peer. + +Metadata is collected at the following times. + + * When a bus is created (KDBUS_CMD_MAKE), information about the + calling task is collected. This data is returned by the kernel + via the KDBUS_CMD_BUS_CREATOR_INFO call. + + * When a connection is created (KDBUS_CMD_HELLO), information about + the calling task is collected. Alternatively, a privileged + connection may provide 'faked' information about credentials, + PIDs and security labels which will be stored instead. This data + is returned by the kernel as information on a connection + (KDBUS_CMD_CONN_INFO). Only metadata that a connection allowed to + be sent (by setting its bit in attach_flags_send) will be exported + in this way. + + * When a message is sent (KDBUS_CMD_SEND), information about the + sending task and the sending connection are collected. This + metadata will be attached to the message when it arrives in the + receiver's pool. If the connection sending the message installed + faked credentials (see kdbus.connection(7)), the message will not + be augmented by any information about the currently sending task. + +Which metadata items are actually delivered depends on the following +sets and masks: + + (a) the system-wide kmod creds mask + (module parameter 'attach_flags_mask') + + (b) the per-connection send creds mask, set by the connecting client + + (c) the per-connection receive creds mask, set by the connecting client + + (d) the per-bus minimal creds mask, set by the bus creator + + (e) the per-bus owner creds mask, set by the bus creator + + (f) the mask specified when querying creds of a bus peer + + (g) the mask specified when querying creds of a bus owner + +With the following rules: + + [1] The creds attached to messages are determined as a & b & c. + + [2] When connecting to a bus (KDBUS_CMD_HELLO), and ~b & d != 0, + the call will fail with, -1, and errno is set to ECONNREFUSED. + + [3] When querying creds of a bus peer, the creds returned + are a & b & f. + + [4] When querying creds of a bus owner, the creds returned + are a & e & g. + +See kdbus.metadata(7) and kdbus.item(7) for more details on which +metadata can currently be attached to messages. + +Signed-off-by: Daniel Mack <daniel@zonque.org> +Signed-off-by: David Herrmann <dh.herrmann@gmail.com> +Signed-off-by: Djalal Harouni <tixxdz@opendz.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> +--- + ipc/kdbus/metadata.c | 1164 ++++++++++++++++++++++++++++++++++++++++++++++++++ + ipc/kdbus/metadata.h | 57 +++ + 2 files changed, 1221 insertions(+) + create mode 100644 ipc/kdbus/metadata.c + create mode 100644 ipc/kdbus/metadata.h + +diff --git a/ipc/kdbus/metadata.c b/ipc/kdbus/metadata.c +new file mode 100644 +index 000000000000..06e0a54a276a +--- /dev/null ++++ b/ipc/kdbus/metadata.c +@@ -0,0 +1,1164 @@ ++/* ++ * 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 <linux/version.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 ++ * @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 ++ * @auxgrps: Auxiliary groups ++ * @n_auxgrps: Number of items in @auxgrps ++ * @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 ++ * @caps: Capabilities ++ * @caps_namespace: User-namespace of @caps ++ * @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 */ ++ kuid_t uid, euid, suid, fsuid; ++ kgid_t gid, egid, sgid, fsgid; ++ ++ /* KDBUS_ITEM_PIDS */ ++ struct pid *pid; ++ struct pid *tgid; ++ struct pid *ppid; ++ ++ /* KDBUS_ITEM_AUXGROUPS */ ++ kgid_t *auxgrps; ++ size_t n_auxgrps; ++ ++ /* 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_CAPS */ ++ struct caps { ++ /* binary compatible to kdbus_caps */ ++ u32 last_cap; ++ struct { ++ u32 caps[_KERNEL_CAPABILITY_U32S]; ++ } set[4]; ++ } caps; ++ struct user_namespace *caps_namespace; ++ ++ /* 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; ++}; ++ ++/** ++ * 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); ++ put_user_ns(mp->caps_namespace); ++ put_pid(mp->ppid); ++ put_pid(mp->tgid); ++ put_pid(mp->pid); ++ ++ kfree(mp->seclabel); ++ kfree(mp->auxgrps); ++ 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_creds(struct kdbus_meta_proc *mp) ++{ ++ mp->uid = current_uid(); ++ mp->euid = current_euid(); ++ mp->suid = current_suid(); ++ mp->fsuid = current_fsuid(); ++ ++ mp->gid = current_gid(); ++ mp->egid = current_egid(); ++ mp->sgid = current_sgid(); ++ mp->fsgid = current_fsgid(); ++ ++ mp->valid |= KDBUS_ATTACH_CREDS; ++} ++ ++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 int kdbus_meta_proc_collect_auxgroups(struct kdbus_meta_proc *mp) ++{ ++ struct group_info *info; ++ size_t i; ++ ++ info = get_current_groups(); ++ ++ if (info->ngroups > 0) { ++ mp->auxgrps = kmalloc_array(info->ngroups, sizeof(kgid_t), ++ GFP_KERNEL); ++ if (!mp->auxgrps) { ++ put_group_info(info); ++ return -ENOMEM; ++ } ++ ++ for (i = 0; i < info->ngroups; i++) ++ mp->auxgrps[i] = GROUP_AT(info, i); ++ } ++ ++ mp->n_auxgrps = info->ngroups; ++ put_group_info(info); ++ mp->valid |= KDBUS_ATTACH_AUXGROUPS; ++ ++ return 0; ++} ++ ++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 mm_struct *mm; ++ ++ mm = get_task_mm(current); ++ if (!mm) ++ return; ++ ++ down_read(&mm->mmap_sem); ++ if (mm->exe_file) { ++ mp->exe_path = mm->exe_file->f_path; ++ path_get(&mp->exe_path); ++ get_fs_root(current->fs, &mp->root_path); ++ mp->valid |= KDBUS_ATTACH_EXE; ++ } ++ up_read(&mm->mmap_sem); ++ ++ mmput(mm); ++} ++ ++static int kdbus_meta_proc_collect_cmdline(struct kdbus_meta_proc *mp) ++{ ++ struct mm_struct *mm; ++ char *cmdline; ++ ++ mm = get_task_mm(current); ++ if (!mm) ++ return 0; ++ ++ if (!mm->arg_end) { ++ mmput(mm); ++ return 0; ++ } ++ ++ cmdline = strndup_user((const char __user *)mm->arg_start, ++ mm->arg_end - mm->arg_start); ++ mmput(mm); ++ ++ 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 void kdbus_meta_proc_collect_caps(struct kdbus_meta_proc *mp) ++{ ++ const struct cred *c = current_cred(); ++ int i; ++ ++ /* ABI: "last_cap" equals /proc/sys/kernel/cap_last_cap */ ++ mp->caps.last_cap = CAP_LAST_CAP; ++ mp->caps_namespace = get_user_ns(current_user_ns()); ++ ++ CAP_FOR_EACH_U32(i) { ++ mp->caps.set[0].caps[i] = c->cap_inheritable.cap[i]; ++ mp->caps.set[1].caps[i] = c->cap_permitted.cap[i]; ++ mp->caps.set[2].caps[i] = c->cap_effective.cap[i]; ++ mp->caps.set[3].caps[i] = c->cap_bset.cap[i]; ++ } ++ ++ /* clear unused bits */ ++ for (i = 0; i < 4; i++) ++ mp->caps.set[i].caps[CAP_TO_INDEX(CAP_LAST_CAP)] &= ++ CAP_LAST_U32_VALID_MASK; ++ ++ mp->valid |= KDBUS_ATTACH_CAPS; ++} ++ ++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); ++ ++ if ((what & KDBUS_ATTACH_CREDS) && ++ !(mp->collected & KDBUS_ATTACH_CREDS)) { ++ kdbus_meta_proc_collect_creds(mp); ++ mp->collected |= KDBUS_ATTACH_CREDS; ++ } ++ ++ 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_AUXGROUPS) && ++ !(mp->collected & KDBUS_ATTACH_AUXGROUPS)) { ++ ret = kdbus_meta_proc_collect_auxgroups(mp); ++ if (ret < 0) ++ goto exit_unlock; ++ mp->collected |= KDBUS_ATTACH_AUXGROUPS; ++ } ++ ++ 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_CAPS) && ++ !(mp->collected & KDBUS_ATTACH_CAPS)) { ++ kdbus_meta_proc_collect_caps(mp); ++ mp->collected |= KDBUS_ATTACH_CAPS; ++ } ++ ++ 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_proc_fake() - Fill process metadata from faked credentials ++ * @mp: Metadata ++ * @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. A call to this function ++ * is considered an alternative to calling kdbus_meta_add_current(), which ++ * derives the same information from the 'current' task. ++ * ++ * This call uses the current task's namespaces to resolve the given ++ * information. ++ * ++ * Return: 0 on success, negative error number otherwise. ++ */ ++int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp, ++ const struct kdbus_creds *creds, ++ const struct kdbus_pids *pids, ++ const char *seclabel) ++{ ++ int ret; ++ ++ if (!mp) ++ return 0; ++ ++ mutex_lock(&mp->lock); ++ ++ if (creds && !(mp->collected & KDBUS_ATTACH_CREDS)) { ++ struct user_namespace *ns = current_user_ns(); ++ ++ mp->uid = make_kuid(ns, creds->uid); ++ mp->euid = make_kuid(ns, creds->euid); ++ mp->suid = make_kuid(ns, creds->suid); ++ mp->fsuid = make_kuid(ns, creds->fsuid); ++ ++ mp->gid = make_kgid(ns, creds->gid); ++ mp->egid = make_kgid(ns, creds->egid); ++ mp->sgid = make_kgid(ns, creds->sgid); ++ mp->fsgid = make_kgid(ns, creds->fsgid); ++ ++ if ((creds->uid != (uid_t)-1 && !uid_valid(mp->uid)) || ++ (creds->euid != (uid_t)-1 && !uid_valid(mp->euid)) || ++ (creds->suid != (uid_t)-1 && !uid_valid(mp->suid)) || ++ (creds->fsuid != (uid_t)-1 && !uid_valid(mp->fsuid)) || ++ (creds->gid != (gid_t)-1 && !gid_valid(mp->gid)) || ++ (creds->egid != (gid_t)-1 && !gid_valid(mp->egid)) || ++ (creds->sgid != (gid_t)-1 && !gid_valid(mp->sgid)) || ++ (creds->fsgid != (gid_t)-1 && !gid_valid(mp->fsgid))) { ++ ret = -EINVAL; ++ goto exit_unlock; ++ } ++ ++ mp->valid |= KDBUS_ATTACH_CREDS; ++ mp->collected |= KDBUS_ATTACH_CREDS; ++ } ++ ++ if (pids && !(mp->collected & KDBUS_ATTACH_PIDS)) { ++ mp->pid = get_pid(find_vpid(pids->tid)); ++ mp->tgid = get_pid(find_vpid(pids->pid)); ++ mp->ppid = get_pid(find_vpid(pids->ppid)); ++ ++ if ((pids->tid != 0 && !mp->pid) || ++ (pids->pid != 0 && !mp->tgid) || ++ (pids->ppid != 0 && !mp->ppid)) { ++ put_pid(mp->pid); ++ put_pid(mp->tgid); ++ put_pid(mp->ppid); ++ mp->pid = NULL; ++ mp->tgid = NULL; ++ mp->ppid = NULL; ++ ret = -EINVAL; ++ goto exit_unlock; ++ } ++ ++ mp->valid |= KDBUS_ATTACH_PIDS; ++ mp->collected |= KDBUS_ATTACH_PIDS; ++ } ++ ++ if (seclabel && !(mp->collected & KDBUS_ATTACH_SECLABEL)) { ++ mp->seclabel = kstrdup(seclabel, GFP_KERNEL); ++ if (!mp->seclabel) { ++ ret = -ENOMEM; ++ goto exit_unlock; ++ } ++ ++ mp->valid |= KDBUS_ATTACH_SECLABEL; ++ mp->collected |= KDBUS_ATTACH_SECLABEL; ++ } ++ ++ ret = 0; ++ ++exit_unlock: ++ mutex_unlock(&mp->lock); ++ return ret; ++} ++ ++/** ++ * 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, ++ struct kdbus_kmsg *kmsg) ++{ ++ struct timespec ts; ++ ++ ktime_get_ts(&ts); ++ mc->ts.monotonic_ns = timespec_to_ns(&ts); ++ ++ ktime_get_real_ts(&ts); ++ mc->ts.realtime_ns = timespec_to_ns(&ts); ++ ++ if (kmsg) ++ mc->ts.seqnum = kmsg->seq; ++ ++ 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_entry *e; ++ struct kdbus_item *item; ++ size_t slen, size; ++ ++ lockdep_assert_held(&conn->ep->bus->name_registry->rwlock); ++ ++ size = 0; ++ list_for_each_entry(e, &conn->names_list, conn_entry) ++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_name) + ++ strlen(e->name) + 1); ++ ++ if (!size) ++ return 0; ++ ++ item = kmalloc(size, GFP_KERNEL); ++ if (!item) ++ return -ENOMEM; ++ ++ mc->owned_names_items = item; ++ mc->owned_names_size = size; ++ ++ list_for_each_entry(e, &conn->names_list, conn_entry) { ++ slen = strlen(e->name) + 1; ++ kdbus_item_set(item, KDBUS_ITEM_OWNED_NAME, NULL, ++ sizeof(struct kdbus_name) + slen); ++ item->name.flags = e->flags; ++ memcpy(item->name.name, e->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 + 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 ++ * @kmsg: Kmsg to collect data from ++ * @conn: Connection to collect data from ++ * @what: Attach flags to collect ++ * ++ * This collects connection metadata from @kmsg 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_kmsg *kmsg, ++ struct kdbus_conn *conn, ++ u64 what) ++{ ++ int ret; ++ ++ if (!mc || !(what & (KDBUS_ATTACH_TIMESTAMP | ++ KDBUS_ATTACH_NAMES | ++ KDBUS_ATTACH_CONN_DESCRIPTION))) ++ return 0; ++ ++ mutex_lock(&mc->lock); ++ ++ if (kmsg && (what & KDBUS_ATTACH_TIMESTAMP) && ++ !(mc->collected & KDBUS_ATTACH_TIMESTAMP)) { ++ kdbus_meta_conn_collect_timestamp(mc, kmsg); ++ 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; ++} ++ ++/* ++ * kdbus_meta_export_prepare() - Prepare metadata for export ++ * @mp: Process metadata, or NULL ++ * @mc: Connection metadata, or NULL ++ * @mask: Pointer to mask of KDBUS_ATTACH_* flags to export ++ * @sz: Pointer to return the size needed by the metadata ++ * ++ * Does a conservative calculation of how much space metadata information ++ * will take up during export. It is 'conservative' because for string ++ * translations in namespaces, it will use the kernel namespaces, which is ++ * the longest possible version. ++ * ++ * The actual size consumed by kdbus_meta_export() may hence vary from the ++ * one reported here, but it is guaranteed never to be greater. ++ * ++ * Return: 0 on success, negative error number otherwise. ++ */ ++int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, ++ struct kdbus_meta_conn *mc, ++ u64 *mask, size_t *sz) ++{ ++ char *exe_pathname = NULL; ++ void *exe_page = NULL; ++ size_t size = 0; ++ u64 valid = 0; ++ int ret = 0; ++ ++ if (mp) { ++ mutex_lock(&mp->lock); ++ valid |= mp->valid; ++ mutex_unlock(&mp->lock); ++ } ++ ++ if (mc) { ++ mutex_lock(&mc->lock); ++ valid |= mc->valid; ++ mutex_unlock(&mc->lock); ++ } ++ ++ *mask &= valid; ++ *mask &= kdbus_meta_attach_mask; ++ ++ if (!*mask) ++ goto exit; ++ ++ /* process metadata */ ++ ++ if (mp && (*mask & KDBUS_ATTACH_CREDS)) ++ size += KDBUS_ITEM_SIZE(sizeof(struct kdbus_creds)); ++ ++ 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->n_auxgrps * 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 (mp && (*mask & KDBUS_ATTACH_EXE)) { ++ exe_page = (void *)__get_free_page(GFP_TEMPORARY); ++ if (!exe_page) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ exe_pathname = d_path(&mp->exe_path, exe_page, PAGE_SIZE); ++ if (IS_ERR(exe_pathname)) { ++ ret = PTR_ERR(exe_pathname); ++ goto exit; ++ } ++ ++ size += KDBUS_ITEM_SIZE(strlen(exe_pathname) + 1); ++ free_page((unsigned long)exe_page); ++ } ++ ++ 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(mp->caps)); ++ ++ 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 += 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)); ++ ++exit: ++ *sz = size; ++ ++ return ret; ++} ++ ++static int kdbus_meta_push_kvec(struct kvec *kvec, ++ struct kdbus_item_header *hdr, ++ u64 type, void *payload, ++ size_t payload_size, u64 *size) ++{ ++ hdr->type = type; ++ hdr->size = KDBUS_ITEM_HEADER_SIZE + payload_size; ++ kdbus_kvec_set(kvec++, hdr, sizeof(*hdr), size); ++ kdbus_kvec_set(kvec++, payload, payload_size, size); ++ return 2 + !!kdbus_kvec_pad(kvec++, size); ++} ++ ++/* This is equivalent to from_kuid_munged(), but maps INVALID_UID to itself */ ++static uid_t kdbus_from_kuid_keep(kuid_t uid) ++{ ++ return uid_valid(uid) ? ++ from_kuid_munged(current_user_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(kgid_t gid) ++{ ++ return gid_valid(gid) ? ++ from_kgid_munged(current_user_ns(), gid) : ((gid_t)-1); ++} ++ ++/** ++ * kdbus_meta_export() - export information from metadata into a slice ++ * @mp: Process metadata, or NULL ++ * @mc: Connection metadata, or NULL ++ * @mask: Mask of KDBUS_ATTACH_* flags to export ++ * @slice: The slice to export to ++ * @offset: The offset inside @slice to write to ++ * @real_size: The real size the metadata consumed ++ * ++ * This function exports information from metadata into @slice at offset ++ * @offset inside that slice. Only information that is requested in @mask ++ * and that has been collected before is exported. ++ * ++ * In order to make sure not to write out of bounds, @mask must be the same ++ * value that was previously returned from kdbus_meta_export_prepare(). The ++ * function will, however, not necessarily write as many bytes as returned by ++ * kdbus_meta_export_prepare(); depending on the namespaces in question, it ++ * might use up less than that. ++ * ++ * All information will be translated using the current namespaces. ++ * ++ * Return: 0 on success, negative error number otherwise. ++ */ ++int kdbus_meta_export(struct kdbus_meta_proc *mp, ++ struct kdbus_meta_conn *mc, ++ u64 mask, ++ struct kdbus_pool_slice *slice, ++ off_t offset, ++ size_t *real_size) ++{ ++ struct user_namespace *user_ns = current_user_ns(); ++ struct kdbus_item_header item_hdr[13], *hdr; ++ char *exe_pathname = NULL; ++ struct kdbus_creds creds; ++ struct kdbus_pids pids; ++ void *exe_page = NULL; ++ struct kvec kvec[40]; ++ u64 *auxgrps = NULL; ++ size_t cnt = 0; ++ u64 size = 0; ++ int ret = 0; ++ ++ hdr = &item_hdr[0]; ++ ++ /* ++ * TODO: We currently have no sane way of translating a set of caps ++ * between different user namespaces. Until that changes, we have ++ * to drop such items. ++ */ ++ if (mp && mp->caps_namespace != user_ns) ++ mask &= ~KDBUS_ATTACH_CAPS; ++ ++ if (mask == 0) { ++ *real_size = 0; ++ return 0; ++ } ++ ++ /* process metadata */ ++ ++ if (mp && (mask & KDBUS_ATTACH_CREDS)) { ++ creds.uid = kdbus_from_kuid_keep(mp->uid); ++ creds.euid = kdbus_from_kuid_keep(mp->euid); ++ creds.suid = kdbus_from_kuid_keep(mp->suid); ++ creds.fsuid = kdbus_from_kuid_keep(mp->fsuid); ++ creds.gid = kdbus_from_kgid_keep(mp->gid); ++ creds.egid = kdbus_from_kgid_keep(mp->egid); ++ creds.sgid = kdbus_from_kgid_keep(mp->sgid); ++ creds.fsgid = kdbus_from_kgid_keep(mp->fsgid); ++ ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_CREDS, ++ &creds, sizeof(creds), &size); ++ } ++ ++ if (mp && (mask & KDBUS_ATTACH_PIDS)) { ++ pids.pid = pid_vnr(mp->tgid); ++ pids.tid = pid_vnr(mp->pid); ++ pids.ppid = pid_vnr(mp->ppid); ++ ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_PIDS, ++ &pids, sizeof(pids), &size); ++ } ++ ++ if (mp && (mask & KDBUS_ATTACH_AUXGROUPS)) { ++ size_t payload_size = mp->n_auxgrps * sizeof(u64); ++ int i; ++ ++ auxgrps = kmalloc(payload_size, GFP_KERNEL); ++ if (!auxgrps) { ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ for (i = 0; i < mp->n_auxgrps; i++) ++ auxgrps[i] = from_kgid_munged(user_ns, mp->auxgrps[i]); ++ ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_AUXGROUPS, ++ auxgrps, payload_size, &size); ++ } ++ ++ if (mp && (mask & KDBUS_ATTACH_TID_COMM)) ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_TID_COMM, mp->tid_comm, ++ strlen(mp->tid_comm) + 1, &size); ++ ++ if (mp && (mask & KDBUS_ATTACH_PID_COMM)) ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_PID_COMM, mp->pid_comm, ++ strlen(mp->pid_comm) + 1, &size); ++ ++ if (mp && (mask & KDBUS_ATTACH_EXE)) { ++ struct path p; ++ ++ /* ++ * TODO: 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, &mp->root_path)) { ++ exe_page = (void *)__get_free_page(GFP_TEMPORARY); ++ if (!exe_page) { ++ path_put(&p); ++ ret = -ENOMEM; ++ goto exit; ++ } ++ ++ exe_pathname = d_path(&mp->exe_path, exe_page, ++ PAGE_SIZE); ++ if (IS_ERR(exe_pathname)) { ++ path_put(&p); ++ ret = PTR_ERR(exe_pathname); ++ goto exit; ++ } ++ ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_EXE, ++ exe_pathname, ++ strlen(exe_pathname) + 1, ++ &size); ++ } ++ path_put(&p); ++ } ++ ++ if (mp && (mask & KDBUS_ATTACH_CMDLINE)) ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_CMDLINE, mp->cmdline, ++ strlen(mp->cmdline) + 1, &size); ++ ++ if (mp && (mask & KDBUS_ATTACH_CGROUP)) ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_CGROUP, mp->cgroup, ++ strlen(mp->cgroup) + 1, &size); ++ ++ if (mp && (mask & KDBUS_ATTACH_CAPS)) ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_CAPS, &mp->caps, ++ sizeof(mp->caps), &size); ++ ++ if (mp && (mask & KDBUS_ATTACH_SECLABEL)) ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_SECLABEL, mp->seclabel, ++ strlen(mp->seclabel) + 1, &size); ++ ++ if (mp && (mask & KDBUS_ATTACH_AUDIT)) { ++ struct kdbus_audit a = { ++ .loginuid = from_kuid(user_ns, mp->audit_loginuid), ++ .sessionid = mp->audit_sessionid, ++ }; ++ ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, KDBUS_ITEM_AUDIT, ++ &a, sizeof(a), &size); ++ } ++ ++ /* connection metadata */ ++ ++ if (mc && (mask & KDBUS_ATTACH_NAMES)) ++ kdbus_kvec_set(&kvec[cnt++], mc->owned_names_items, ++ mc->owned_names_size, &size); ++ ++ if (mc && (mask & KDBUS_ATTACH_CONN_DESCRIPTION)) ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_CONN_DESCRIPTION, ++ mc->conn_description, ++ strlen(mc->conn_description) + 1, ++ &size); ++ ++ if (mc && (mask & KDBUS_ATTACH_TIMESTAMP)) ++ cnt += kdbus_meta_push_kvec(kvec + cnt, hdr++, ++ KDBUS_ITEM_TIMESTAMP, &mc->ts, ++ sizeof(mc->ts), &size); ++ ++ ret = kdbus_pool_slice_copy_kvec(slice, offset, kvec, cnt, size); ++ *real_size = size; ++ ++exit: ++ kfree(auxgrps); ++ ++ if (exe_page) ++ free_page((unsigned long)exe_page); ++ ++ return ret; ++} ++ ++/** ++ * kdbus_meta_calc_attach_flags() - calculate attach flags for a sender ++ * and a receiver ++ * @sender: Sending connection ++ * @receiver: Receiving connection ++ * ++ * Return: the attach flags both the sender and the receiver have opted-in ++ * for. ++ */ ++u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender, ++ const struct kdbus_conn *receiver) ++{ ++ return atomic64_read(&sender->attach_flags_send) & ++ atomic64_read(&receiver->attach_flags_recv); ++} +diff --git a/ipc/kdbus/metadata.h b/ipc/kdbus/metadata.h +new file mode 100644 +index 000000000000..42c942b34d2c +--- /dev/null ++++ b/ipc/kdbus/metadata.h +@@ -0,0 +1,57 @@ ++/* ++ * 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_kmsg; ++struct kdbus_pool_slice; ++ ++struct kdbus_meta_proc; ++struct kdbus_meta_conn; ++ ++extern unsigned long long kdbus_meta_attach_mask; ++ ++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); ++int kdbus_meta_proc_fake(struct kdbus_meta_proc *mp, ++ 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_kmsg *kmsg, ++ struct kdbus_conn *conn, ++ u64 what); ++ ++int kdbus_meta_export_prepare(struct kdbus_meta_proc *mp, ++ struct kdbus_meta_conn *mc, ++ u64 *mask, size_t *sz); ++int kdbus_meta_export(struct kdbus_meta_proc *mp, ++ struct kdbus_meta_conn *mc, ++ u64 mask, ++ struct kdbus_pool_slice *slice, ++ off_t offset, size_t *real_size); ++u64 kdbus_meta_calc_attach_flags(const struct kdbus_conn *sender, ++ const struct kdbus_conn *receiver); ++ ++#endif |