lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:	Tue, 14 Jun 2016 22:19:40 +0530
From:	Aravinda Prasad <aravinda@...ux.vnet.ibm.com>
To:	a.p.zijlstra@...llo.nl, linux-kernel@...r.kernel.org,
	rostedt@...dmis.org, mingo@...hat.com, paulus@...ba.org,
	acme@...nel.org, ebiederm@...ssion.com
Cc:	hbathini@...ux.vnet.ibm.com, ananth@...ibm.com
Subject: [RFC PATCH 1/2] perf/namespaces: Add a new namespace for isolated
 tracing

From: Hari Bathini <hbathini@...ux.vnet.ibm.com>

This patch adds a new namespace to the kernel inline with the existing
namespaces like pid, uts, etc. The aim of this namespace is to support
isolated tracing within the context of this new namespace.

Signed-off-by: Hari Bathini <hbathini@...ux.vnet.ibm.com>
---
 fs/proc/namespaces.c           |    4 +
 include/linux/nsproxy.h        |    2 +
 include/linux/perf_namespace.h |   52 +++++++++++++++++
 include/linux/proc_ns.h        |    2 +
 include/uapi/linux/sched.h     |    1 
 init/Kconfig                   |    7 ++
 kernel/Makefile                |    1 
 kernel/fork.c                  |    3 +
 kernel/nsproxy.c               |   20 ++++++
 kernel/perf_namespace.c        |  124 ++++++++++++++++++++++++++++++++++++++++
 10 files changed, 213 insertions(+), 3 deletions(-)
 create mode 100644 include/linux/perf_namespace.h
 create mode 100644 kernel/perf_namespace.c

diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c
index 51b8b0a..f9812fc 100644
--- a/fs/proc/namespaces.c
+++ b/fs/proc/namespaces.c
@@ -8,6 +8,7 @@
 #include <linux/ipc_namespace.h>
 #include <linux/pid_namespace.h>
 #include <linux/user_namespace.h>
+#include <linux/perf_namespace.h>
 #include "internal.h"
 
 
@@ -31,6 +32,9 @@ static const struct proc_ns_operations *ns_entries[] = {
 #ifdef CONFIG_CGROUPS
 	&cgroupns_operations,
 #endif
+#ifdef CONFIG_PERF_NS
+	&perfns_operations,
+#endif
 };
 
 static const char *proc_ns_get_link(struct dentry *dentry,
diff --git a/include/linux/nsproxy.h b/include/linux/nsproxy.h
index ac0d65b..7e83e63 100644
--- a/include/linux/nsproxy.h
+++ b/include/linux/nsproxy.h
@@ -9,6 +9,7 @@ struct uts_namespace;
 struct ipc_namespace;
 struct pid_namespace;
 struct cgroup_namespace;
+struct perf_namespace;
 struct fs_struct;
 
 /*
@@ -35,6 +36,7 @@ struct nsproxy {
 	struct pid_namespace *pid_ns_for_children;
 	struct net 	     *net_ns;
 	struct cgroup_namespace *cgroup_ns;
+	struct perf_namespace *perf_ns;
 };
 extern struct nsproxy init_nsproxy;
 
diff --git a/include/linux/perf_namespace.h b/include/linux/perf_namespace.h
new file mode 100644
index 0000000..9713724
--- /dev/null
+++ b/include/linux/perf_namespace.h
@@ -0,0 +1,52 @@
+#ifndef _LINUX_PERF_NS_H
+#define _LINUX_PERF_NS_H
+
+#include <linux/nsproxy.h>
+#include <linux/kref.h>
+#include <linux/ns_common.h>
+
+struct user_namespace;
+extern struct user_namespace init_user_ns;
+
+struct perf_namespace {
+	struct kref kref;
+	struct user_namespace *user_ns;	/* Owning user namespace */
+	struct ns_common ns;
+};
+extern struct perf_namespace init_perf_ns;
+
+#ifdef CONFIG_PERF_NS
+extern struct perf_namespace *copy_perf_ns(unsigned long flags,
+	struct user_namespace *user_ns, struct perf_namespace *old_ns);
+extern void free_perf_ns(struct kref *kref);
+
+static inline void get_perf_ns(struct perf_namespace *ns)
+{
+	kref_get(&ns->kref);
+}
+
+static inline void put_perf_ns(struct perf_namespace *ns)
+{
+	kref_put(&ns->kref, free_perf_ns);
+}
+
+#else /* !CONFIG_PERF_NS */
+static inline void get_perf_ns(struct perf_namespace *ns)
+{
+}
+
+static inline void put_perf_ns(struct perf_namespace *ns)
+{
+}
+
+static inline struct perf_namespace *copy_perf_ns(unsigned long flags,
+	struct user_namespace *user_ns, struct perf_namespace *old_ns)
+{
+	if (flags & CLONE_NEWPERF)
+		return ERR_PTR(-EINVAL);
+
+	return old_ns;
+}
+#endif /* CONFIG_PERF_NS */
+
+#endif /* _LINUX_PERF_NS_H */
diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h
index de0e771..c2916a7 100644
--- a/include/linux/proc_ns.h
+++ b/include/linux/proc_ns.h
@@ -27,6 +27,7 @@ extern const struct proc_ns_operations pidns_operations;
 extern const struct proc_ns_operations userns_operations;
 extern const struct proc_ns_operations mntns_operations;
 extern const struct proc_ns_operations cgroupns_operations;
