summaryrefslogtreecommitdiff
path: root/ipc/kdbus/metadata.c
diff options
context:
space:
mode:
Diffstat (limited to 'ipc/kdbus/metadata.c')
-rw-r--r--ipc/kdbus/metadata.c1347
1 files changed, 0 insertions, 1347 deletions
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));
-}