+extern const struct proc_ns_operations perfns_operations;
 
 /*
  * We always define these enumerators
@@ -38,6 +39,7 @@ enum {
 	PROC_USER_INIT_INO	= 0xEFFFFFFDU,
 	PROC_PID_INIT_INO	= 0xEFFFFFFCU,
 	PROC_CGROUP_INIT_INO	= 0xEFFFFFFBU,
+	PROC_PERF_INIT_INO	= 0xEFFFFFFAU,
 };
 
 #ifdef CONFIG_PROC_FS
diff --git a/include/uapi/linux/sched.h b/include/uapi/linux/sched.h
index 5f0fe01..6a13d40 100644
--- a/include/uapi/linux/sched.h
+++ b/include/uapi/linux/sched.h
@@ -9,6 +9,7 @@
 #define CLONE_FS	0x00000200	/* set if fs info shared between processes */
 #define CLONE_FILES	0x00000400	/* set if open files shared between processes */
 #define CLONE_SIGHAND	0x00000800	/* set if signal handlers and blocked signals shared */
+#define CLONE_NEWPERF	0x00001000	/* New perf namespace */
 #define CLONE_PTRACE	0x00002000	/* set if we want to let tracing continue on the child too */
 #define CLONE_VFORK	0x00004000	/* set if the parent wants the child to wake it up on mm_release */
 #define CLONE_PARENT	0x00008000	/* set if we want to have the same parent as the cloner */
diff --git a/init/Kconfig b/init/Kconfig
index f755a60..e0b23f2 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -1221,6 +1221,13 @@ config NET_NS
 	  Allow user space to create what appear to be multiple instances
 	  of the network stack.
 
+config PERF_NS
+	bool "Perf Namespaces"
+	default y if PERF_EVENTS
+	help
+	  Support perf namespaces. A namespace to provide isolated tracing
+	  support in context of this namespace.
+
 endif # NAMESPACES
 
 config SCHED_AUTOGROUP
diff --git a/kernel/Makefile b/kernel/Makefile
index e2ec54e..ee94119 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -71,6 +71,7 @@ obj-$(CONFIG_CPUSETS) += cpuset.o
 obj-$(CONFIG_UTS_NS) += utsname.o
 obj-$(CONFIG_USER_NS) += user_namespace.o
 obj-$(CONFIG_PID_NS) += pid_namespace.o
+obj-$(CONFIG_PERF_NS) += perf_namespace.o
 obj-$(CONFIG_IKCONFIG) += configs.o
 obj-$(CONFIG_SMP) += stop_machine.o
 obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
diff --git a/kernel/fork.c b/kernel/fork.c
index 5c2c355..d53756c 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1926,7 +1926,8 @@ static int check_unshare_flags(unsigned long unshare_flags)
 	if (unshare_flags & ~(CLONE_THREAD|CLONE_FS|CLONE_NEWNS|CLONE_SIGHAND|
 				CLONE_VM|CLONE_FILES|CLONE_SYSVSEM|
 				CLONE_NEWUTS|CLONE_NEWIPC|CLONE_NEWNET|
-				CLONE_NEWUSER|CLONE_NEWPID|CLONE_NEWCGROUP))
+				CLONE_NEWUSER|CLONE_NEWPID|
+				CLONE_NEWCGROUP|CLONE_NEWPERF))
 		return -EINVAL;
 	/*
 	 * Not implemented, but pretend it works if there is nothing
diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c
index 782102e..b9a9831 100644
--- a/kernel/nsproxy.c
+++ b/kernel/nsproxy.c
@@ -22,6 +22,7 @@
 #include <linux/pid_namespace.h>
 #include <net/net_namespace.h>
 #include <linux/ipc_namespace.h>
+#include <linux/perf_namespace.h>
 #include <linux/proc_ns.h>
 #include <linux/file.h>
 #include <linux/syscalls.h>
@@ -43,6 +44,9 @@ struct nsproxy init_nsproxy = {
 #ifdef CONFIG_CGROUPS
 	.cgroup_ns		= &init_cgroup_ns,
 #endif
+#ifdef CONFIG_PERF_NS
+	.perf_ns		= &init_perf_ns,
+#endif
 };
 
 static inline struct nsproxy *create_nsproxy(void)
@@ -103,6 +107,12 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
 		goto out_cgroup;
 	}
 
+	new_nsp->perf_ns = copy_perf_ns(flags, user_ns, tsk->nsproxy->perf_ns);
+	if (IS_ERR(new_nsp->perf_ns)) {
+		err = PTR_ERR(new_nsp->perf_ns);
+		goto out_perf;
+	}
+
 	new_nsp->net_ns = copy_net_ns(flags, user_ns, tsk->nsproxy->net_ns);
 	if (IS_ERR(new_nsp->net_ns)) {
 		err = PTR_ERR(new_nsp->net_ns);
@@ -113,6 +123,9 @@ static struct nsproxy *create_new_namespaces(unsigned long flags,
 
 out_net:
 	put_cgroup_ns(new_nsp->cgroup_ns);
+out_perf:
+	if (new_nsp->net_ns)
+		put_net(new_nsp->net_ns);
 out_cgroup:
 	if (new_nsp->pid_ns_for_children)
 		put_pid_ns(new_nsp->pid_ns_for_children);
@@ -142,7 +155,7 @@ int copy_namespaces(unsigned long flags, struct task_struct *tsk)
 
 	if (likely(!(flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
 			      CLONE_NEWPID | CLONE_NEWNET |
-			      CLONE_NEWCGROUP)))) {
+			      CLONE_NEWCGROUP | CLONE_NEWPERF)))) {
 		get_nsproxy(old_ns);
 		return 0;
 	}
@@ -177,6 +190,8 @@ void free_nsproxy(struct nsproxy *ns)
 		put_uts_ns(ns->uts_ns);
 	if (ns->ipc_ns)
 		put_ipc_ns(ns->ipc_ns);
+	if (ns->perf_ns)
+		put_perf_ns(ns->perf_ns);
 	if (ns->pid_ns_for_children)
 		put_pid_ns(ns->pid_ns_for_children);
 	put_cgroup_ns(ns->cgroup_ns);
@@ -195,7 +210,8 @@ int unshare_nsproxy_namespaces(unsigned long unshare_flags,
 	int err = 0;
 
 	if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC |
-			       CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWCGROUP)))
+			       CLONE_NEWNET | CLONE_NEWPID |
+			       CLONE_NEWCGROUP | CLONE_NEWPERF)))
 		return 0;
 
 	user_ns = new_cred ? new_cred->user_ns : current_user_ns();
diff --git a/kernel/perf_namespace.c b/kernel/perf_namespace.c
new file mode 100644
index 0000000..5b76fd8
--- /dev/null
+++ b/kernel/perf_namespace.c
@@ -0,0 +1,124 @@
+/*
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License as
+ *  published by the Free Software Foundation, version 2 of the
+ *  License.
+ */
+
+#include <linux/export.h>
+#include <linux/perf_namespace.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/user_namespace.h>
+#include <linux/proc_ns.h>
+
+static struct perf_namespace *create_perf_ns(struct user_namespace *user_ns)
+{
+	struct perf_namespace *perf_ns;
+	int err;
+
+	perf_ns = kmalloc(sizeof(struct perf_namespace), GFP_KERNEL);
+	if (!perf_ns)
+		return ERR_PTR(-ENOMEM);
+
+	kref_init(&perf_ns->kref);
+	err = ns_alloc_inum(&perf_ns->ns);
+	if (err) {
+		kfree(perf_ns);
+		return ERR_PTR(err);
+	}
+
+	perf_ns->ns.ops = &perfns_operations;
+	perf_ns->user_ns = get_user_ns(user_ns);
+	return perf_ns;
+}
+
+struct perf_namespace *copy_perf_ns(unsigned long flags,
+	struct user_namespace *user_ns, struct perf_namespace *old_ns)
+{
+	struct perf_namespace *new_ns;
+
+	BUG_ON(!old_ns);
+	get_perf_ns(old_ns);
+
+	if (!(flags & CLONE_NEWPERF))
+		return old_ns;
+
+	new_ns = create_perf_ns(user_ns);
+
+	put_perf_ns(old_ns);
+	return new_ns;
+}
+
+void free_perf_ns(struct kref *kref)
+{
+	struct perf_namespace *ns;
+
+	ns = container_of(kref, struct perf_namespace, kref);
+	put_user_ns(ns->user_ns);
+	ns_free_inum(&ns->ns);
+	kfree(ns);
+}
+
+static inline struct perf_namespace *to_perf_ns(struct ns_common *ns)
+{
+	return container_of(ns, struct perf_namespace, ns);
+}
+
+static struct ns_common *perfns_get(struct task_struct *task)
+{
+	struct perf_namespace *ns = NULL;
+	struct nsproxy *nsproxy;
+
+	task_lock(task);
+	nsproxy = task->nsproxy;
+	if (nsproxy) {
+		ns = nsproxy->perf_ns;
+		get_perf_ns(ns);
+	}
+	task_unlock(task);
+
+	return ns ? &ns->ns : NULL;
+}
+
+static void perfns_put(struct ns_common *ns)
+{
+	put_perf_ns(to_perf_ns(ns));
+}
+
+static int perfns_install(struct nsproxy *nsproxy, struct ns_common *new)
+{
+	struct perf_namespace *ns = to_perf_ns(new);
+
+	if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) ||
+	    !ns_capable(current_user_ns(), CAP_SYS_ADMIN))
+		return -EPERM;
+
+	get_perf_ns(ns);
+	put_perf_ns(nsproxy->perf_ns);
+	nsproxy->perf_ns = ns;
+	return 0;
+}
+
+const struct proc_ns_operations perfns_operations = {
+	.name		= "perf",
+	.type		= CLONE_NEWPERF,
+	.get		= perfns_get,
+	.put		= perfns_put,
+	.install	= perfns_install,
+};
+
+/*
+ * TODO: Find a better place to put this..
+ */
+struct perf_namespace init_perf_ns = {
+	.kref = {
+		.refcount = ATOMIC_INIT(2),
+	},
+	.user_ns = &init_user_ns,
+	.ns.inum = PROC_PERF_INIT_INO,
+#ifdef CONFIG_PERF_NS
+	.ns.ops = &perfns_operations,
+#endif
+};
+EXPORT_SYMBOL_GPL(init_perf_ns);

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